[compiler-rt] ee0ac45 - [TSan][Darwin] Add integration tests for dyld interposition
Julian Lettner via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 9 13:34:17 PDT 2021
Author: Julian Lettner
Date: 2021-09-09T22:33:59+02:00
New Revision: ee0ac45672367e4590fe6e1da0b798b8a4816dc7
URL: https://github.com/llvm/llvm-project/commit/ee0ac45672367e4590fe6e1da0b798b8a4816dc7
DIFF: https://github.com/llvm/llvm-project/commit/ee0ac45672367e4590fe6e1da0b798b8a4816dc7.diff
LOG: [TSan][Darwin] Add integration tests for dyld interposition
Add integration tests for dyld interposition: DYLD_LIBRARY_PATH and
DYLD_INSERT_LIBRARIES.
DYLD_INSERT_LIBRARIES is also relevant for TSan thread
finalization/destruction sequence in the presence of additional pthread
introspection hooks (libBacktraceRecording.dylib for Xcode 'Queue
Debugging' feature).
rdar://78739125
Differential Revision: https://reviews.llvm.org/D109332
Added:
compiler-rt/test/tsan/Darwin/dyld-insert-libraries.c
compiler-rt/test/tsan/Darwin/dyld-library-path.c
Modified:
Removed:
################################################################################
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
index 0000000000000..04fa78a7665f5
--- /dev/null
+++ b/compiler-rt/test/tsan/Darwin/dyld-insert-libraries.c
@@ -0,0 +1,113 @@
+// 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'
+//
+// XFAIL: ios
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+
+#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 the injected library
+ // constructor (see __library_initializer() below) runs after the TSan
+ // initializer. It replaces and forward to the previously-installed TSan
+ // introspection hook (very similar to what libBacktraceRecording.dylib does).
+ assert(previous_pthread_hook);
+ previous_pthread_hook(event, thread, addr, size);
+
+ // Use some intercepted APIs *after* TSan hook runs.
+ {
+ assert(self == pthread_self());
+ char name2[k_max_thread_name_size];
+ pthread_getname_np(self, name2, k_max_thread_name_size);
+ if (strlen(name2) == 0) {
+ strlcpy(name2, "n/a", 4);
+ }
+ assert(strcmp(name, name2) == 0);
+ }
+
+ 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
index 0000000000000..729c45d53fcee
--- /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 <pthread.h>
+#include <stdio.h>
+
+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.
More information about the llvm-commits
mailing list