Skip to content

Commit 6d8fe3d

Browse files
authored
[sanitizer] Pre-commit disabled test for fork (llvm#75257)
1 parent aa217eb commit 6d8fe3d

File tree

2 files changed

+107
-1
lines changed

2 files changed

+107
-1
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// RUN: %clangxx -O0 %s -o %t && %env_tool_opts=die_after_fork=0 %run %t
2+
3+
// UNSUPPORTED: asan, hwasan, lsan, msan, tsan, ubsan
4+
5+
// Forking in multithread environment is unsupported. However we already have
6+
// some workarounds, and will add more, so this is the test.
7+
// The test try to check two things:
8+
// 1. Internal mutexes used by `inparent` thread do not deadlock `inchild`
9+
// thread.
10+
// 2. Stack poisoned by `inparent` is not poisoned in `inchild` thread.
11+
12+
#include <assert.h>
13+
#include <pthread.h>
14+
#include <stdint.h>
15+
#include <stdio.h>
16+
#include <stdlib.h>
17+
#include <sys/types.h>
18+
#include <sys/wait.h>
19+
#include <unistd.h>
20+
21+
#include "sanitizer_common/sanitizer_specific.h"
22+
23+
static const size_t kBufferSize = 1 << 20;
24+
25+
pthread_barrier_t bar;
26+
27+
// Without appropriate workarounds this code can cause the forked process to
28+
// start with locked internal mutexes.
29+
void ShouldNotDeadlock() {
30+
// Don't bother with leaks, we try to trigger allocator or lsan deadlock.
31+
__lsan::ScopedDisabler disable;
32+
char *volatile p = new char[10];
33+
__lsan_do_recoverable_leak_check();
34+
delete[] p;
35+
}
36+
37+
// Prevent stack buffer cleanup by instrumentation.
38+
#define NOSAN __attribute__((no_sanitize("address", "hwaddress", "memory")))
39+
40+
NOSAN static void *inparent(void *arg) {
41+
fprintf(stderr, "inparent %d\n", gettid());
42+
43+
char t[kBufferSize];
44+
make_mem_bad(t, sizeof(t));
45+
46+
pthread_barrier_wait(&bar);
47+
48+
for (;;)
49+
ShouldNotDeadlock();
50+
51+
return 0;
52+
}
53+
54+
NOSAN static void *inchild(void *arg) {
55+
char t[kBufferSize];
56+
check_mem_is_good(t, sizeof(t));
57+
ShouldNotDeadlock();
58+
return 0;
59+
}
60+
61+
int main(void) {
62+
pid_t pid;
63+
64+
pthread_barrier_init(&bar, nullptr, 2);
65+
pthread_t thread_id;
66+
while (pthread_create(&thread_id, 0, &inparent, 0) != 0) {
67+
}
68+
pthread_barrier_wait(&bar);
69+
70+
pid = fork();
71+
switch (pid) {
72+
case -1:
73+
perror("fork");
74+
return -1;
75+
case 0:
76+
while (pthread_create(&thread_id, 0, &inchild, 0) != 0) {
77+
}
78+
break;
79+
default: {
80+
fprintf(stderr, "fork %d\n", pid);
81+
int status;
82+
while (waitpid(-1, &status, __WALL) != pid) {
83+
}
84+
assert(WIFEXITED(status) && WEXITSTATUS(status) == 0);
85+
break;
86+
}
87+
}
88+
89+
return 0;
90+
}

compiler-rt/test/sanitizer_common/sanitizer_specific.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
#ifndef __SANITIZER_COMMON_SANITIZER_SPECIFIC_H__
22
#define __SANITIZER_COMMON_SANITIZER_SPECIFIC_H__
33

4+
#include <sanitizer/lsan_interface.h>
5+
6+
__attribute__((weak)) int __lsan_do_recoverable_leak_check() { return 0; }
7+
__attribute__((weak)) void __lsan_disable(void) {}
8+
__attribute__((weak)) void __lsan_enable(void) {}
9+
410
#ifndef __has_feature
511
# define __has_feature(x) 0
612
#endif
@@ -10,15 +16,25 @@
1016
static void check_mem_is_good(void *p, size_t s) {
1117
__msan_check_mem_is_initialized(p, s);
1218
}
19+
static void make_mem_good(void *p, size_t s) { __msan_unpoison(p, s); }
20+
static void make_mem_bad(void *p, size_t s) { __msan_poison(p, s); }
1321
#elif __has_feature(address_sanitizer)
1422
# include <sanitizer/asan_interface.h>
1523
# include <stdlib.h>
1624
static void check_mem_is_good(void *p, size_t s) {
1725
if (__asan_region_is_poisoned(p, s))
1826
abort();
1927
}
28+
static void make_mem_good(void *p, size_t s) {
29+
__asan_unpoison_memory_region(p, s);
30+
}
31+
static void make_mem_bad(void *p, size_t s) {
32+
__asan_poison_memory_region(p, s);
33+
}
2034
#else
2135
static void check_mem_is_good(void *p, size_t s) {}
36+
static void make_mem_good(void *p, size_t s) {}
37+
static void make_mem_bad(void *p, size_t s) {}
2238
#endif
2339

24-
#endif // __SANITIZER_COMMON_SANITIZER_SPECIFIC_H__
40+
#endif // __SANITIZER_COMMON_SANITIZER_SPECIFIC_H__

0 commit comments

Comments
 (0)