Detect thread termination in LSan/NetBSD
authorKamil Rytarowski <n54@gmx.com>
Sun, 26 Nov 2017 09:42:01 +0000 (09:42 +0000)
committerKamil Rytarowski <n54@gmx.com>
Sun, 26 Nov 2017 09:42:01 +0000 (09:42 +0000)
Summary:
Stop using the Linux solution with pthread_key_create(3).
This approach does not work on NetBSD, because calling
the thread destructor is not the latest operation on a POSIX
thread entity.

Detect _lwp_exit(2) call as it is really the latest operation
called from a detaching POSIX thread.

The pthread_key_create(3) solution also cannot be used
in early libc/libpthread initialization on NetBSD as the
system libraries are not bootstrapped enough.

Sponsored by <The NetBSD Foundation>

Reviewers: joerg, vitalybuka, kcc, dvyukov

Reviewed By: dvyukov

Subscribers: llvm-commits, #sanitizers

Tags: #sanitizers

Differential Revision: https://reviews.llvm.org/D40457

llvm-svn: 318994

compiler-rt/lib/lsan/lsan_interceptors.cc

index a7c0f72..b3e73e3 100644 (file)
@@ -309,6 +309,7 @@ INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
 
 ///// Thread initialization and finalization. /////
 
+#if !SANITIZER_NETBSD
 static unsigned g_thread_finalize_key;
 
 static void thread_finalize(void *v) {
@@ -322,6 +323,18 @@ static void thread_finalize(void *v) {
   }
   ThreadFinish();
 }
+#endif
+
+#if SANITIZER_NETBSD
+INTERCEPTOR(void, _lwp_exit) {
+  ENSURE_LSAN_INITED;
+  ThreadFinish();
+  REAL(_lwp_exit)();
+}
+#define LSAN_MAYBE_INTERCEPT__LWP_EXIT INTERCEPT_FUNCTION(_lwp_exit)
+#else
+#define LSAN_MAYBE_INTERCEPT__LWP_EXIT
+#endif
 
 struct ThreadParam {
   void *(*callback)(void *arg);
@@ -335,11 +348,13 @@ extern "C" void *__lsan_thread_start_func(void *arg) {
   void *param = p->param;
   // Wait until the last iteration to maximize the chance that we are the last
   // destructor to run.
+#if !SANITIZER_NETBSD
   if (pthread_setspecific(g_thread_finalize_key,
                           (void*)GetPthreadDestructorIterations())) {
     Report("LeakSanitizer: failed to set thread key.\n");
     Die();
   }
+#endif
   int tid = 0;
   while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
     internal_sched_yield();
@@ -427,10 +442,14 @@ void InitializeInterceptors() {
   INTERCEPT_FUNCTION(pthread_join);
   INTERCEPT_FUNCTION(_exit);
 
+  LSAN_MAYBE_INTERCEPT__LWP_EXIT;
+
+#if !SANITIZER_NETBSD
   if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
     Report("LeakSanitizer: failed to create thread key.\n");
     Die();
   }
+#endif
 }
 
 } // namespace __lsan