xref: /llvm-project/compiler-rt/test/msan/fork.cpp (revision 643a2080ec028bd7674206e0f97cbc7d0f132f99)
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