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
18static void handler(int signo);
19static void *thr(void *arg);
20
21int 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
53static void handler(int signo) {
54}
55
56static void *thr(void *arg) {
57 for (;;)
58 sleep(seconds: 1);
59 return 0;
60}
61

source code of compiler-rt/test/lsan/TestCases/Linux/signal_during_stop_the_world.cpp