| /* 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; |
| } |
| |