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