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
10static const struct sockaddr sa;
11
12int 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