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
34extern "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
44void *lib;
45void (*func)();
46int ready;
47
48void *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
60int 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

source code of compiler-rt/test/tsan/Linux/dlopen_static_tls.cpp