1 #include <stdlib.h> 2 #include <stddef.h> 3 #include <unistd.h> 4 #include <signal.h> 5 #include <sys/types.h> 6 #include <sys/socket.h> 7 #include <stdio.h> 8 #include <sys/wait.h> 9 10 static const struct sockaddr sa; 11 12 int main(int argc, char *argv[]) 13 { 14 int loops; 15 int pid; 16 sigset_t set; 17 18 printf( 19 "Please run me under 'strace -f -oLOG', and examine LOG file for incorrect\n" 20 "decoding of interrupted syscalls: grep for 'sendto', '??" /* anti-trigraph gap */ "?', 'unavailable'.\n" 21 "Pass number of iterations in argv[1] (default: 999).\n" 22 ); 23 fflush(NULL); 24 25 sigemptyset(&set); 26 sigaddset(&set, SIGCHLD); 27 sigprocmask(SIG_BLOCK, &set, NULL); 28 29 loops = 999; 30 if (argv[1]) 31 loops = atoi(argv[1]); 32 33 while (--loops >= 0) { 34 pid = fork(); 35 36 if (pid < 0) 37 exit(1); 38 39 if (!pid) { 40 /* child */ 41 int child = getpid(); 42 43 loops = 99; 44 while (--loops) { 45 pid = fork(); 46 47 if (pid < 0) 48 exit(1); 49 50 if (!pid) { 51 /* grandchild: kill child */ 52 kill(child, SIGKILL); 53 exit(0); 54 } 55 56 /* Add various syscalls you want to test here. 57 * strace will decode them and suddenly find 58 * process disappearing. 59 * But leave at least one case "empty", so that 60 * "kill grandchild" happens quicker. 61 * This produces cases when strace can't even 62 * decode syscall number before process dies. 63 */ 64 switch (loops & 1) { 65 case 0: 66 break; /* intentionally empty */ 67 case 1: 68 sendto(-1, "Hello cruel world", 17, 0, &sa, sizeof(sa)); 69 break; 70 } 71 72 /* kill grandchild */ 73 kill(pid, SIGKILL); 74 } 75 76 exit(0); 77 } 78 79 /* parent */ 80 wait(NULL); 81 } 82 83 return 0; 84 } 85