// RUN: %clangxx_tsan -O1 %s -DBUILD_SO -fPIC -shared -o %t-so.so // RUN: %clangxx_tsan -O1 %s %link_libcxx_tsan -o %t && %run %t 2>&1 | FileCheck %s // A test for loading a dynamic library with static TLS. // Such static TLS is a hack that allows a dynamic library to have faster TLS, // but it can be loaded only iff all threads happened to allocate some excess // of static TLS space for whatever reason. If it's not the case loading fails with: // dlopen: cannot load any more object with static TLS // We used to produce a false positive because dlopen will write into TLS // of all existing threads to initialize/zero TLS region for the loaded library. // And this appears to be racing with initialization of TLS in the thread // since we model a write into the whole static TLS region (we don't know what part // of it is currently unused): // WARNING: ThreadSanitizer: data race (pid=2317365) // Write of size 1 at 0x7f1fa9bfcdd7 by main thread: // #0 memset // #1 init_one_static_tls // #2 __pthread_init_static_tls // [[ this is where main calls dlopen ]] // #3 main // Previous write of size 8 at 0x7f1fa9bfcdd0 by thread T1: // #0 __tsan_tls_initialization // Failing on bots: // https://lab.llvm.org/buildbot#builders/184/builds/1580 // https://lab.llvm.org/buildbot#builders/18/builds/3167 // UNSUPPORTED: target={{(aarch64|powerpc64).*}} #ifdef BUILD_SO __attribute__((tls_model("initial-exec"))) __thread char x = 42; __attribute__((tls_model("initial-exec"))) __thread char y; extern "C" int sofunc() { return ++x + ++y; } #else // BUILD_SO # include "../test.h" # include # include __thread int x[1023]; void *lib; void (*func)(); int ready; void *thread(void *arg) { barrier_wait(&barrier); if (__atomic_load_n(&ready, __ATOMIC_ACQUIRE)) func(); barrier_wait(&barrier); if (dlclose(lib)) { printf("error in dlclose: %s\n", dlerror()); exit(1); } return 0; } int main(int argc, char *argv[]) { barrier_init(&barrier, 2); pthread_t th; pthread_create(&th, 0, thread, 0); lib = dlopen((std::string(argv[0]) + "-so.so").c_str(), RTLD_NOW); if (lib == 0) { printf("error in dlopen: %s\n", dlerror()); return 1; } func = (void (*)())dlsym(lib, "sofunc"); if (func == 0) { printf("error in dlsym: %s\n", dlerror()); return 1; } __atomic_store_n(&ready, 1, __ATOMIC_RELEASE); barrier_wait(&barrier); func(); barrier_wait(&barrier); pthread_join(th, 0); fprintf(stderr, "DONE\n"); return 0; } #endif // BUILD_SO // CHECK: DONE