[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