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