Skip to content

Commit

Permalink
[asan/lsan] Avoid possible deadlock in dynamic ASan runtime thread in…
Browse files Browse the repository at this point in the history
…itialization.

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
  • Loading branch information
Maxim Ostapenko committed Oct 28, 2016
1 parent 64428ac commit 984f42e
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
1 change: 1 addition & 0 deletions compiler-rt/lib/lsan/lsan_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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++; }
Expand Down
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 984f42e

Please sign in to comment.