xref: /xnu-11417.121.6/tests/exec-race-58566604.c (revision a1e26a70f38d1d7daa7b49b258e2f8538ad81650)
1*a1e26a70SApple OSS Distributions #include <assert.h>
2*a1e26a70SApple OSS Distributions #include <stdio.h>
3*a1e26a70SApple OSS Distributions #include <pthread.h>
4*a1e26a70SApple OSS Distributions #include <signal.h>
5*a1e26a70SApple OSS Distributions #include <unistd.h>
6*a1e26a70SApple OSS Distributions #include <errno.h>
7*a1e26a70SApple OSS Distributions #include <string.h>
8*a1e26a70SApple OSS Distributions #include <sys/wait.h>
9*a1e26a70SApple OSS Distributions 
10*a1e26a70SApple OSS Distributions #include <darwintest.h>
11*a1e26a70SApple OSS Distributions 
12*a1e26a70SApple OSS Distributions // rdar://58566604
13*a1e26a70SApple OSS Distributions // Exercise races of signal delivery vs exec in multi-threaded processes
14*a1e26a70SApple OSS Distributions 
15*a1e26a70SApple OSS Distributions T_GLOBAL_META(T_META_NAMESPACE("xnu.exec"),
16*a1e26a70SApple OSS Distributions     T_META_CHECK_LEAKS(false),
17*a1e26a70SApple OSS Distributions     T_META_ALL_VALID_ARCHS(true));
18*a1e26a70SApple OSS Distributions 
19*a1e26a70SApple OSS Distributions enum { KILL_ONCE, KILL_MANY, KILL_LAST } kill_mode;
20*a1e26a70SApple OSS Distributions enum { EXEC_FIRST, EXEC_SECOND, EXEC_LAST } exec_mode;
21*a1e26a70SApple OSS Distributions 
22*a1e26a70SApple OSS Distributions static int fd[2];
23*a1e26a70SApple OSS Distributions 
24*a1e26a70SApple OSS Distributions static void
do_exec(void)25*a1e26a70SApple OSS Distributions do_exec(void)
26*a1e26a70SApple OSS Distributions {
27*a1e26a70SApple OSS Distributions 	char echo_arg[50] = "";
28*a1e26a70SApple OSS Distributions 
29*a1e26a70SApple OSS Distributions 	snprintf(echo_arg, sizeof(echo_arg), "            Child[%d] says hello after exec", getpid());
30*a1e26a70SApple OSS Distributions 
31*a1e26a70SApple OSS Distributions 	char * new_argv[] = {
32*a1e26a70SApple OSS Distributions 		"/bin/echo",
33*a1e26a70SApple OSS Distributions 		echo_arg,
34*a1e26a70SApple OSS Distributions 		NULL
35*a1e26a70SApple OSS Distributions 	};
36*a1e26a70SApple OSS Distributions 
37*a1e26a70SApple OSS Distributions 	int ret = execv(new_argv[0], new_argv);
38*a1e26a70SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "execv()");
39*a1e26a70SApple OSS Distributions }
40*a1e26a70SApple OSS Distributions 
41*a1e26a70SApple OSS Distributions static void*
thread_main(void * arg)42*a1e26a70SApple OSS Distributions thread_main(void* arg)
43*a1e26a70SApple OSS Distributions {
44*a1e26a70SApple OSS Distributions 	T_LOG("mode: %d, %d: Child[%d] created second thread\n",
45*a1e26a70SApple OSS Distributions 	    kill_mode, exec_mode, getpid());
46*a1e26a70SApple OSS Distributions 
47*a1e26a70SApple OSS Distributions 	if (exec_mode == EXEC_SECOND) {
48*a1e26a70SApple OSS Distributions 		int ret = dprintf(fd[1], "Hi!");
49*a1e26a70SApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "dprintf()");
50*a1e26a70SApple OSS Distributions 		do_exec();
51*a1e26a70SApple OSS Distributions 	}
52*a1e26a70SApple OSS Distributions 
53*a1e26a70SApple OSS Distributions 	while (1) {
54*a1e26a70SApple OSS Distributions 	}
55*a1e26a70SApple OSS Distributions 	return NULL;
56*a1e26a70SApple OSS Distributions }
57*a1e26a70SApple OSS Distributions 
58*a1e26a70SApple OSS Distributions void
run_test(void)59*a1e26a70SApple OSS Distributions run_test(void)
60*a1e26a70SApple OSS Distributions {
61*a1e26a70SApple OSS Distributions 	T_LOG("mode: %d, %d: Parent[%d]: forking\n",
62*a1e26a70SApple OSS Distributions 	    kill_mode, exec_mode, getpid());
63*a1e26a70SApple OSS Distributions 
64*a1e26a70SApple OSS Distributions 	pid_t child_pid = fork();
65*a1e26a70SApple OSS Distributions 
66*a1e26a70SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(child_pid, "fork()");
67*a1e26a70SApple OSS Distributions 
68*a1e26a70SApple OSS Distributions 	int ret = 0;
69*a1e26a70SApple OSS Distributions 	errno = 0;
70*a1e26a70SApple OSS Distributions 
71*a1e26a70SApple OSS Distributions 	if (child_pid == 0) {
72*a1e26a70SApple OSS Distributions 		pthread_t thread;
73*a1e26a70SApple OSS Distributions 		ret = pthread_create(&thread, NULL, thread_main, NULL);
74*a1e26a70SApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "pthread_create()");
75*a1e26a70SApple OSS Distributions 
76*a1e26a70SApple OSS Distributions 		if (exec_mode == EXEC_FIRST) {
77*a1e26a70SApple OSS Distributions 			ret = dprintf(fd[1], "Hi!");
78*a1e26a70SApple OSS Distributions 			T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "dprintf()");
79*a1e26a70SApple OSS Distributions 
80*a1e26a70SApple OSS Distributions 			do_exec();
81*a1e26a70SApple OSS Distributions 		}
82*a1e26a70SApple OSS Distributions 
83*a1e26a70SApple OSS Distributions 		while (1) {
84*a1e26a70SApple OSS Distributions 		}
85*a1e26a70SApple OSS Distributions 	} else {
86*a1e26a70SApple OSS Distributions 		char buffer[4] = "";
87*a1e26a70SApple OSS Distributions 		ret = read(fd[0], buffer, sizeof(buffer));
88*a1e26a70SApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "read()");
89*a1e26a70SApple OSS Distributions 
90*a1e26a70SApple OSS Distributions 		T_LOG("mode: %d, %d: Parent[%d]: got: '%s' from execing child, trying to kill and wait\n",
91*a1e26a70SApple OSS Distributions 		    kill_mode, exec_mode, getpid(), buffer);
92*a1e26a70SApple OSS Distributions 
93*a1e26a70SApple OSS Distributions 		int killcount = 0, status = 0, waitedpid = 0;
94*a1e26a70SApple OSS Distributions 
95*a1e26a70SApple OSS Distributions 		switch (kill_mode) {
96*a1e26a70SApple OSS Distributions 		case KILL_ONCE:
97*a1e26a70SApple OSS Distributions 			ret = kill(child_pid, SIGKILL);
98*a1e26a70SApple OSS Distributions 			T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "kill()");
99*a1e26a70SApple OSS Distributions 
100*a1e26a70SApple OSS Distributions 			waitedpid = waitpid(child_pid, &status, 0);
101*a1e26a70SApple OSS Distributions 
102*a1e26a70SApple OSS Distributions 			T_QUIET; T_ASSERT_POSIX_SUCCESS(waitedpid, "waitpid()");
103*a1e26a70SApple OSS Distributions 
104*a1e26a70SApple OSS Distributions 			killcount++;
105*a1e26a70SApple OSS Distributions 			break;
106*a1e26a70SApple OSS Distributions 		case KILL_MANY:
107*a1e26a70SApple OSS Distributions 			while (waitedpid == 0) {
108*a1e26a70SApple OSS Distributions 				ret = kill(child_pid, SIGKILL);
109*a1e26a70SApple OSS Distributions 				T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "kill()");
110*a1e26a70SApple OSS Distributions 
111*a1e26a70SApple OSS Distributions 				waitedpid = waitpid(child_pid, &status, WNOHANG);
112*a1e26a70SApple OSS Distributions 				T_QUIET; T_ASSERT_POSIX_SUCCESS(waitedpid, "waitpid()");
113*a1e26a70SApple OSS Distributions 
114*a1e26a70SApple OSS Distributions 				killcount++;
115*a1e26a70SApple OSS Distributions 			}
116*a1e26a70SApple OSS Distributions 			break;
117*a1e26a70SApple OSS Distributions 		default:
118*a1e26a70SApple OSS Distributions 			break;
119*a1e26a70SApple OSS Distributions 		}
120*a1e26a70SApple OSS Distributions 
121*a1e26a70SApple OSS Distributions 		T_LOG("mode: %d, %d: Parent[%d]: waitpid returned: %d, errno %d (%s), exit signal %d, after %d loops\n",
122*a1e26a70SApple OSS Distributions 		    kill_mode, exec_mode, getpid(), waitedpid, errno, strerror(errno), WTERMSIG(status), killcount);
123*a1e26a70SApple OSS Distributions 	}
124*a1e26a70SApple OSS Distributions }
125*a1e26a70SApple OSS Distributions 
126*a1e26a70SApple OSS Distributions T_DECL(exec_exit_race_once_first, "Exec-exit race, one kill, exec on first thread") {
127*a1e26a70SApple OSS Distributions 	int rv = pipe(fd);
128*a1e26a70SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pipe()");
129*a1e26a70SApple OSS Distributions 
130*a1e26a70SApple OSS Distributions 	kill_mode = KILL_ONCE;
131*a1e26a70SApple OSS Distributions 	exec_mode = EXEC_FIRST;
132*a1e26a70SApple OSS Distributions 
133*a1e26a70SApple OSS Distributions 	for (int i = 0; i < 1000; i++) {
134*a1e26a70SApple OSS Distributions 		run_test();
135*a1e26a70SApple OSS Distributions 	}
136*a1e26a70SApple OSS Distributions }
137*a1e26a70SApple OSS Distributions 
138*a1e26a70SApple OSS Distributions T_DECL(exec_exit_race_many_first, "Exec-exit race, many kill, exec on first thread") {
139*a1e26a70SApple OSS Distributions 	int rv = pipe(fd);
140*a1e26a70SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pipe()");
141*a1e26a70SApple OSS Distributions 
142*a1e26a70SApple OSS Distributions 	kill_mode = KILL_MANY;
143*a1e26a70SApple OSS Distributions 	exec_mode = EXEC_FIRST;
144*a1e26a70SApple OSS Distributions 
145*a1e26a70SApple OSS Distributions 	for (int i = 0; i < 1000; i++) {
146*a1e26a70SApple OSS Distributions 		run_test();
147*a1e26a70SApple OSS Distributions 	}
148*a1e26a70SApple OSS Distributions }
149*a1e26a70SApple OSS Distributions 
150*a1e26a70SApple OSS Distributions T_DECL(exec_exit_race_once_second, "Exec-exit race, one kill, exec on second thread") {
151*a1e26a70SApple OSS Distributions 	int rv = pipe(fd);
152*a1e26a70SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pipe()");
153*a1e26a70SApple OSS Distributions 
154*a1e26a70SApple OSS Distributions 	kill_mode = KILL_ONCE;
155*a1e26a70SApple OSS Distributions 	exec_mode = EXEC_SECOND;
156*a1e26a70SApple OSS Distributions 
157*a1e26a70SApple OSS Distributions 	for (int i = 0; i < 1000; i++) {
158*a1e26a70SApple OSS Distributions 		run_test();
159*a1e26a70SApple OSS Distributions 	}
160*a1e26a70SApple OSS Distributions }
161*a1e26a70SApple OSS Distributions 
162*a1e26a70SApple OSS Distributions T_DECL(exec_exit_race_many_second, "Exec-exit race, many kill, exec on second thread") {
163*a1e26a70SApple OSS Distributions 	int rv = pipe(fd);
164*a1e26a70SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pipe()");
165*a1e26a70SApple OSS Distributions 
166*a1e26a70SApple OSS Distributions 	kill_mode = KILL_MANY;
167*a1e26a70SApple OSS Distributions 	exec_mode = EXEC_SECOND;
168*a1e26a70SApple OSS Distributions 
169*a1e26a70SApple OSS Distributions 	for (int i = 0; i < 1000; i++) {
170*a1e26a70SApple OSS Distributions 		run_test();
171*a1e26a70SApple OSS Distributions 	}
172*a1e26a70SApple OSS Distributions }
173