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: env MSAN_OPTIONS=store_context_size=1000,origin_history_size=0,origin_history_per_stack_limit=0 %run %t 2>&1 | 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 // Flaky on PPC64. 14 // UNSUPPORTED: powerpc64-target-arch 15 // UNSUPPORTED: powerpc64le-target-arch 16 17 // Sometimes hangs 18 // UNSUPPORTED: target={{.*netbsd.*}} 19 20 #include <pthread.h> 21 #include <unistd.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <sys/types.h> 25 #include <sys/wait.h> 26 #include <sys/time.h> 27 #include <signal.h> 28 #include <errno.h> 29 30 #include <sanitizer/msan_interface.h> 31 32 int done; 33 34 void copy_uninit_thread2() { 35 volatile int x; 36 volatile int v; 37 while (true) { 38 v = x; 39 x = v; 40 if (__atomic_load_n(&done, __ATOMIC_RELAXED)) 41 return; 42 } 43 } 44 45 void copy_uninit_thread1(int level) { 46 if (!level) 47 copy_uninit_thread2(); 48 else 49 copy_uninit_thread1(level - 1); 50 } 51 52 void *copy_uninit_thread(void *id) { 53 copy_uninit_thread1((long)id); 54 return 0; 55 } 56 57 // Run through stackdepot in the child process. 58 // If any of the hash table cells are locked, this may deadlock. 59 void child() { 60 volatile int x; 61 volatile int v; 62 for (int i = 0; i < 10000; ++i) { 63 v = x; 64 x = v; 65 } 66 write(2, "done\n", 5); 67 } 68 69 void test() { 70 const int kThreads = 10; 71 pthread_t t[kThreads]; 72 for (int i = 0; i < kThreads; ++i) 73 pthread_create(&t[i], NULL, copy_uninit_thread, (void*)(long)i); 74 usleep(100000); 75 pid_t pid = fork(); 76 if (pid) { 77 // parent 78 __atomic_store_n(&done, 1, __ATOMIC_RELAXED); 79 pid_t p; 80 while ((p = wait(NULL)) == -1) { } 81 } else { 82 // child 83 child(); 84 } 85 } 86 87 int main() { 88 const int kChildren = 20; 89 for (int i = 0; i < kChildren; ++i) { 90 pid_t pid = fork(); 91 if (pid) { 92 // parent 93 } else { 94 test(); 95 exit(0); 96 } 97 } 98 99 for (int i = 0; i < kChildren; ++i) { 100 pid_t p; 101 while ((p = wait(NULL)) == -1) { } 102 } 103 104 return 0; 105 } 106 107 // Expect 20 (== kChildren) "done" messages. 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 // CHECK: done 123 // CHECK: done 124 // CHECK: done 125 // CHECK: done 126 // CHECK: done 127 // CHECK: done 128