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