1// RUN: %clang -O0 %s -o %t && %env_tool_opts=die_after_fork=0 %run %t
2
3// The test uses pthread barriers which are not available on Darwin.
4// UNSUPPORTED: darwin
5
6// FIXME: It probably hangs on this platform.
7// UNSUPPORTED: ppc
8
9// FIXME: TSAN does not lock allocator.
10// UNSUPPORTED: tsan
11
12// FIXME: False stack overflow report
13// UNSUPPORTED: android && asan
14
15// FIXME: Requires `FutexWait` implementation. See __asan::InstallAtForkHandler.
16// UNSUPPORTED: target={{.*solaris.*}}
17// UNSUPPORTED: target={{.*netbsd.*}}
18// UNSUPPORTED: target={{.*apple.*}}
19
20// Forking in multithread environment is unsupported. However we already have
21// some workarounds, and will add more, so this is the test.
22// The test try to check two things:
23// 1. Internal mutexes used by `inparent` thread do not deadlock `inchild`
24// thread.
25// 2. Stack poisoned by `inparent` is not poisoned in `inchild` thread.
26
27#include <assert.h>
28#include <pthread.h>
29#include <stdint.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <sys/types.h>
33#include <sys/wait.h>
34#include <unistd.h>
35
36#include "sanitizer_common/sanitizer_specific.h"
37
38static const size_t kBufferSize = 8192;
39
40pthread_barrier_t bar;
41
42// Without appropriate workarounds this code can cause the forked process to
43// start with locked internal mutexes.
44void ShouldNotDeadlock() {
45 // Don't bother with leaks, we try to trigger allocator or lsan deadlock.
46 __lsan_disable();
47 void *volatile p = malloc(size: 10);
48 __lsan_do_recoverable_leak_check();
49 // Allocator still in broken state, `free` may report errors.
50 // free(p);
51 __lsan_enable();
52}
53
54// Prevent stack buffer cleanup by instrumentation.
55#define NOSAN __attribute__((no_sanitize("address", "hwaddress", "memory")))
56
57NOSAN static void *inparent(void *arg) {
58 char t[kBufferSize];
59 make_mem_bad(t, sizeof(t));
60
61 pthread_barrier_wait(barrier: &bar);
62
63 for (;;)
64 ShouldNotDeadlock();
65
66 return 0;
67}
68
69NOSAN static void *inchild(void *arg) {
70 char t[kBufferSize];
71 check_mem_is_good(t, sizeof(t));
72 ShouldNotDeadlock();
73 return 0;
74}
75
76int main(void) {
77#if __has_feature(hwaddress_sanitizer)
78 __hwasan_enable_allocator_tagging();
79#endif
80
81 pid_t pid;
82
83 pthread_barrier_init(barrier: &bar, NULL, count: 2);
84 pthread_t thread_id;
85 while (pthread_create(newthread: &thread_id, attr: 0, start_routine: &inparent, arg: 0) != 0) {
86 }
87 pthread_barrier_wait(barrier: &bar);
88
89 pid = fork();
90 switch (pid) {
91 case -1:
92 perror(s: "fork");
93 return -1;
94 case 0:
95 ShouldNotDeadlock();
96 while (pthread_create(newthread: &thread_id, attr: 0, start_routine: &inchild, arg: 0) != 0) {
97 }
98 pthread_join(th: thread_id, NULL);
99 _exit(status: 0);
100 break;
101 default: {
102 int status;
103 pid_t child = waitpid(pid: pid, stat_loc: &status, /*options=*/0);
104 assert(pid == child);
105 assert(WIFEXITED(status));
106 assert(WEXITSTATUS(status) == 0);
107 break;
108 }
109 }
110
111 return 0;
112}
113

source code of compiler-rt/test/sanitizer_common/TestCases/Posix/fork_threaded.c