diff --git a/compiler-rt/test/tsan/Darwin/dyld-insert-libraries.c b/compiler-rt/test/tsan/Darwin/dyld-insert-libraries.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/tsan/Darwin/dyld-insert-libraries.c @@ -0,0 +1,108 @@ +// Test that dyld interposition works in the presence of DYLD_INSERT_LIBRARIES. +// Additionally, the injected library also has a pthread introspection hook that +// calls intercepted APIs before and after calling through to the TSan hook. +// This mirrors what libBacktraceRecording.dylib (Xcode 'Queue Debugging' +// feature) does. + +// RUN: %clang_tsan %s -o %t +// RUN: %clang_tsan %s -o %t.dylib -fno-sanitize=thread -dynamiclib -DSHARED_LIB +// +// RUN: env DYLD_INSERT_LIBRARIES=%t.dylib %run %t 2>&1 | FileCheck %s --implicit-check-not='ThreadSanitizer' + +#include +#include +#include +#include + +#if defined(SHARED_LIB) +enum { + PTHREAD_INTROSPECTION_THREAD_CREATE = 1, + PTHREAD_INTROSPECTION_THREAD_START, + PTHREAD_INTROSPECTION_THREAD_TERMINATE, + PTHREAD_INTROSPECTION_THREAD_DESTROY, +}; +typedef void (*pthread_introspection_hook_t)(unsigned int event, + pthread_t thread, void *addr, + size_t size); +extern pthread_introspection_hook_t pthread_introspection_hook_install( + pthread_introspection_hook_t hook); + +static pthread_introspection_hook_t previous_pthread_hook; +static void pthread_introspection_hook(unsigned int event, pthread_t thread, void *addr, size_t size) { + pthread_t self; + const unsigned k_max_thread_name_size = 64; + char name[k_max_thread_name_size]; + + // Use some intercepted APIs *before* TSan hook runs. + { + self = pthread_self(); + pthread_getname_np(self, name, k_max_thread_name_size); + if (strlen(name) == 0) { + strlcpy(name, "n/a", 4); + } + } + + // This calls through to the TSan-installed hook, because injected library + // constructors (DYLD_INSERT_LIBRARIES) run after the TSan initializer + // replacing and forwarding to the previous hook. + assert(previous_pthread_hook); + previous_pthread_hook(event, thread, addr, size); + + // Use some intercepted APIs *after* TSan hook runs. + { + self = pthread_self(); + pthread_getname_np(self, name, k_max_thread_name_size); + if (strlen(name) == 0) { + strlcpy(name, "n/a", 4); + } + } + + switch (event) { + case PTHREAD_INTROSPECTION_THREAD_CREATE: + fprintf(stderr, "THREAD_CREATE %p, self: %p, name: %s\n", thread, self, name); + break; + case PTHREAD_INTROSPECTION_THREAD_START: + fprintf(stderr, "THREAD_START %p, self: %p, name: %s\n", thread, self, name); + break; + case PTHREAD_INTROSPECTION_THREAD_TERMINATE: + fprintf(stderr, "THREAD_TERMINATE %p, self: %p, name: %s\n", thread, self, name); + break; + case PTHREAD_INTROSPECTION_THREAD_DESTROY: + fprintf(stderr, "THREAD_DESTROY %p, self: %p, name: %s\n", thread, self, name); + break; + } +} + +__attribute__((constructor)) +static void __library_initializer(void) { + fprintf(stderr, "__library_initializer\n"); + previous_pthread_hook = pthread_introspection_hook_install(pthread_introspection_hook); +} + +#else // defined(SHARED_LIB) + +void *Thread(void *a) { + pthread_setname_np("child thread"); + fprintf(stderr, "Hello from pthread\n"); + return NULL; +} + +int main() { + fprintf(stderr, "main\n"); + pthread_t t; + pthread_create(&t, NULL, Thread, NULL); + pthread_join(t, NULL); + fprintf(stderr, "Done.\n"); +} +#endif // defined(SHARED_LIB) + +// CHECK: __library_initializer +// CHECK: main +// Ignore TSan background thread. +// CHECK: THREAD_CREATE +// CHECK: THREAD_CREATE [[CHILD:0x[0-9a-f]+]], self: [[MAIN:0x[0-9a-f]+]], name: n/a +// CHECK: THREAD_START [[CHILD]], self: [[CHILD]], name: n/a +// CHECK: Hello from pthread +// CHECK: THREAD_TERMINATE [[CHILD]], self: [[CHILD]], name: child thread +// CHECK: THREAD_DESTROY [[CHILD]], self: [[MAIN]] +// CHECK: Done. diff --git a/compiler-rt/test/tsan/Darwin/dyld-library-path.c b/compiler-rt/test/tsan/Darwin/dyld-library-path.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/tsan/Darwin/dyld-library-path.c @@ -0,0 +1,22 @@ +// Test that dyld interposition works in the presence of DYLD_LIBRARY_PATH. + +// RUN: %clang_tsan %s -o %t +// RUN: env DYLD_LIBRARY_PATH=/usr/lib/system/introspection/ %run %t 2>&1 | FileCheck %s --implicit-check-not='ThreadSanitizer' + +#include +#include + +void *Thread(void *a) { + fprintf(stderr, "Hello from pthread\n"); + return NULL; +} + +int main() { + pthread_t t; + pthread_create(&t, NULL, Thread, NULL); + pthread_join(t, NULL); + fprintf(stderr, "Done.\n"); +} + +// CHECK: Hello from pthread +// CHECK: Done.