• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
copy_uninit_thread2()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 
copy_uninit_thread1(int level)39 void copy_uninit_thread1(int level) {
40   if (!level)
41     copy_uninit_thread2();
42   else
43     copy_uninit_thread1(level - 1);
44 }
45 
copy_uninit_thread(void * id)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.
child()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 
test()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 
main()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