[compiler-rt] r294994 - Use pthreads to manage thread-local storage on darwin for leak sanitizer

Francis Ricci via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 13 14:20:08 PST 2017


Author: fjricci
Date: Mon Feb 13 16:20:07 2017
New Revision: 294994

URL: http://llvm.org/viewvc/llvm-project?rev=294994&view=rev
Log:
Use pthreads to manage thread-local storage on darwin for leak sanitizer

Summary:
__thread is supported on Darwin, but is implemented dynamically via
function calls to __tls_get_addr. This causes two issues when combined
with leak sanitizer, due to malloc() interception.

- The dynamic loader calls malloc during the process of loading
  the sanitizer dylib, while swapping a placeholder tlv_boostrap
  function for __tls_get_addr. This will cause tlv_bootstrap to
  be called in DisabledInThisThread() via the asan allocator.

- The first time __tls_get_addr is called, it allocates memory
  for the thread-local object, during which it calls malloc(). This
  call will be intercepted, leading to an infinite loop in the asan
  allocator, in which the allocator calls DisabledInThisThread,
  which calls tls_get_addr, which calls into the allocator again.

Reviewers: kcc, glider, kubamracek

Subscribers: llvm-commits

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

Modified:
    compiler-rt/trunk/lib/lsan/lsan_common.cc
    compiler-rt/trunk/lib/lsan/lsan_common.h
    compiler-rt/trunk/lib/lsan/lsan_common_linux.cc
    compiler-rt/trunk/lib/lsan/lsan_common_mac.cc

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=294994&r1=294993&r2=294994&view=diff
==============================================================================
--- compiler-rt/trunk/lib/lsan/lsan_common.cc (original)
+++ compiler-rt/trunk/lib/lsan/lsan_common.cc Mon Feb 13 16:20:07 2017
@@ -32,20 +32,15 @@ namespace __lsan {
 // also to protect the global list of root regions.
 BlockingMutex global_mutex(LINKER_INITIALIZED);
 
-__attribute__((tls_model("initial-exec")))
-THREADLOCAL int disable_counter;
-bool DisabledInThisThread() { return disable_counter > 0; }
-void DisableInThisThread() { disable_counter++; }
-void EnableInThisThread() {
-  if (!disable_counter && common_flags()->detect_leaks) {
+Flags lsan_flags;
+
+void DisableCounterUnderflow() {
+  if (common_flags()->detect_leaks) {
     Report("Unmatched call to __lsan_enable().\n");
     Die();
   }
-  disable_counter--;
 }
 
-Flags lsan_flags;
-
 void Flags::SetDefaults() {
 #define LSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
 #include "lsan_flags.inc"

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=294994&r1=294993&r2=294994&view=diff
==============================================================================
--- compiler-rt/trunk/lib/lsan/lsan_common.h (original)
+++ compiler-rt/trunk/lib/lsan/lsan_common.h Mon Feb 13 16:20:07 2017
@@ -127,6 +127,7 @@ enum IgnoreObjectResult {
 // Functions called from the parent tool.
 void InitCommonLsan();
 void DoLeakCheck();
+void DisableCounterUnderflow();
 bool DisabledInThisThread();
 
 // Used to implement __lsan::ScopedDisabler.

Modified: compiler-rt/trunk/lib/lsan/lsan_common_linux.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/lsan/lsan_common_linux.cc?rev=294994&r1=294993&r2=294994&view=diff
==============================================================================
--- compiler-rt/trunk/lib/lsan/lsan_common_linux.cc (original)
+++ compiler-rt/trunk/lib/lsan/lsan_common_linux.cc Mon Feb 13 16:20:07 2017
@@ -34,6 +34,17 @@ static bool IsLinker(const char* full_na
   return LibraryNameIs(full_name, kLinkerName);
 }
 
+__attribute__((tls_model("initial-exec")))
+THREADLOCAL int disable_counter;
+bool DisabledInThisThread() { return disable_counter > 0; }
+void DisableInThisThread() { disable_counter++; }
+void EnableInThisThread() {
+  if (disable_counter == 0) {
+    DisableCounterUnderflow();
+  }
+  disable_counter--;
+}
+
 void InitializePlatformSpecificModules() {
   ListOfModules modules;
   modules.init();

Modified: compiler-rt/trunk/lib/lsan/lsan_common_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/lsan/lsan_common_mac.cc?rev=294994&r1=294993&r2=294994&view=diff
==============================================================================
--- compiler-rt/trunk/lib/lsan/lsan_common_mac.cc (original)
+++ compiler-rt/trunk/lib/lsan/lsan_common_mac.cc Mon Feb 13 16:20:07 2017
@@ -12,12 +12,53 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "sanitizer_common/sanitizer_allocator_internal.h"
 #include "sanitizer_common/sanitizer_platform.h"
 #include "lsan_common.h"
 
 #if CAN_SANITIZE_LEAKS && SANITIZER_MAC
+
+#include <pthread.h>
+
 namespace __lsan {
 
+static pthread_key_t key;
+static pthread_once_t key_once = PTHREAD_ONCE_INIT;
+
+static void make_tls_key() { CHECK_EQ(pthread_key_create(&key, NULL), 0); }
+
+static int *get_tls_val(bool allocate) {
+  pthread_once(&key_once, make_tls_key);
+
+  int *ptr = (int *)pthread_getspecific(key);
+  if (ptr == NULL && allocate) {
+    ptr = (int *)InternalAlloc(sizeof(*ptr));
+    *ptr = 0;
+    pthread_setspecific(key, ptr);
+  }
+
+  return ptr;
+}
+
+bool DisabledInThisThread() {
+  int *disable_counter = get_tls_val(false);
+  return disable_counter ? *disable_counter > 0 : false;
+}
+
+void DisableInThisThread() {
+  int *disable_counter = get_tls_val(true);
+
+  ++*disable_counter;
+}
+
+void EnableInThisThread() {
+  int *disable_counter = get_tls_val(true);
+  if (*disable_counter == 0) {
+    DisableCounterUnderflow();
+  }
+  --*disable_counter;
+}
+
 void InitializePlatformSpecificModules() {
   CHECK(0 && "unimplemented");
 }




More information about the llvm-commits mailing list