Home | History | Annotate | Download | only in tsan
      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