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// 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
32int done;
33
34void 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
45void copy_uninit_thread1(int level) {
46 if (!level)
47 copy_uninit_thread2();
48 else
49 copy_uninit_thread1(level: level - 1);
50}
51
52void *copy_uninit_thread(void *id) {
53 copy_uninit_thread1(level: (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.
59void 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(fd: 2, buf: "done\n", n: 5);
67}
68
69void test() {
70 const int kThreads = 10;
71 pthread_t t[kThreads];
72 for (int i = 0; i < kThreads; ++i)
73 pthread_create(newthread: &t[i], NULL, start_routine: copy_uninit_thread, arg: (void*)(long)i);
74 usleep(useconds: 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
87int 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(status: 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

source code of compiler-rt/test/msan/fork.cpp