Merge "Fix scope ids for link-local IPv6 addresses from getifaddrs(3)."
diff --git a/libc/arch-x86/atom/string/ssse3-strcmp-atom.S b/libc/arch-x86/atom/string/ssse3-strcmp-atom.S
index 1275379..ee253b9 100644
--- a/libc/arch-x86/atom/string/ssse3-strcmp-atom.S
+++ b/libc/arch-x86/atom/string/ssse3-strcmp-atom.S
@@ -115,6 +115,7 @@
 ENTRY (STRCMP)
 #ifdef USE_AS_STRNCMP
 	PUSH	(%ebp)
+	cfi_remember_state
 #endif
 	movl	STR1(%esp), %edx
 	movl	STR2(%esp), %eax
@@ -213,9 +214,6 @@
 	PUSH	(%ebx)
 	PUSH	(%edi)
 	PUSH	(%esi)
-#ifdef USE_AS_STRNCMP
-	cfi_remember_state
-#endif
 
 	movl	%edx, %edi
 	movl	%eax, %ecx
@@ -2103,7 +2101,6 @@
 	RETURN
 
 #ifdef USE_AS_STRNCMP
-	cfi_restore_state
 	.p2align 4
 L(more8byteseq):
 	POP	(%esi)
@@ -2120,7 +2117,7 @@
 	ret
 
 #ifdef USE_AS_STRNCMP
-	CFI_PUSH (%ebp)
+	cfi_restore_state
 
 	.p2align 4
 L(less16bytes_sncmp):
diff --git a/libc/malloc_debug/DebugData.cpp b/libc/malloc_debug/DebugData.cpp
index 92b866d..0447566 100644
--- a/libc/malloc_debug/DebugData.cpp
+++ b/libc/malloc_debug/DebugData.cpp
@@ -82,3 +82,21 @@
   }
   return true;
 }
+
+void DebugData::PrepareFork() {
+  if (track != nullptr) {
+    track->PrepareFork();
+  }
+}
+
+void DebugData::PostForkParent() {
+  if (track != nullptr) {
+    track->PostForkParent();
+  }
+}
+
+void DebugData::PostForkChild() {
+  if (track != nullptr) {
+    track->PostForkChild();
+  }
+}
diff --git a/libc/malloc_debug/DebugData.h b/libc/malloc_debug/DebugData.h
index 40978db..4600b33 100644
--- a/libc/malloc_debug/DebugData.h
+++ b/libc/malloc_debug/DebugData.h
@@ -82,6 +82,10 @@
   bool need_header() { return need_header_; }
   size_t extra_bytes() { return extra_bytes_; }
 
+  void PrepareFork();
+  void PostForkParent();
+  void PostForkChild();
+
   std::unique_ptr<BacktraceData> backtrace;
   std::unique_ptr<TrackData> track;
   std::unique_ptr<FrontGuardData> front_guard;
diff --git a/libc/malloc_debug/TrackData.h b/libc/malloc_debug/TrackData.h
index 45e6892..dcf0ede 100644
--- a/libc/malloc_debug/TrackData.h
+++ b/libc/malloc_debug/TrackData.h
@@ -58,6 +58,10 @@
 
   void DisplayLeaks(DebugData& debug);
 
+  void PrepareFork() { pthread_mutex_lock(&mutex_); }
+  void PostForkParent() { pthread_mutex_unlock(&mutex_); }
+  void PostForkChild() { pthread_mutex_init(&mutex_, NULL); }
+
  private:
   pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER;
   std::unordered_set<Header*> headers_;
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 0c0907d..dcc6048 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -85,6 +85,28 @@
 __END_DECLS
 // ------------------------------------------------------------------------
 
+static void InitAtfork() {
+  static pthread_once_t atfork_init = PTHREAD_ONCE_INIT;
+  pthread_once(&atfork_init, [](){
+    pthread_atfork(
+        [](){
+          if (g_debug != nullptr) {
+            g_debug->PrepareFork();
+          }
+        },
+        [](){
+          if (g_debug != nullptr) {
+            g_debug->PostForkParent();
+          }
+        },
+        [](){
+          if (g_debug != nullptr) {
+            g_debug->PostForkChild();
+          }
+        }
+    );
+  });
+}
 static void LogTagError(const Header* header, const void* pointer, const char* name) {
   ScopedDisableDebugCalls disable;
 
@@ -156,6 +178,9 @@
   if (malloc_zygote_child == nullptr) {
     return false;
   }
+
+  InitAtfork();
+
   g_malloc_zygote_child = malloc_zygote_child;
 
   g_dispatch = malloc_dispatch;
diff --git a/linker/linker.cpp b/linker/linker.cpp
index e1e3578..872d81d 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -214,21 +214,21 @@
 static r_debug _r_debug =
     {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0};
 
-static link_map* r_debug_tail = 0;
+static link_map* r_debug_tail = nullptr;
 
 static void insert_link_map_into_debug_map(link_map* map) {
   // Stick the new library at the end of the list.
   // gdb tends to care more about libc than it does
   // about leaf libraries, and ordering it this way
   // reduces the back-and-forth over the wire.
-  if (r_debug_tail) {
+  if (r_debug_tail != nullptr) {
     r_debug_tail->l_next = map;
     map->l_prev = r_debug_tail;
-    map->l_next = 0;
+    map->l_next = nullptr;
   } else {
     _r_debug.r_map = map;
-    map->l_prev = 0;
-    map->l_next = 0;
+    map->l_prev = nullptr;
+    map->l_next = nullptr;
   }
   r_debug_tail = map;
 }
@@ -3893,8 +3893,7 @@
  * Without this, gdb has trouble locating the linker's ".text"
  * and ".plt" sections. Gdb could also potentially use this to
  * relocate the offset of our exported 'rtld_db_dlactivity' symbol.
- * Don't use soinfo_alloc(), because the linker shouldn't
- * be on the soinfo list.
+ * Note that the linker shouldn't be on the soinfo list.
  */
 static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
   static link_map linker_link_map_for_gdb;
@@ -4001,11 +4000,7 @@
 
   map->l_addr = 0;
   map->l_name = args.argv[0];
-  map->l_prev = nullptr;
-  map->l_next = nullptr;
-
-  _r_debug.r_map = map;
-  r_debug_tail = map;
+  insert_link_map_into_debug_map(map);
 
   init_linker_info_for_gdb(linker_base);