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