Index: compiler-rt/trunk/lib/lsan/lsan_common.h =================================================================== --- compiler-rt/trunk/lib/lsan/lsan_common.h +++ compiler-rt/trunk/lib/lsan/lsan_common.h @@ -127,6 +127,7 @@ // Functions called from the parent tool. void InitCommonLsan(); void DoLeakCheck(); +void DisableCounterUnderflow(); bool DisabledInThisThread(); // Used to implement __lsan::ScopedDisabler. Index: compiler-rt/trunk/lib/lsan/lsan_common.cc =================================================================== --- compiler-rt/trunk/lib/lsan/lsan_common.cc +++ compiler-rt/trunk/lib/lsan/lsan_common.cc @@ -32,20 +32,15 @@ // 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" Index: compiler-rt/trunk/lib/lsan/lsan_common_linux.cc =================================================================== --- compiler-rt/trunk/lib/lsan/lsan_common_linux.cc +++ compiler-rt/trunk/lib/lsan/lsan_common_linux.cc @@ -34,6 +34,17 @@ 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(); Index: compiler-rt/trunk/lib/lsan/lsan_common_mac.cc =================================================================== --- compiler-rt/trunk/lib/lsan/lsan_common_mac.cc +++ compiler-rt/trunk/lib/lsan/lsan_common_mac.cc @@ -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 + 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"); }