Home | History | Annotate | Download | only in msan
      1 // Test that chained origins are fork-safe.
      2 // Run a number of threads that create new chained origins, then fork
      3 // and verify that origin reads do not deadlock in the child process.
      4 
      5 // RUN: %clangxx_msan -std=c++11 -fsanitize-memory-track-origins=2 -g -O3 %s -o %t
      6 // RUN: MSAN_OPTIONS=store_context_size=1000,origin_history_size=0,origin_history_per_stack_limit=0 %run %t |& FileCheck %s
      7 
      8 // Fun fact: if test output is redirected to a file (as opposed to
      9 // being piped directly to FileCheck), we may lose some "done"s due to
     10 // a kernel bug:
     11 // https://lkml.org/lkml/2014/2/17/324
     12 
     13 
     14 #include <pthread.h>
     15 #include <unistd.h>
     16 #include <stdio.h>
     17 #include <stdlib.h>
     18 #include <sys/types.h>
     19 #include <sys/wait.h>
     20 #include <sys/time.h>
     21 #include <signal.h>
     22 #include <errno.h>
     23 
     24 #include <sanitizer/msan_interface.h>
     25 
     26 int done;
     27 
     28 void copy_uninit_thread2() {
     29   volatile int x;
     30   volatile int v;
     31   while (true) {
     32     v = x;
     33     x = v;
     34     if (__atomic_load_n(&done, __ATOMIC_RELAXED))
     35       return;
     36   }
     37 }
     38 
     39 void copy_uninit_thread1(int level) {
     40   if (!level)
     41     copy_uninit_thread2();
     42   else
     43     copy_uninit_thread1(level - 1);
     44 }
     45 
     46 void *copy_uninit_thread(void *id) {
     47   copy_uninit_thread1((long)id);
     48   return 0;
     49 }
     50 
     51 // Run through stackdepot in the child process.
     52 // If any of the hash table cells are locked, this may deadlock.
     53 void child() {
     54   volatile int x;
     55   volatile int v;
     56   for (int i = 0; i < 10000; ++i) {
     57     v = x;
     58     x = v;
     59   }
     60   write(2, "done\n", 5);
     61 }
     62 
     63 void test() {
     64   const int kThreads = 10;
     65   pthread_t t[kThreads];
     66   for (int i = 0; i < kThreads; ++i)
     67     pthread_create(&t[i], NULL, copy_uninit_thread, (void*)(long)i);
     68   usleep(100000);
     69   pid_t pid = fork();
     70   if (pid) {
     71     // parent
     72     __atomic_store_n(&done, 1, __ATOMIC_RELAXED);
     73     pid_t p;
     74     while ((p = wait(NULL)) == -1) {  }
     75   } else {
     76     // child
     77     child();
     78   }
     79 }
     80 
     81 int main() {
     82   const int kChildren = 20;
     83   for (int i = 0; i < kChildren; ++i) {
     84     pid_t pid = fork();
     85     if (pid) {
     86       // parent
     87     } else {
     88       test();
     89       exit(0);
     90     }
     91   }
     92 
     93   for (int i = 0; i < kChildren; ++i) {
     94     pid_t p;
     95     while ((p = wait(NULL)) == -1) {  }
     96   }
     97 
     98   return 0;
     99 }
    100 
    101 // Expect 20 (== kChildren) "done" messages.
    102 // CHECK: done
    103 // CHECK: done
    104 // CHECK: done
    105 // CHECK: done
    106 // CHECK: done
    107 // CHECK: done
    108 // CHECK: done
    109 // CHECK: done
    110 // CHECK: done
    111 // CHECK: done
    112 // CHECK: done
    113 // CHECK: done
    114 // CHECK: done
    115 // CHECK: done
    116 // CHECK: done
    117 // CHECK: done
    118 // CHECK: done
    119 // CHECK: done
    120 // CHECK: done
    121 // CHECK: done
    122