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