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