/* Tests that Valgrind retains control over blocked signals. If synchronous signals (SIGSEGV) would be blocked, kernel would simply kill the process. When operating properly, Valgrind involves its synchronous signal handler and reports on the signal delivery. Valgrind and libc all retain their sigmasks and lie to us politely about what the actual sigmask is. One of reliable tests is to fork another process (because libc thinks it blocks all signals before fork and the forked process inherits the sigmask) and try to SIGSEGV it. */ #include <assert.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> int main(void) { pid_t pid = fork(); if (pid < 0) { perror("fork"); exit(1); } else if (pid == 0) { /* Causes SIGSEGV. */ char *s = NULL; s[0] = 1; } else { pid_t ret; int status; while ((ret = waitpid(pid, &status, 0)) != pid) { if (errno != EINTR) { perror("waitpid"); exit(1); } } if (WIFSIGNALED(status)) { assert(WTERMSIG(status) != 0); if (WTERMSIG(status) == SIGSEGV) { printf("PASS\n"); } else { fprintf(stderr, "Child process died with unexpected signal %d.\n", WTERMSIG(status)); } } else if (WIFEXITED(status)) { if (WEXITSTATUS(status) == 0) { fprintf(stderr, "Child process exited without expected SIGSEGV " "signal.\n"); } else { fprintf(stderr, "Child process exited with unexpected status %d.\n", WEXITSTATUS(status)); } } else { fprintf(stderr, "Unrecognized status of child proces %x?\n", status); } } return 0; }