xref: /llvm-project/compiler-rt/test/tsan/stack_sync_reuse.cpp (revision bcaeed49cb063de9fe504aa29e1cadff8a7be710)
1*bcaeed49SFangrui Song // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
2*bcaeed49SFangrui Song #include "test.h"
3*bcaeed49SFangrui Song 
4*bcaeed49SFangrui Song // Test case https://github.com/google/sanitizers/issues/494
5*bcaeed49SFangrui Song // Tsan sees false HB edge on address pointed to by syncp variable.
6*bcaeed49SFangrui Song // It is false because when acquire is done syncp points to a var in one frame,
7*bcaeed49SFangrui Song // and during release it points to a var in a different frame.
8*bcaeed49SFangrui Song // The code is somewhat tricky because it prevents compiler from optimizing
9*bcaeed49SFangrui Song // our accesses away, structured to not introduce other data races and
10*bcaeed49SFangrui Song // not introduce other synchronization, and to arrange the vars in different
11*bcaeed49SFangrui Song // frames to occupy the same address.
12*bcaeed49SFangrui Song 
13*bcaeed49SFangrui Song // The data race CHECK-NOT below actually must be CHECK, because the program
14*bcaeed49SFangrui Song // does contain the data race on global.
15*bcaeed49SFangrui Song 
16*bcaeed49SFangrui Song // CHECK-NOT: WARNING: ThreadSanitizer: data race
17*bcaeed49SFangrui Song // CHECK: DONE
18*bcaeed49SFangrui Song 
19*bcaeed49SFangrui Song long global;
20*bcaeed49SFangrui Song long *syncp;
21*bcaeed49SFangrui Song long *addr;
22*bcaeed49SFangrui Song long sink;
23*bcaeed49SFangrui Song 
Thread(void * x)24*bcaeed49SFangrui Song void *Thread(void *x) {
25*bcaeed49SFangrui Song   while (__atomic_load_n(&syncp, __ATOMIC_ACQUIRE) == 0)
26*bcaeed49SFangrui Song     usleep(1000);  // spin wait
27*bcaeed49SFangrui Song   global = 42;
28*bcaeed49SFangrui Song   __atomic_store_n(syncp, 1, __ATOMIC_RELEASE);
29*bcaeed49SFangrui Song   __atomic_store_n(&syncp, 0, __ATOMIC_RELAXED);
30*bcaeed49SFangrui Song   return NULL;
31*bcaeed49SFangrui Song }
32*bcaeed49SFangrui Song 
foobar()33*bcaeed49SFangrui Song void __attribute__((noinline)) foobar() {
34*bcaeed49SFangrui Song   __attribute__((aligned(64))) long s;
35*bcaeed49SFangrui Song 
36*bcaeed49SFangrui Song   addr = &s;
37*bcaeed49SFangrui Song   __atomic_store_n(&s, 0, __ATOMIC_RELAXED);
38*bcaeed49SFangrui Song   __atomic_store_n(&syncp, &s, __ATOMIC_RELEASE);
39*bcaeed49SFangrui Song   while (__atomic_load_n(&syncp, __ATOMIC_RELAXED) != 0)
40*bcaeed49SFangrui Song     usleep(1000);  // spin wait
41*bcaeed49SFangrui Song }
42*bcaeed49SFangrui Song 
barfoo()43*bcaeed49SFangrui Song void __attribute__((noinline)) barfoo() {
44*bcaeed49SFangrui Song   __attribute__((aligned(64))) long s;
45*bcaeed49SFangrui Song 
46*bcaeed49SFangrui Song   if (addr != &s) {
47*bcaeed49SFangrui Song     printf("address mismatch addr=%p &s=%p\n", addr, &s);
48*bcaeed49SFangrui Song     exit(1);
49*bcaeed49SFangrui Song   }
50*bcaeed49SFangrui Song   __atomic_store_n(&addr, &s, __ATOMIC_RELAXED);
51*bcaeed49SFangrui Song   __atomic_store_n(&s, 0, __ATOMIC_RELAXED);
52*bcaeed49SFangrui Song   sink = __atomic_load_n(&s, __ATOMIC_ACQUIRE);
53*bcaeed49SFangrui Song   global = 43;
54*bcaeed49SFangrui Song }
55*bcaeed49SFangrui Song 
main()56*bcaeed49SFangrui Song int main() {
57*bcaeed49SFangrui Song   pthread_t t;
58*bcaeed49SFangrui Song   pthread_create(&t, 0, Thread, 0);
59*bcaeed49SFangrui Song   foobar();
60*bcaeed49SFangrui Song   barfoo();
61*bcaeed49SFangrui Song   pthread_join(t, 0);
62*bcaeed49SFangrui Song   if (sink != 0)
63*bcaeed49SFangrui Song     exit(1);
64*bcaeed49SFangrui Song   fprintf(stderr, "DONE\n");
65*bcaeed49SFangrui Song   return 0;
66*bcaeed49SFangrui Song }
67*bcaeed49SFangrui Song 
68