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