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 
7 volatile 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 
access(volatile void * p,int sz,int rw)12 static 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 
accesssize(int sz)30 static 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 
39 template<int off, int off2>
access3(bool main,int sz1,bool rw,volatile char * p)40 static 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 
55 template<int off>
56 static NOINLINE void
access2(bool main,int sz1,int off2,bool rw,volatile char * obj)57 access2(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 
76 static NOINLINE void
access1(bool main,int off,int sz1,int off2,bool rw,char * obj)77 access1(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 
Test(bool main)96 NOINLINE 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 
Thread(void * p)112 void *Thread(void *p) {
113   (void)p;
114   barrier_wait(&barrier);
115   Test(false);
116   return 0;
117 }
118 
main()119 int 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