[compiler-rt] r192585 - [asan] Improve thread lifetime tracking on POSIX systems.

Sergey Matveev earthdok at google.com
Mon Oct 14 05:01:05 PDT 2013


Author: smatveev
Date: Mon Oct 14 07:01:05 2013
New Revision: 192585

URL: http://llvm.org/viewvc/llvm-project?rev=192585&view=rev
Log:
[asan] Improve thread lifetime tracking on POSIX systems.

Call AsanThread::Destroy() from a late-running TSD destructor.
Previously we called it before any user-registered TSD destructors, which caused
false positives in LeakSanitizer.

Added:
    compiler-rt/trunk/lib/lsan/lit_tests/TestCases/cleanup_in_tsd_destructor.cc
Modified:
    compiler-rt/trunk/lib/asan/asan_internal.h
    compiler-rt/trunk/lib/asan/asan_posix.cc
    compiler-rt/trunk/lib/asan/asan_rtl.cc
    compiler-rt/trunk/lib/asan/asan_thread.cc
    compiler-rt/trunk/lib/asan/asan_thread.h
    compiler-rt/trunk/lib/asan/asan_win.cc

Modified: compiler-rt/trunk/lib/asan/asan_internal.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_internal.h?rev=192585&r1=192584&r2=192585&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_internal.h (original)
+++ compiler-rt/trunk/lib/asan/asan_internal.h Mon Oct 14 07:01:05 2013
@@ -98,6 +98,7 @@ void StopInitOrderChecking();
 void AsanTSDInit(void (*destructor)(void *tsd));
 void *AsanTSDGet();
 void AsanTSDSet(void *tsd);
+void PlatformTSDDtor(void *tsd);
 
 void AppendToErrorMessageBuffer(const char *buffer);
 

Modified: compiler-rt/trunk/lib/asan/asan_posix.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_posix.cc?rev=192585&r1=192584&r2=192585&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_posix.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_posix.cc Mon Oct 14 07:01:05 2013
@@ -1,4 +1,4 @@
-//===-- asan_linux.cc -----------------------------------------------------===//
+//===-- asan_posix.cc -----------------------------------------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -116,6 +116,15 @@ void AsanTSDSet(void *tsd) {
   pthread_setspecific(tsd_key, tsd);
 }
 
+void PlatformTSDDtor(void *tsd) {
+  AsanThreadContext *context = (AsanThreadContext*)tsd;
+  if (context->destructor_iterations > 1) {
+    context->destructor_iterations--;
+    CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
+    return;
+  }
+  AsanThread::TSDDtor(tsd);
+}
 }  // namespace __asan
 
 #endif  // SANITIZER_LINUX || SANITIZER_MAC

Modified: compiler-rt/trunk/lib/asan/asan_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_rtl.cc?rev=192585&r1=192584&r2=192585&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_rtl.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_rtl.cc Mon Oct 14 07:01:05 2013
@@ -535,7 +535,7 @@ void __asan_init() {
 
   InstallSignalHandlers();
 
-  AsanTSDInit(AsanThread::TSDDtor);
+  AsanTSDInit(PlatformTSDDtor);
   // Allocator should be initialized before starting external symbolizer, as
   // fork() on Mac locks the allocator.
   InitializeAllocator();

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=192585&r1=192584&r2=192585&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_thread.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_thread.cc Mon Oct 14 07:01:05 2013
@@ -165,7 +165,13 @@ thread_return_t AsanThread::ThreadStart(
   malloc_storage().CommitBack();
   if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
 
-  this->Destroy();
+  // On POSIX systems we defer this to the TSD destructor. LSan will consider
+  // the thread's memory as non-live from the moment we call Destroy(), even
+  // though that memory might contain pointers to heap objects which will be
+  // cleaned up by a user-defined TSD destructor. Thus, calling Destroy() before
+  // the TSD destructors have run might cause false positives in LSan.
+  if (!SANITIZER_POSIX)
+    this->Destroy();
 
   return res;
 }

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=192585&r1=192584&r2=192585&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_thread.h (original)
+++ compiler-rt/trunk/lib/asan/asan_thread.h Mon Oct 14 07:01:05 2013
@@ -19,6 +19,7 @@
 #include "asan_fake_stack.h"
 #include "asan_stack.h"
 #include "asan_stats.h"
+#include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_thread_registry.h"
 
@@ -36,10 +37,12 @@ class AsanThreadContext : public ThreadC
   explicit AsanThreadContext(int tid)
       : ThreadContextBase(tid),
         announced(false),
+        destructor_iterations(kPthreadDestructorIterations),
         thread(0) {
     internal_memset(&stack, 0, sizeof(stack));
   }
   bool announced;
+  int destructor_iterations;
   StackTrace stack;
   AsanThread *thread;
 

Modified: compiler-rt/trunk/lib/asan/asan_win.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_win.cc?rev=192585&r1=192584&r2=192585&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_win.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_win.cc Mon Oct 14 07:01:05 2013
@@ -60,6 +60,9 @@ void AsanTSDSet(void *tsd) {
   fake_tsd = tsd;
 }
 
+void PlatformTSDDtor(void *tsd) {
+  AsanThread::TSDDtor(tsd);
+}
 // ---------------------- Various stuff ---------------- {{{1
 void MaybeReexec() {
   // No need to re-exec on Windows.

Added: compiler-rt/trunk/lib/lsan/lit_tests/TestCases/cleanup_in_tsd_destructor.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/lsan/lit_tests/TestCases/cleanup_in_tsd_destructor.cc?rev=192585&view=auto
==============================================================================
--- compiler-rt/trunk/lib/lsan/lit_tests/TestCases/cleanup_in_tsd_destructor.cc (added)
+++ compiler-rt/trunk/lib/lsan/lit_tests/TestCases/cleanup_in_tsd_destructor.cc Mon Oct 14 07:01:05 2013
@@ -0,0 +1,45 @@
+// Regression test for thread lifetime tracking. Thread data should be
+// considered live during the thread's termination, at least until the
+// user-installed TSD destructors have finished running (since they may contain
+// additional cleanup tasks). LSan doesn't actually meet that goal 100%, but it
+// makes its best effort.
+// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:use_tls=1 %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:use_tls=0 not %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sanitizer/lsan_interface.h"
+
+pthread_key_t key;
+__thread void *p;
+
+void key_destructor(void *arg) {
+  // Generally this may happen on a different thread.
+  __lsan_do_leak_check();
+}
+
+void *thread_func(void *arg) {
+  p = malloc(1337);
+  fprintf(stderr, "Test alloc: %p.\n", p);
+  int res = pthread_setspecific(key, (void*)1);
+  assert(res == 0);
+  return 0;
+}
+
+int main() {
+  int res = pthread_key_create(&key, &key_destructor);
+  assert(res == 0);
+  pthread_t thread_id;
+  res = pthread_create(&thread_id, 0, thread_func, 0);
+  assert(res == 0);
+  res = pthread_join(thread_id, 0);
+  assert(res == 0);
+  return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: leaked 1337 byte object at [[ADDR]]





More information about the llvm-commits mailing list