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'
7 // RUN: %clang_tsan %s -o %t
8 // RUN: %clang_tsan %s -o %t.dylib -fno-sanitize=thread -dynamiclib -DSHARED_LIB
10 // RUN: env DYLD_INSERT_LIBRARIES=%t.dylib %run %t 2>&1 | FileCheck %s --implicit-check-not='ThreadSanitizer'
19 #if defined(SHARED_LIB)
21 PTHREAD_INTROSPECTION_THREAD_CREATE
= 1,
22 PTHREAD_INTROSPECTION_THREAD_START
,
23 PTHREAD_INTROSPECTION_THREAD_TERMINATE
,
24 PTHREAD_INTROSPECTION_THREAD_DESTROY
,
26 typedef void (*pthread_introspection_hook_t
)(unsigned int event
,
27 pthread_t thread
, void *addr
,
29 extern pthread_introspection_hook_t
pthread_introspection_hook_install(
30 pthread_introspection_hook_t hook
);
32 static pthread_introspection_hook_t previous_pthread_hook
;
33 static void pthread_introspection_hook(unsigned int event
, pthread_t thread
, void *addr
, size_t size
) {
35 const unsigned k_max_thread_name_size
= 64;
36 char name
[k_max_thread_name_size
];
38 // Use some intercepted APIs *before* TSan hook runs.
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);
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
);
54 // Use some intercepted APIs *after* TSan hook runs.
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);
62 assert(strcmp(name
, name2
) == 0);
66 case PTHREAD_INTROSPECTION_THREAD_CREATE
:
67 fprintf(stderr
, "THREAD_CREATE %p, self: %p, name: %s\n", thread
, self
, name
);
69 case PTHREAD_INTROSPECTION_THREAD_START
:
70 fprintf(stderr
, "THREAD_START %p, self: %p, name: %s\n", thread
, self
, name
);
72 case PTHREAD_INTROSPECTION_THREAD_TERMINATE
:
73 fprintf(stderr
, "THREAD_TERMINATE %p, self: %p, name: %s\n", thread
, self
, name
);
75 case PTHREAD_INTROSPECTION_THREAD_DESTROY
:
76 fprintf(stderr
, "THREAD_DESTROY %p, self: %p, name: %s\n", thread
, self
, name
);
81 __attribute__((constructor
))
82 static void __library_initializer(void) {
83 fprintf(stderr
, "__library_initializer\n");
84 previous_pthread_hook
= pthread_introspection_hook_install(pthread_introspection_hook
);
87 #else // defined(SHARED_LIB)
89 void *Thread(void *a
) {
90 pthread_setname_np("child thread");
91 fprintf(stderr
, "Hello from pthread\n");
96 fprintf(stderr
, "main\n");
98 pthread_create(&t
, NULL
, Thread
, NULL
);
99 pthread_join(t
, NULL
);
100 fprintf(stderr
, "Done.\n");
102 #endif // defined(SHARED_LIB)
104 // CHECK: __library_initializer
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]]