[compiler-rt] r185815 - [lsan] Handle fork() correctly.

Sergey Matveev earthdok at google.com
Mon Jul 8 05:57:24 PDT 2013


Author: smatveev
Date: Mon Jul  8 07:57:24 2013
New Revision: 185815

URL: http://llvm.org/viewvc/llvm-project?rev=185815&view=rev
Log:
[lsan] Handle fork() correctly.

Update the main thread's os_id on every pthread_create, and before
initiating leak checking. This ensures that we have the correct os_id even if we
have forked after Init().

Added:
    compiler-rt/trunk/lib/lsan/lit_tests/TestCases/fork.cc
    compiler-rt/trunk/lib/lsan/lit_tests/TestCases/fork_threaded.cc
Modified:
    compiler-rt/trunk/lib/asan/asan_interceptors.cc
    compiler-rt/trunk/lib/asan/asan_thread.cc
    compiler-rt/trunk/lib/asan/asan_thread.h
    compiler-rt/trunk/lib/lsan/lsan_common.cc
    compiler-rt/trunk/lib/lsan/lsan_common.h
    compiler-rt/trunk/lib/lsan/lsan_interceptors.cc
    compiler-rt/trunk/lib/lsan/lsan_thread.cc
    compiler-rt/trunk/lib/lsan/lsan_thread.h

Modified: compiler-rt/trunk/lib/asan/asan_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_interceptors.cc?rev=185815&r1=185814&r2=185815&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_interceptors.cc Mon Jul  8 07:57:24 2013
@@ -138,6 +138,7 @@ extern "C" int pthread_attr_getdetachsta
 
 INTERCEPTOR(int, pthread_create, void *thread,
     void *attr, void *(*start_routine)(void*), void *arg) {
+  EnsureMainThreadIDIsCorrect();
   // Strict init-order checking in thread-hostile.
   if (flags()->strict_init_order)
     StopInitOrderChecking();

Modified: compiler-rt/trunk/lib/asan/asan_thread.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_thread.cc?rev=185815&r1=185814&r2=185815&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_thread.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_thread.cc Mon Jul  8 07:57:24 2013
@@ -211,7 +211,8 @@ static bool ThreadStackContainsAddress(T
 }
 
 AsanThread *GetCurrentThread() {
-  AsanThreadContext *context = (AsanThreadContext*)AsanTSDGet();
+  AsanThreadContext *context =
+      reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
   if (!context) {
     if (SANITIZER_ANDROID) {
       // On Android, libc constructor is called _after_ asan_init, and cleans up
@@ -254,6 +255,13 @@ AsanThread *FindThreadByStackAddress(upt
                                                    (void *)addr));
   return tctx ? tctx->thread : 0;
 }
+
+void EnsureMainThreadIDIsCorrect() {
+  AsanThreadContext *context =
+      reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
+  if (context && (context->tid == 0))
+    context->os_id = GetTid();
+}
 }  // namespace __asan
 
 // --- Implementation of LSan-specific functions --- {{{1
@@ -283,4 +291,8 @@ void LockThreadRegistry() {
 void UnlockThreadRegistry() {
   __asan::asanThreadRegistry().Unlock();
 }
+
+void EnsureMainThreadIDIsCorrect() {
+  __asan::EnsureMainThreadIDIsCorrect();
+}
 }  // namespace __lsan

Modified: compiler-rt/trunk/lib/asan/asan_thread.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_thread.h?rev=185815&r1=185814&r2=185815&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_thread.h (original)
+++ compiler-rt/trunk/lib/asan/asan_thread.h Mon Jul  8 07:57:24 2013
@@ -124,6 +124,8 @@ void SetCurrentThread(AsanThread *t);
 u32 GetCurrentTidOrInvalid();
 AsanThread *FindThreadByStackAddress(uptr addr);
 
+// Used to handle fork().
+void EnsureMainThreadIDIsCorrect();
 }  // namespace __asan
 
 #endif  // ASAN_THREAD_H

Added: compiler-rt/trunk/lib/lsan/lit_tests/TestCases/fork.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/lsan/lit_tests/TestCases/fork.cc?rev=185815&view=auto
==============================================================================
--- compiler-rt/trunk/lib/lsan/lit_tests/TestCases/fork.cc (added)
+++ compiler-rt/trunk/lib/lsan/lit_tests/TestCases/fork.cc Mon Jul  8 07:57:24 2013
@@ -0,0 +1,24 @@
+// Test that thread local data is handled correctly after forking without exec().
+// RUN: %clangxx_lsan %s -o %t
+// RUN: %t 2>&1
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+__thread void *thread_local_var;
+
+int main() {
+  int status = 0;
+  thread_local_var = malloc(1337);
+  pid_t pid = fork();
+  assert(pid >= 0);
+  if (pid > 0) {
+    waitpid(pid, &status, 0);
+    assert(WIFEXITED(status));
+    return WEXITSTATUS(status);
+  }
+  return 0;
+}

Added: compiler-rt/trunk/lib/lsan/lit_tests/TestCases/fork_threaded.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/lsan/lit_tests/TestCases/fork_threaded.cc?rev=185815&view=auto
==============================================================================
--- compiler-rt/trunk/lib/lsan/lit_tests/TestCases/fork_threaded.cc (added)
+++ compiler-rt/trunk/lib/lsan/lit_tests/TestCases/fork_threaded.cc Mon Jul  8 07:57:24 2013
@@ -0,0 +1,44 @@
+// Test that thread local data is handled correctly after forking without
+// exec(). In this test leak checking is initiated from a non-main thread.
+// RUN: %clangxx_lsan %s -o %t
+// RUN: %t 2>&1
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+__thread void *thread_local_var;
+
+void *exit_thread_func(void *arg) {
+  exit(0);
+}
+
+void ExitFromThread() {
+  pthread_t tid;
+  int res;
+  res = pthread_create(&tid, 0, exit_thread_func, 0);
+  assert(res == 0);
+  res = pthread_join(tid, 0);
+  assert(res == 0);
+}
+
+int main() {
+  int status = 0;
+  thread_local_var = malloc(1337);
+  pid_t pid = fork();
+  assert(pid >= 0);
+  if (pid > 0) {
+    waitpid(pid, &status, 0);
+    assert(WIFEXITED(status));
+    return WEXITSTATUS(status);
+  } else {
+    // Spawn a thread and call exit() from there, to check that we track main
+    // thread's pid correctly even if leak checking is initiated from another
+    // thread.
+    ExitFromThread();
+  }
+  return 0;
+}

Modified: compiler-rt/trunk/lib/lsan/lsan_common.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/lsan/lsan_common.cc?rev=185815&r1=185814&r2=185815&view=diff
==============================================================================
--- compiler-rt/trunk/lib/lsan/lsan_common.cc (original)
+++ compiler-rt/trunk/lib/lsan/lsan_common.cc Mon Jul  8 07:57:24 2013
@@ -350,6 +350,7 @@ static void DoLeakCheckCallback(const Su
 }
 
 void DoLeakCheck() {
+  EnsureMainThreadIDIsCorrect();
   BlockingMutexLock l(&global_mutex);
   static bool already_done;
   CHECK(!already_done);

Modified: compiler-rt/trunk/lib/lsan/lsan_common.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/lsan/lsan_common.h?rev=185815&r1=185814&r2=185815&view=diff
==============================================================================
--- compiler-rt/trunk/lib/lsan/lsan_common.h (original)
+++ compiler-rt/trunk/lib/lsan/lsan_common.h Mon Jul  8 07:57:24 2013
@@ -135,6 +135,13 @@ void UnlockThreadRegistry();
 bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
                            uptr *tls_begin, uptr *tls_end,
                            uptr *cache_begin, uptr *cache_end);
+// If called from the main thread, updates the main thread's TID in the thread
+// registry. We need this to handle processes that fork() without a subsequent
+// exec(), which invalidates the recorded TID. To update it, we must call
+// gettid() from the main thread. Our solution is to call this function before
+// leak checking and also before every call to pthread_create() (to handle cases
+// where leak checking is initiated from a non-main thread).
+void EnsureMainThreadIDIsCorrect();
 // If p points into a chunk that has been allocated to the user, returns its
 // user-visible address. Otherwise, returns 0.
 uptr PointsIntoChunk(void *p);

Modified: compiler-rt/trunk/lib/lsan/lsan_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/lsan/lsan_interceptors.cc?rev=185815&r1=185814&r2=185815&view=diff
==============================================================================
--- compiler-rt/trunk/lib/lsan/lsan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/lsan/lsan_interceptors.cc Mon Jul  8 07:57:24 2013
@@ -218,6 +218,7 @@ extern "C" void *__lsan_thread_start_fun
 INTERCEPTOR(int, pthread_create, void *th, void *attr,
             void *(*callback)(void *), void *param) {
   Init();
+  EnsureMainThreadIDIsCorrect();
   __sanitizer_pthread_attr_t myattr;
   if (attr == 0) {
     pthread_attr_init(&myattr);

Modified: compiler-rt/trunk/lib/lsan/lsan_thread.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/lsan/lsan_thread.cc?rev=185815&r1=185814&r2=185815&view=diff
==============================================================================
--- compiler-rt/trunk/lib/lsan/lsan_thread.cc (original)
+++ compiler-rt/trunk/lib/lsan/lsan_thread.cc Mon Jul  8 07:57:24 2013
@@ -123,6 +123,11 @@ void ThreadJoin(u32 tid) {
   thread_registry->JoinThread(tid, /* arg */0);
 }
 
+void EnsureMainThreadIDIsCorrect() {
+  if (GetCurrentThread() == 0)
+    CurrentThreadContext()->os_id = GetTid();
+}
+
 ///// Interface to the common LSan module. /////
 
 bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,

Modified: compiler-rt/trunk/lib/lsan/lsan_thread.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/lsan/lsan_thread.h?rev=185815&r1=185814&r2=185815&view=diff
==============================================================================
--- compiler-rt/trunk/lib/lsan/lsan_thread.h (original)
+++ compiler-rt/trunk/lib/lsan/lsan_thread.h Mon Jul  8 07:57:24 2013
@@ -47,7 +47,7 @@ u32 ThreadTid(uptr uid);
 u32 GetCurrentThread();
 void SetCurrentThread(u32 tid);
 ThreadContext *CurrentThreadContext();
-
+void EnsureMainThreadIDIsCorrect();
 }  // namespace __lsan
 
 #endif  // LSAN_THREAD_H





More information about the llvm-commits mailing list