xref: /llvm-project/compiler-rt/test/tsan/Linux/dlopen_static_tls.cpp (revision fbe3f89bcf54cd8f674308d839a5a8f318915a8e)
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 
sofunc()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 
thread(void * arg)48 void *thread(void *arg) {
49   barrier_wait(&barrier);
50   if (__atomic_load_n(&ready, __ATOMIC_ACQUIRE))
51     func();
52   barrier_wait(&barrier);
53   if (dlclose(lib)) {
54     printf("error in dlclose: %s\n", dlerror());
55     exit(1);
56   }
57   return 0;
58 }
59 
main(int argc,char * argv[])60 int main(int argc, char *argv[]) {
61   barrier_init(&barrier, 2);
62   pthread_t th;
63   pthread_create(&th, 0, thread, 0);
64   lib = dlopen((std::string(argv[0]) + "-so.so").c_str(), RTLD_NOW);
65   if (lib == 0) {
66     printf("error in dlopen: %s\n", dlerror());
67     return 1;
68   }
69   func = (void (*)())dlsym(lib, "sofunc");
70   if (func == 0) {
71     printf("error in dlsym: %s\n", dlerror());
72     return 1;
73   }
74   __atomic_store_n(&ready, 1, __ATOMIC_RELEASE);
75   barrier_wait(&barrier);
76   func();
77   barrier_wait(&barrier);
78   pthread_join(th, 0);
79   fprintf(stderr, "DONE\n");
80   return 0;
81 }
82 
83 #endif // BUILD_SO
84 
85 // CHECK: DONE
86