forked from OSchip/llvm-project
[asan/lsan] Avoid possible deadlock in dynamic ASan runtime thread initialization.
There is possible deadlock in dynamic ASan runtime when we dlopen() shared lib which creates a thread at the global initialization stage. The scenario: 1) dlopen grabs a GI_pthread_mutex_lock in main thread. 2) main thread calls pthread_create, ASan intercepts it, calls real pthread_create and waits for the second thread to be "fully initialized". 3) Newly created thread tries to access a thread local disable_counter in LSan (to complete its "full initialization") and hangs in tls_get_addr_tail, because it also tries to acquire GI_pthread_mutex_lock. The issue is reproducible on relative recent Glibc versions e.g. 2.23. Differential Revision: https://reviews.llvm.org/D26028 llvm-svn: 285385
This commit is contained in:
parent
64428acf41
commit
984f42eed5
|
@ -32,6 +32,7 @@ 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++; }
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
// Test that ASan doesn't deadlock in __interceptor_pthread_create called
|
||||
// from dlopened shared library constructor. The deadlock happens only in shared
|
||||
// ASan runtime with recent Glibc (2.23 fits) when __interceptor_pthread_create
|
||||
// grabs global Glibc's GL(dl_load_lock) and waits for tls_get_addr_tail that
|
||||
// also tries to acquire it.
|
||||
//
|
||||
// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t-so.so
|
||||
// RUN: %clangxx_asan %s -o %t
|
||||
// RUN: %run %t 2>&1
|
||||
|
||||
// dlopen() can not be intercepted on Android
|
||||
// UNSUPPORTED: android
|
||||
|
||||
#ifdef BUILD_SO
|
||||
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void *threadFn(void *) {
|
||||
fprintf(stderr, "thread started\n");
|
||||
while (true) {
|
||||
usleep(100000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __attribute__((constructor)) startPolling() {
|
||||
fprintf(stderr, "initializing library\n");
|
||||
pthread_t t;
|
||||
pthread_create(&t, 0, &threadFn, 0);
|
||||
fprintf(stderr, "done\n");
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
std::string path = std::string(argv[0]) + "-so.so";
|
||||
void *handle = dlopen(path.c_str(), RTLD_LAZY);
|
||||
if (!handle)
|
||||
abort();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue