diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp --- a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp @@ -138,6 +138,8 @@ creation_stack_id = CurrentStackId(args->thr, args->pc); } +extern "C" void __tsan_stack_initialization() {} + struct OnStartedArgs { ThreadState *thr; uptr stk_addr; @@ -173,9 +175,15 @@ #endif #if !SANITIZER_GO + // Don't imitate stack/TLS writes for the main thread, + // because its initialization is synchronized with all + // subsequent threads anyway. if (tid != kMainTid) { - if (stk_addr && stk_size) - MemoryRangeImitateWrite(thr, /*pc=*/1, stk_addr, stk_size); + if (stk_addr && stk_size) { + const uptr pc = StackTrace::GetNextInstructionPc( + reinterpret_cast(__tsan_stack_initialization)); + MemoryRangeImitateWrite(thr, pc, stk_addr, stk_size); + } if (tls_addr && tls_size) ImitateTlsWrite(thr, tls_addr, tls_size); diff --git a/compiler-rt/test/tsan/stack_race3.cpp b/compiler-rt/test/tsan/stack_race3.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/tsan/stack_race3.cpp @@ -0,0 +1,34 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s + +// Race with initial stack initialization: +// there is no explicit second write, +// but the stack variable is published unsafely. +#include "test.h" + +long *P; + +void *Thread(void *a) { + long X; + __atomic_store_n(&P, &X, __ATOMIC_RELAXED); + barrier_wait(&barrier); + barrier_wait(&barrier); + return 0; +} + +int main() { + barrier_init(&barrier, 2); + pthread_t t; + pthread_create(&t, NULL, Thread, NULL); + barrier_wait(&barrier); + long *p = __atomic_load_n(&P, __ATOMIC_RELAXED); + *p = 42; + barrier_wait(&barrier); + pthread_join(t, 0); +} + +// CHECK: WARNING: ThreadSanitizer: data race +// CHECK: Write of size 8 at {{.*}} by main thread: +// CHECK: #0 main +// CHECK: Previous write of size 8 at {{.*}} by thread T1: +// CHECK: #0 __tsan_stack_initialization +// CHECK: Location is stack of thread T1