forked from OSchip/llvm-project
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 llvm-svn: 294994
This commit is contained in:
parent
48dfa1a6ed
commit
7cda03e6d1
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -34,6 +34,17 @@ static bool IsLinker(const char* full_name) {
|
|||
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();
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue