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