[compiler-rt] r205617 - [asan] fix a leak in __tls_get_addr handler; introduce a run-time flag to disable this handler completely; remove a workaround for a bug fixed in glibc

Kostya Serebryany kcc at google.com
Fri Apr 4 02:10:59 PDT 2014


Author: kcc
Date: Fri Apr  4 04:10:58 2014
New Revision: 205617

URL: http://llvm.org/viewvc/llvm-project?rev=205617&view=rev
Log:
[asan] fix a leak in __tls_get_addr handler; introduce a run-time flag to disable this handler completely; remove a workaround for a bug fixed in glibc

Modified:
    compiler-rt/trunk/lib/asan/asan_rtl.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_tls_get_addr.cc
    compiler-rt/trunk/test/asan/TestCases/Linux/stress_dtls.c

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=205617&r1=205616&r2=205617&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_rtl.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_rtl.cc Fri Apr  4 04:10:58 2014
@@ -226,6 +226,7 @@ void InitializeFlags(Flags *f, const cha
   SetCommonFlagsDefaults(cf);
   cf->external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
   cf->malloc_context_size = kDefaultMallocContextSize;
+  cf->intercept_tls_get_addr = true;
 
   internal_memset(f, 0, sizeof(*f));
   f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28;

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc?rev=205617&r1=205616&r2=205617&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.cc Fri Apr  4 04:10:58 2014
@@ -53,6 +53,7 @@ void SetCommonFlagsDefaults(CommonFlags
   f->clear_shadow_mmap_threshold = 64 * 1024;
   f->color = "auto";
   f->legacy_pthread_cond = false;
+  f->intercept_tls_get_addr = false;
 }
 
 void ParseCommonFlagsFromString(CommonFlags *f, const char *str) {
@@ -115,6 +116,8 @@ void ParseCommonFlagsFromString(CommonFl
       "Colorize reports: (always|never|auto).");
   ParseFlag(str, &f->legacy_pthread_cond, "legacy_pthread_cond",
       "Enables support for dynamic libraries linked with libpthread 2.2.5.");
+  ParseFlag(str, &f->intercept_tls_get_addr, "intercept_tls_get_addr",
+            "Intercept __tls_get_addr.");
   ParseFlag(str, &f->help, "help", "Print the flag descriptions.");
 
   // Do a sanity check for certain flags.

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h?rev=205617&r1=205616&r2=205617&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.h Fri Apr  4 04:10:58 2014
@@ -50,6 +50,7 @@ struct CommonFlags {
   uptr clear_shadow_mmap_threshold;
   const char *color;
   bool legacy_pthread_cond;
+  bool intercept_tls_get_addr;
   bool help;
 };
 

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_tls_get_addr.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_tls_get_addr.cc?rev=205617&r1=205616&r2=205617&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_tls_get_addr.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_tls_get_addr.cc Fri Apr  4 04:10:58 2014
@@ -43,30 +43,41 @@ static atomic_uintptr_t number_of_live_d
 
 static const uptr kDestroyedThread = -1;
 
+static inline void DTLS_Deallocate(uptr size) {
+  if (!size) return;
+  VPrintf(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", &dtls, size);
+  UnmapOrDie(dtls.dtv, size * sizeof(DTLS::DTV));
+  atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed);
+}
+
 static inline void DTLS_Resize(uptr new_size) {
   if (dtls.dtv_size >= new_size) return;
   new_size = RoundUpToPowerOfTwo(new_size);
   new_size = Max(new_size, 4096UL / sizeof(DTLS::DTV));
   DTLS::DTV *new_dtv =
       (DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize");
-  CHECK_LT(atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed),
-           1 << 20);
-  if (dtls.dtv_size)
+  uptr num_live_dtls =
+      atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed);
+  VPrintf(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls);
+  CHECK_LT(num_live_dtls, 1 << 20);
+  if (dtls.dtv_size) {
     internal_memcpy(new_dtv, dtls.dtv, dtls.dtv_size * sizeof(DTLS::DTV));
-  DTLS_Destroy();
+    DTLS_Deallocate(dtls.dtv_size);
+  }
   dtls.dtv = new_dtv;
   dtls.dtv_size = new_size;
 }
 
 void DTLS_Destroy() {
-  if (!dtls.dtv_size) return;
+  if (!common_flags()->intercept_tls_get_addr) return;
+  VPrintf(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size);
   uptr s = dtls.dtv_size;
   dtls.dtv_size = kDestroyedThread;  // Do this before unmap for AS-safety.
-  UnmapOrDie(dtls.dtv, s * sizeof(DTLS::DTV));
-  atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed);
+  DTLS_Deallocate(s);
 }
 
 void DTLS_on_tls_get_addr(void *arg_void, void *res) {
+  if (!common_flags()->intercept_tls_get_addr) return;
   TlsGetAddrParam *arg = reinterpret_cast<TlsGetAddrParam *>(arg_void);
   uptr dso_id = arg->dso_id;
   if (dtls.dtv_size == kDestroyedThread) return;
@@ -75,29 +86,23 @@ void DTLS_on_tls_get_addr(void *arg_void
     return;
   uptr tls_size = 0;
   uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset;
-  // This function uses the fancy 2147483647 verbosity level,
-  // because printing in this function crashes with some versions of libstdc++
-  // because of the following bug:
-  // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066
-  // The bug leads to mis-aligned stack in this function, and subsequently
-  // SSE instructions in Printf crash.
-  // But there is a test that searches for printfs from this function.
-  // The bug can affect any code, so do as less as possible here.
-  VPrintf(2147483647, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p\n",
-      arg, arg->dso_id, arg->offset, res, tls_beg, &tls_beg);
+  VPrintf(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p "
+             "num_live_dtls %zd\n",
+          arg, arg->dso_id, arg->offset, res, tls_beg, &tls_beg,
+          atomic_load(&number_of_live_dtls, memory_order_relaxed));
   if (dtls.last_memalign_ptr == tls_beg) {
     tls_size = dtls.last_memalign_size;
-    VPrintf(2147483647, "__tls_get_addr: glibc <=2.18 suspected; tls={%p,%p}\n",
+    VPrintf(2, "__tls_get_addr: glibc <=2.18 suspected; tls={%p,%p}\n",
         tls_beg, tls_size);
   } else if ((tls_beg % 4096) == sizeof(Glibc_2_19_tls_header)) {
     // We may want to check gnu_get_libc_version().
     Glibc_2_19_tls_header *header = (Glibc_2_19_tls_header *)tls_beg - 1;
     tls_size = header->size;
     tls_beg = header->start;
-    VPrintf(2147483647, "__tls_get_addr: glibc >=2.19 suspected; tls={%p %p}\n",
+    VPrintf(2, "__tls_get_addr: glibc >=2.19 suspected; tls={%p %p}\n",
         tls_beg, tls_size);
   } else {
-    VPrintf(2147483647, "__tls_get_addr: Can't guess glibc version\n");
+    VPrintf(2, "__tls_get_addr: Can't guess glibc version\n");
     // This may happen inside the DTOR of main thread, so just ignore it.
     tls_size = 0;
   }
@@ -106,7 +111,8 @@ void DTLS_on_tls_get_addr(void *arg_void
 }
 
 void DTLS_on_libc_memalign(void *ptr, uptr size) {
-  VPrintf(2147483647, "DTLS_on_libc_memalign: %p %p\n", ptr, size);
+  if (!common_flags()->intercept_tls_get_addr) return;
+  VPrintf(2, "DTLS_on_libc_memalign: %p %p\n", ptr, size);
   dtls.last_memalign_ptr = reinterpret_cast<uptr>(ptr);
   dtls.last_memalign_size = size;
 }

Modified: compiler-rt/trunk/test/asan/TestCases/Linux/stress_dtls.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Linux/stress_dtls.c?rev=205617&r1=205616&r2=205617&view=diff
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Linux/stress_dtls.c (original)
+++ compiler-rt/trunk/test/asan/TestCases/Linux/stress_dtls.c Fri Apr  4 04:10:58 2014
@@ -12,12 +12,22 @@
 // RUN: %clangxx_asan %s -o %t
 // RUN: %t 0 3
 // RUN: %t 2 3
-// RUN: ASAN_OPTIONS=verbosity=2147483647 %t 2 2 2>&1 | FileCheck %s
+// RUN: ASAN_OPTIONS=verbosity=2 %t 10 2 2>&1 | FileCheck %s
+// RUN: ASAN_OPTIONS=verbosity=2:intercept_tls_get_addr=1 %t 10 2 2>&1 | FileCheck %s
+// RUN: ASAN_OPTIONS=verbosity=2:intercept_tls_get_addr=0 %t 10 2 2>&1 | FileCheck %s --check-prefix=CHECK0
 // CHECK: __tls_get_addr
+// CHECK: Creating thread 0
 // CHECK: __tls_get_addr
+// CHECK: Creating thread 1
 // CHECK: __tls_get_addr
+// CHECK: Creating thread 2
 // CHECK: __tls_get_addr
+// CHECK: Creating thread 3
 // CHECK: __tls_get_addr
+// Make sure that TLS slots don't leak
+// CHECK-NOT: num_live_dtls 5
+//
+// CHECK0-NOT: __tls_get_addr
 /*
 cc=your-compiler
 
@@ -88,6 +98,7 @@ int main(int argc, char *argv[]) {
     int i;
     for (i = 0; i < num_threads; i++) {
       pthread_t t;
+      fprintf(stderr, "Creating thread %d\n", i);
       pthread_create(&t, 0, PrintStuff, 0);
       pthread_join(t, 0);
     }





More information about the llvm-commits mailing list