1 | // RUN: %clangxx_tsan -O1 %s -DBUILD_SO -fPIC -shared -o %t-so.so |
2 | // RUN: %clangxx_tsan -O1 %s %link_libcxx_tsan -o %t && %run %t 2>&1 | FileCheck %s |
3 | |
4 | // A test for loading a dynamic library with static TLS. |
5 | // Such static TLS is a hack that allows a dynamic library to have faster TLS, |
6 | // but it can be loaded only iff all threads happened to allocate some excess |
7 | // of static TLS space for whatever reason. If it's not the case loading fails with: |
8 | // dlopen: cannot load any more object with static TLS |
9 | // We used to produce a false positive because dlopen will write into TLS |
10 | // of all existing threads to initialize/zero TLS region for the loaded library. |
11 | // And this appears to be racing with initialization of TLS in the thread |
12 | // since we model a write into the whole static TLS region (we don't know what part |
13 | // of it is currently unused): |
14 | // WARNING: ThreadSanitizer: data race (pid=2317365) |
15 | // Write of size 1 at 0x7f1fa9bfcdd7 by main thread: |
16 | // #0 memset |
17 | // #1 init_one_static_tls |
18 | // #2 __pthread_init_static_tls |
19 | // [[ this is where main calls dlopen ]] |
20 | // #3 main |
21 | // Previous write of size 8 at 0x7f1fa9bfcdd0 by thread T1: |
22 | // #0 __tsan_tls_initialization |
23 | |
24 | // Failing on bots: |
25 | // https://lab.llvm.org/buildbot#builders/184/builds/1580 |
26 | // https://lab.llvm.org/buildbot#builders/18/builds/3167 |
27 | // UNSUPPORTED: target={{(aarch64|powerpc64).*}} |
28 | |
29 | #ifdef BUILD_SO |
30 | |
31 | __attribute__((tls_model("initial-exec" ))) __thread char x = 42; |
32 | __attribute__((tls_model("initial-exec" ))) __thread char y; |
33 | |
34 | extern "C" int sofunc() { return ++x + ++y; } |
35 | |
36 | #else // BUILD_SO |
37 | |
38 | # include "../test.h" |
39 | # include <dlfcn.h> |
40 | # include <string> |
41 | |
42 | __thread int x[1023]; |
43 | |
44 | void *lib; |
45 | void (*func)(); |
46 | int ready; |
47 | |
48 | void *thread(void *arg) { |
49 | barrier_wait(barrier: &barrier); |
50 | if (__atomic_load_n(&ready, __ATOMIC_ACQUIRE)) |
51 | func(); |
52 | barrier_wait(barrier: &barrier); |
53 | if (dlclose(handle: lib)) { |
54 | printf(format: "error in dlclose: %s\n" , dlerror()); |
55 | exit(status: 1); |
56 | } |
57 | return 0; |
58 | } |
59 | |
60 | int main(int argc, char *argv[]) { |
61 | barrier_init(barrier: &barrier, count: 2); |
62 | pthread_t th; |
63 | pthread_create(newthread: &th, attr: 0, start_routine: thread, arg: 0); |
64 | lib = dlopen((std::string(argv[0]) + "-so.so" ).c_str(), RTLD_NOW); |
65 | if (lib == 0) { |
66 | printf(format: "error in dlopen: %s\n" , dlerror()); |
67 | return 1; |
68 | } |
69 | func = (void (*)())dlsym(handle: lib, name: "sofunc" ); |
70 | if (func == 0) { |
71 | printf(format: "error in dlsym: %s\n" , dlerror()); |
72 | return 1; |
73 | } |
74 | __atomic_store_n(&ready, 1, __ATOMIC_RELEASE); |
75 | barrier_wait(barrier: &barrier); |
76 | func(); |
77 | barrier_wait(barrier: &barrier); |
78 | pthread_join(th: th, thread_return: 0); |
79 | fprintf(stderr, format: "DONE\n" ); |
80 | return 0; |
81 | } |
82 | |
83 | #endif // BUILD_SO |
84 | |
85 | // CHECK: DONE |
86 | |