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