| // Test StopTheWorld behavior during signal storm. |
| // Historically StopTheWorld crashed because did not handle EINTR properly. |
| // The test is somewhat convoluted, but that's what caused crashes previously. |
| |
| // RUN: %clangxx_asan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <signal.h> |
| #include <unistd.h> |
| #include <sys/types.h> |
| #include <sys/prctl.h> |
| #include <sys/wait.h> |
| #include <time.h> |
| #include <pthread.h> |
| #include <sanitizer/lsan_interface.h> |
| |
| static void handler(int signo); |
| static void *thr(void *arg); |
| |
| int main() { |
| struct sigaction act = {}; |
| act.sa_handler = handler; |
| sigaction(SIGPROF, &act, 0); |
| |
| pid_t pid = fork(); |
| if (pid < 0) { |
| fprintf(stderr, "failed to fork\n"); |
| exit(1); |
| } |
| if (pid == 0) { |
| // Child constantly sends signals to parent to cause spurious return from |
| // waitpid in StopTheWorld. |
| prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); |
| pid_t parent = getppid(); |
| for (;;) { |
| // There is no strong reason for these two particular signals, |
| // but at least one of them ought to unblock waitpid. |
| kill(parent, SIGCHLD); |
| kill(parent, SIGPROF); |
| } |
| } |
| usleep(10000); // Let the child start. |
| __lsan_do_leak_check(); |
| // Kill and join the child. |
| kill(pid, SIGTERM); |
| waitpid(pid, 0, 0); |
| sleep(1); // If the tracer thread still runs, give it time to crash. |
| fprintf(stderr, "DONE\n"); |
| // CHECK: DONE |
| } |
| |
| static void handler(int signo) { |
| } |
| |
| static void *thr(void *arg) { |
| for (;;) |
| sleep(1); |
| return 0; |
| } |