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