xref: /llvm-project/compiler-rt/test/tsan/Darwin/dyld-insert-libraries.c (revision 8e724ad96565de7f91d7d9f89c24d0086086a903)
1 // Test that dyld interposition works in the presence of DYLD_INSERT_LIBRARIES.
2 // Additionally, the injected library also has a pthread introspection hook that
3 // calls intercepted APIs before and after calling through to the TSan hook.
4 // This mirrors what libBacktraceRecording.dylib (Xcode 'Queue Debugging'
5 // feature) does.
6 
7 // RUN: %clang_tsan %s -o %t
8 // RUN: %clang_tsan %s -o %t.dylib -fno-sanitize=thread -dynamiclib -DSHARED_LIB
9 //
10 // RUN: env DYLD_INSERT_LIBRARIES=%t.dylib %run %t 2>&1 | FileCheck %s --implicit-check-not='ThreadSanitizer'
11 //
12 // XFAIL: ios
13 
14 #include <assert.h>
15 #include <pthread.h>
16 #include <stdio.h>
17 #include <string.h>
18 
19 #if defined(SHARED_LIB)
20 enum {
21   PTHREAD_INTROSPECTION_THREAD_CREATE = 1,
22   PTHREAD_INTROSPECTION_THREAD_START,
23   PTHREAD_INTROSPECTION_THREAD_TERMINATE,
24   PTHREAD_INTROSPECTION_THREAD_DESTROY,
25 };
26 typedef void (*pthread_introspection_hook_t)(unsigned int event,
27                                              pthread_t thread, void *addr,
28                                              size_t size);
29 extern pthread_introspection_hook_t pthread_introspection_hook_install(
30     pthread_introspection_hook_t hook);
31 
32 static pthread_introspection_hook_t previous_pthread_hook;
pthread_introspection_hook(unsigned int event,pthread_t thread,void * addr,size_t size)33 static void pthread_introspection_hook(unsigned int event, pthread_t thread, void *addr, size_t size) {
34   pthread_t self;
35   const unsigned k_max_thread_name_size = 64;
36   char name[k_max_thread_name_size];
37 
38   // Use some intercepted APIs *before* TSan hook runs.
39   {
40     self = pthread_self();
41     pthread_getname_np(self, name, k_max_thread_name_size);
42     if (strlen(name) == 0) {
43       strlcpy(name, "n/a", 4);
44     }
45   }
46 
47   // This calls through to the TSan-installed hook, because the injected library
48   // constructor (see __library_initializer() below) runs after the TSan
49   // initializer.  It replaces and forward to the previously-installed TSan
50   // introspection hook (very similar to what libBacktraceRecording.dylib does).
51   assert(previous_pthread_hook);
52   previous_pthread_hook(event, thread, addr, size);
53 
54   // Use some intercepted APIs *after* TSan hook runs.
55   {
56     assert(self == pthread_self());
57     char name2[k_max_thread_name_size];
58     pthread_getname_np(self, name2, k_max_thread_name_size);
59     if (strlen(name2) == 0) {
60       strlcpy(name2, "n/a", 4);
61     }
62     assert(strcmp(name, name2) == 0);
63   }
64 
65   switch (event) {
66   case PTHREAD_INTROSPECTION_THREAD_CREATE:
67     fprintf(stderr, "THREAD_CREATE    %p, self: %p, name: %s\n", thread, self, name);
68     break;
69   case PTHREAD_INTROSPECTION_THREAD_START:
70     fprintf(stderr, "THREAD_START     %p, self: %p, name: %s\n", thread, self, name);
71     break;
72   case PTHREAD_INTROSPECTION_THREAD_TERMINATE:
73     fprintf(stderr, "THREAD_TERMINATE %p, self: %p, name: %s\n", thread, self, name);
74     break;
75   case PTHREAD_INTROSPECTION_THREAD_DESTROY:
76     fprintf(stderr, "THREAD_DESTROY   %p, self: %p, name: %s\n", thread, self, name);
77     break;
78   }
79 }
80 
81 __attribute__((constructor))
__library_initializer(void)82 static void __library_initializer(void) {
83   fprintf(stderr, "__library_initializer\n");
84   previous_pthread_hook = pthread_introspection_hook_install(pthread_introspection_hook);
85 }
86 
87 #else  // defined(SHARED_LIB)
88 
Thread(void * a)89 void *Thread(void *a) {
90   pthread_setname_np("child thread");
91   fprintf(stderr, "Hello from pthread\n");
92   return NULL;
93 }
94 
main()95 int main() {
96   fprintf(stderr, "main\n");
97   pthread_t t;
98   pthread_create(&t, NULL, Thread, NULL);
99   pthread_join(t, NULL);
100   fprintf(stderr, "Done.\n");
101 }
102 #endif  // defined(SHARED_LIB)
103 
104 // CHECK: __library_initializer
105 // CHECK: main
106 // Ignore TSan background thread.
107 // CHECK: THREAD_CREATE
108 // CHECK: THREAD_CREATE    [[CHILD:0x[0-9a-f]+]]
109 // CHECK: THREAD_START     [[CHILD]], self: [[CHILD]], name: n/a
110 // CHECK: Hello from pthread
111 // CHECK: THREAD_TERMINATE [[CHILD]], self: [[CHILD]], name: child thread
112 // CHECK: THREAD_DESTROY   [[CHILD]]
113