1// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
2#include <pthread.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <stdint.h>
6#include <unistd.h>
7
8#define NOINLINE __attribute__((noinline))
9
10volatile uint64_t objs[8*2*(2 + 4 + 8)][2];
11
12extern "C" {
13uint16_t __sanitizer_unaligned_load16(volatile void *addr);
14uint32_t __sanitizer_unaligned_load32(volatile void *addr);
15uint64_t __sanitizer_unaligned_load64(volatile void *addr);
16void __sanitizer_unaligned_store16(volatile void *addr, uint16_t v);
17void __sanitizer_unaligned_store32(volatile void *addr, uint32_t v);
18void __sanitizer_unaligned_store64(volatile void *addr, uint64_t v);
19}
20
21// All this mess is to generate unique stack for each race,
22// otherwise tsan will suppress similar stacks.
23
24static NOINLINE void access(volatile char *p, int sz, int rw) {
25  if (rw) {
26    switch (sz) {
27    case 0: __sanitizer_unaligned_store16(p, 0); break;
28    case 1: __sanitizer_unaligned_store32(p, 0); break;
29    case 2: __sanitizer_unaligned_store64(p, 0); break;
30    default: exit(1);
31    }
32  } else {
33    switch (sz) {
34    case 0: __sanitizer_unaligned_load16(p); break;
35    case 1: __sanitizer_unaligned_load32(p); break;
36    case 2: __sanitizer_unaligned_load64(p); break;
37    default: exit(1);
38    }
39  }
40}
41
42static int accesssize(int sz) {
43  switch (sz) {
44  case 0: return 2;
45  case 1: return 4;
46  case 2: return 8;
47  }
48  exit(1);
49}
50
51template<int off, int off2>
52static NOINLINE void access3(bool main, int sz1, bool rw, volatile char *p) {
53  p += off;
54  if (main) {
55    access(p, sz1, true);
56  } else {
57    p += off2;
58    if (rw) {
59      *p = 42;
60    } else {
61       if (*p == 42)
62         printf("bingo!\n");
63    }
64  }
65}
66
67template<int off>
68static NOINLINE void
69access2(bool main, int sz1, int off2, bool rw, volatile char *obj) {
70  if (off2 == 0)
71    access3<off, 0>(main, sz1, rw, obj);
72  else if (off2 == 1)
73    access3<off, 1>(main, sz1, rw, obj);
74  else if (off2 == 2)
75    access3<off, 2>(main, sz1, rw, obj);
76  else if (off2 == 3)
77    access3<off, 3>(main, sz1, rw, obj);
78  else if (off2 == 4)
79    access3<off, 4>(main, sz1, rw, obj);
80  else if (off2 == 5)
81    access3<off, 5>(main, sz1, rw, obj);
82  else if (off2 == 6)
83    access3<off, 6>(main, sz1, rw, obj);
84  else if (off2 == 7)
85    access3<off, 7>(main, sz1, rw, obj);
86}
87
88static NOINLINE void
89access1(bool main, int off, int sz1, int off2, bool rw, char *obj) {
90  if (off == 0)
91    access2<0>(main, sz1, off2, rw, obj);
92  else if (off == 1)
93    access2<1>(main, sz1, off2, rw, obj);
94  else if (off == 2)
95    access2<2>(main, sz1, off2, rw, obj);
96  else if (off == 3)
97    access2<3>(main, sz1, off2, rw, obj);
98  else if (off == 4)
99    access2<4>(main, sz1, off2, rw, obj);
100  else if (off == 5)
101    access2<5>(main, sz1, off2, rw, obj);
102  else if (off == 6)
103    access2<6>(main, sz1, off2, rw, obj);
104  else if (off == 7)
105    access2<7>(main, sz1, off2, rw, obj);
106}
107
108NOINLINE void Test(bool main) {
109  volatile uint64_t *obj = objs[0];
110  for (int off = 0; off < 8; off++) {
111    for (int sz1 = 0; sz1 < 3; sz1++) {
112      for (int off2 = 0; off2 < accesssize(sz1); off2++) {
113        for (int rw = 0; rw < 2; rw++) {
114          // printf("thr=%d off=%d sz1=%d off2=%d rw=%d p=%p\n",
115          //        main, off, sz1, off2, rw, obj);
116          access1(main, off, sz1, off2, rw, (char*)obj);
117          obj += 2;
118        }
119      }
120    }
121  }
122}
123
124void *Thread(void *p) {
125  (void)p;
126  sleep(1);
127  Test(false);
128  return 0;
129}
130
131int main() {
132  pthread_t th;
133  pthread_create(&th, 0, Thread, 0);
134  Test(true);
135  pthread_join(th, 0);
136}
137
138// CHECK: WARNING: ThreadSanitizer: data race
139// CHECK: ThreadSanitizer: reported 224 warnings
140