1 | // Test StopTheWorld behavior during signal storm. |
2 | // Historically StopTheWorld crashed because did not handle EINTR properly. |
3 | // The test is somewhat convoluted, but that's what caused crashes previously. |
4 | |
5 | // RUN: %clangxx_lsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s |
6 | |
7 | #include <stdio.h> |
8 | #include <stdlib.h> |
9 | #include <signal.h> |
10 | #include <unistd.h> |
11 | #include <sys/types.h> |
12 | #include <sys/prctl.h> |
13 | #include <sys/wait.h> |
14 | #include <time.h> |
15 | #include <pthread.h> |
16 | #include <sanitizer/lsan_interface.h> |
17 | |
18 | static void handler(int signo); |
19 | static void *thr(void *arg); |
20 | |
21 | int main() { |
22 | struct sigaction act = {}; |
23 | act.sa_handler = handler; |
24 | sigaction(SIGPROF, act: &act, oact: 0); |
25 | |
26 | pid_t pid = fork(); |
27 | if (pid < 0) { |
28 | fprintf(stderr, format: "failed to fork\n" ); |
29 | exit(status: 1); |
30 | } |
31 | if (pid == 0) { |
32 | // Child constantly sends signals to parent to cause spurious return from |
33 | // waitpid in StopTheWorld. |
34 | prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); |
35 | pid_t parent = getppid(); |
36 | for (;;) { |
37 | // There is no strong reason for these two particular signals, |
38 | // but at least one of them ought to unblock waitpid. |
39 | kill(pid: parent, SIGCHLD); |
40 | kill(pid: parent, SIGPROF); |
41 | } |
42 | } |
43 | usleep(useconds: 10000); // Let the child start. |
44 | __lsan_do_leak_check(); |
45 | // Kill and join the child. |
46 | kill(pid: pid, SIGTERM); |
47 | waitpid(pid: pid, stat_loc: 0, options: 0); |
48 | sleep(seconds: 1); // If the tracer thread still runs, give it time to crash. |
49 | fprintf(stderr, format: "DONE\n" ); |
50 | // CHECK: DONE |
51 | } |
52 | |
53 | static void handler(int signo) { |
54 | } |
55 | |
56 | static void *thr(void *arg) { |
57 | for (;;) |
58 | sleep(seconds: 1); |
59 | return 0; |
60 | } |
61 | |