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