1 /* Tests that Valgrind retains control over blocked signals.
2 If synchronous signals (SIGSEGV) would be blocked, kernel would
3 simply kill the process. When operating properly, Valgrind involves
4 its synchronous signal handler and reports on the signal delivery.
5
6 Valgrind and libc all retain their sigmasks and lie to us politely
7 about what the actual sigmask is. One of reliable tests is to fork
8 another process (because libc thinks it blocks all signals before fork
9 and the forked process inherits the sigmask) and try to SIGSEGV it.
10 */
11
12 #include <assert.h>
13 #include <errno.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <sys/wait.h>
18
main(void)19 int main(void)
20 {
21 pid_t pid = fork();
22 if (pid < 0) {
23 perror("fork");
24 exit(1);
25 } else if (pid == 0) {
26 /* Causes SIGSEGV. */
27 char *s = NULL;
28 s[0] = 1;
29 } else {
30 pid_t ret;
31 int status;
32
33 while ((ret = waitpid(pid, &status, 0)) != pid) {
34 if (errno != EINTR) {
35 perror("waitpid");
36 exit(1);
37 }
38 }
39
40 if (WIFSIGNALED(status)) {
41 assert(WTERMSIG(status) != 0);
42
43 if (WTERMSIG(status) == SIGSEGV) {
44 printf("PASS\n");
45 } else {
46 fprintf(stderr, "Child process died with unexpected signal %d.\n",
47 WTERMSIG(status));
48 }
49 } else if (WIFEXITED(status)) {
50 if (WEXITSTATUS(status) == 0) {
51 fprintf(stderr, "Child process exited without expected SIGSEGV "
52 "signal.\n");
53 } else {
54 fprintf(stderr, "Child process exited with unexpected status %d.\n",
55 WEXITSTATUS(status));
56 }
57 } else {
58 fprintf(stderr, "Unrecognized status of child proces %x?\n", status);
59 }
60 }
61
62 return 0;
63 }
64
65