xref: /llvm-project/compiler-rt/test/lsan/TestCases/Linux/signal_during_stop_the_world.cpp (revision f05731434589284116cbf79be7c5571af9558405)
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 
main()21 int main() {
22   struct sigaction act = {};
23   act.sa_handler = handler;
24   sigaction(SIGPROF, &act, 0);
25 
26   pid_t pid = fork();
27   if (pid < 0) {
28     fprintf(stderr, "failed to fork\n");
29     exit(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(parent, SIGCHLD);
40       kill(parent, SIGPROF);
41     }
42   }
43   usleep(10000);  // Let the child start.
44   __lsan_do_leak_check();
45   // Kill and join the child.
46   kill(pid, SIGTERM);
47   waitpid(pid, 0, 0);
48   sleep(1);  // If the tracer thread still runs, give it time to crash.
49   fprintf(stderr, "DONE\n");
50 // CHECK: DONE
51 }
52 
handler(int signo)53 static void handler(int signo) {
54 }
55 
thr(void * arg)56 static void *thr(void *arg) {
57   for (;;)
58     sleep(1);
59   return 0;
60 }
61