1 | // REQUIRES: asan-64-bits |
2 | // UNSUPPORTED: android |
3 | // Stress test dynamic TLS + dlopen + threads. |
4 | // |
5 | // Note that glibc 2.15 seems utterly broken on this test, |
6 | // it fails with ~17 DSOs dlopen-ed. |
7 | // glibc 2.19 seems fine. |
8 | // |
9 | // |
10 | // RUN: %clangxx_asan -x c -DSO_NAME=f0 %s -shared -o %t-f0.so -fPIC |
11 | // RUN: %clangxx_asan -x c -DSO_NAME=f1 %s -shared -o %t-f1.so -fPIC |
12 | // RUN: %clangxx_asan -x c -DSO_NAME=f2 %s -shared -o %t-f2.so -fPIC |
13 | // RUN: %clangxx_asan %s -ldl -pthread -o %t |
14 | // RUN: %run %t 0 3 |
15 | // RUN: %run %t 2 3 |
16 | // RUN: %env_asan_opts=verbosity=2 %run %t 10 2 2>&1 | FileCheck %s |
17 | // RUN: %env_asan_opts=verbosity=2:intercept_tls_get_addr=1 %run %t 10 2 2>&1 | FileCheck %s |
18 | // RUN: %env_asan_opts=verbosity=2:intercept_tls_get_addr=0 %run %t 10 2 2>&1 | FileCheck %s --check-prefix=CHECK0 |
19 | // CHECK: __tls_get_addr |
20 | // CHECK: Creating thread 0 |
21 | // CHECK: __tls_get_addr |
22 | // CHECK: Creating thread 1 |
23 | // CHECK: __tls_get_addr |
24 | // CHECK: Creating thread 2 |
25 | // CHECK: __tls_get_addr |
26 | // CHECK: Creating thread 3 |
27 | // CHECK: __tls_get_addr |
28 | // Make sure that TLS slots don't leak |
29 | // CHECK-NOT: num_live_dtls 5 |
30 | // |
31 | // CHECK0-NOT: __tls_get_addr |
32 | /* |
33 | cc=your-compiler |
34 | |
35 | $cc stress_dtls.c -pthread -ldl |
36 | for((i=0;i<100;i++)); do |
37 | $cc -fPIC -shared -DSO_NAME=f$i -o a.out-f$i.so stress_dtls.c; |
38 | done |
39 | ./a.out 2 4 # <<<<<< 2 threads, 4 libs |
40 | ./a.out 3 50 # <<<<<< 3 threads, 50 libs |
41 | */ |
42 | #ifndef SO_NAME |
43 | #define _GNU_SOURCE |
44 | #include <assert.h> |
45 | #include <dlfcn.h> |
46 | #include <stdio.h> |
47 | #include <stdlib.h> |
48 | #include <pthread.h> |
49 | #include <stdint.h> |
50 | |
51 | typedef void **(*f_t)(); |
52 | |
53 | __thread int my_tls; |
54 | |
55 | #define MAX_N_FUNCTIONS 1000 |
56 | f_t Functions[MAX_N_FUNCTIONS]; |
57 | |
58 | void *PrintStuff(void *unused) { |
59 | uintptr_t stack; |
60 | // fprintf(stderr, "STACK: %p TLS: %p SELF: %p\n", &stack, &my_tls, |
61 | // (void *)pthread_self()); |
62 | int i; |
63 | for (i = 0; i < MAX_N_FUNCTIONS; i++) { |
64 | if (!Functions[i]) break; |
65 | uintptr_t dtls = (uintptr_t)Functions[i](); |
66 | fprintf(stderr, format: " dtls[%03d]: %lx\n" , i, dtls); |
67 | *(long*)dtls = 42; // check that this is writable. |
68 | } |
69 | return NULL; |
70 | } |
71 | |
72 | int main(int argc, char *argv[]) { |
73 | int num_threads = 1; |
74 | int num_libs = 1; |
75 | if (argc >= 2) |
76 | num_threads = atoi(nptr: argv[1]); |
77 | if (argc >= 3) |
78 | num_libs = atoi(nptr: argv[2]); |
79 | assert(num_libs <= MAX_N_FUNCTIONS); |
80 | |
81 | int lib; |
82 | for (lib = 0; lib < num_libs; lib++) { |
83 | char buf[4096]; |
84 | snprintf(s: buf, maxlen: sizeof(buf), format: "%s-f%d.so" , argv[0], lib); |
85 | void *handle = dlopen(file: buf, RTLD_LAZY); |
86 | if (!handle) { |
87 | fprintf(stderr, format: "%s\n" , dlerror()); |
88 | exit(status: 1); |
89 | } |
90 | snprintf(s: buf, maxlen: sizeof(buf), format: "f%d" , lib); |
91 | Functions[lib] = (f_t)dlsym(handle: handle, name: buf); |
92 | if (!Functions[lib]) { |
93 | fprintf(stderr, format: "%s\n" , dlerror()); |
94 | exit(status: 1); |
95 | } |
96 | fprintf(stderr, format: "LIB[%03d] %s: %p\n" , lib, buf, Functions[lib]); |
97 | PrintStuff(unused: 0); |
98 | |
99 | int i; |
100 | for (i = 0; i < num_threads; i++) { |
101 | pthread_t t; |
102 | fprintf(stderr, format: "Creating thread %d\n" , i); |
103 | pthread_create(newthread: &t, attr: 0, start_routine: PrintStuff, arg: 0); |
104 | pthread_join(th: t, thread_return: 0); |
105 | } |
106 | } |
107 | return 0; |
108 | } |
109 | #else // SO_NAME |
110 | #ifndef DTLS_SIZE |
111 | # define DTLS_SIZE (1 << 17) |
112 | #endif |
113 | __thread void *huge_thread_local_array[DTLS_SIZE]; |
114 | void **SO_NAME() { |
115 | return &huge_thread_local_array[0]; |
116 | } |
117 | #endif |
118 | |