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 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