xref: /freebsd/lib/libc/tests/stdlib/libc_exit_test.c (revision c0946aee5b2ab6c9bb2e8281a1f625914ed2fec8)
15132e16eSMark Johnston /*-
25132e16eSMark Johnston  * Copyright (c) 2023 Klara, Inc.
35132e16eSMark Johnston  *
45132e16eSMark Johnston  * SPDX-License-Identifier: BSD-2-Clause
55132e16eSMark Johnston  */
65132e16eSMark Johnston 
75132e16eSMark Johnston #include <sys/wait.h>
85132e16eSMark Johnston 
9*c0946aeeSMark Johnston #include <pthread.h>
105132e16eSMark Johnston #include <stdio.h>
115132e16eSMark Johnston #include <stdlib.h>
125132e16eSMark Johnston #include <unistd.h>
135132e16eSMark Johnston 
145132e16eSMark Johnston #include <atf-c.h>
155132e16eSMark Johnston 
165132e16eSMark Johnston static void
func_a(void)175132e16eSMark Johnston func_a(void)
185132e16eSMark Johnston {
195132e16eSMark Johnston 	if (write(STDOUT_FILENO, "a", 1) != 1)
205132e16eSMark Johnston 		_Exit(1);
215132e16eSMark Johnston }
225132e16eSMark Johnston 
235132e16eSMark Johnston static void
func_b(void)245132e16eSMark Johnston func_b(void)
255132e16eSMark Johnston {
265132e16eSMark Johnston 	if (write(STDOUT_FILENO, "b", 1) != 1)
275132e16eSMark Johnston 		_Exit(1);
285132e16eSMark Johnston }
295132e16eSMark Johnston 
305132e16eSMark Johnston static void
func_c(void)315132e16eSMark Johnston func_c(void)
325132e16eSMark Johnston {
335132e16eSMark Johnston 	if (write(STDOUT_FILENO, "c", 1) != 1)
345132e16eSMark Johnston 		_Exit(1);
355132e16eSMark Johnston }
365132e16eSMark Johnston 
375132e16eSMark Johnston static void
child(void)385132e16eSMark Johnston child(void)
395132e16eSMark Johnston {
405132e16eSMark Johnston 	/* this will be received by the parent */
415132e16eSMark Johnston 	printf("hello, ");
425132e16eSMark Johnston 	fflush(stdout);
435132e16eSMark Johnston 	/* this won't, because quick_exit() does not flush */
445132e16eSMark Johnston 	printf("world");
455132e16eSMark Johnston 	/* these will be called in reverse order, producing "abc" */
465132e16eSMark Johnston 	if (at_quick_exit(func_c) != 0 ||
475132e16eSMark Johnston 	    at_quick_exit(func_b) != 0 ||
485132e16eSMark Johnston 	    at_quick_exit(func_a) != 0)
495132e16eSMark Johnston 		_Exit(1);
505132e16eSMark Johnston 	quick_exit(0);
515132e16eSMark Johnston }
525132e16eSMark Johnston 
535132e16eSMark Johnston ATF_TC_WITHOUT_HEAD(quick_exit);
ATF_TC_BODY(quick_exit,tc)545132e16eSMark Johnston ATF_TC_BODY(quick_exit, tc)
555132e16eSMark Johnston {
565132e16eSMark Johnston 	char buf[100] = "";
575132e16eSMark Johnston 	ssize_t len;
585132e16eSMark Johnston 	int p[2], wstatus = 0;
595132e16eSMark Johnston 	pid_t pid;
605132e16eSMark Johnston 
615132e16eSMark Johnston 	ATF_REQUIRE(pipe(p) == 0);
625132e16eSMark Johnston 	pid = fork();
635132e16eSMark Johnston 	if (pid == 0) {
645132e16eSMark Johnston 		if (dup2(p[1], STDOUT_FILENO) < 0)
655132e16eSMark Johnston 			_Exit(1);
665132e16eSMark Johnston 		(void)close(p[1]);
675132e16eSMark Johnston 		(void)close(p[0]);
685132e16eSMark Johnston 		child();
695132e16eSMark Johnston 		_Exit(1);
705132e16eSMark Johnston 	}
715132e16eSMark Johnston 	ATF_REQUIRE_MSG(pid > 0,
725132e16eSMark Johnston 	    "expect fork() to succeed");
735132e16eSMark Johnston 	ATF_CHECK_EQ_MSG(pid, waitpid(pid, &wstatus, 0),
745132e16eSMark Johnston 	    "expect to collect child process");
755132e16eSMark Johnston 	ATF_CHECK_EQ_MSG(0, wstatus,
765132e16eSMark Johnston 	    "expect child to exit cleanly");
775132e16eSMark Johnston 	ATF_CHECK_MSG((len = read(p[0], buf, sizeof(buf))) > 0,
785132e16eSMark Johnston 	    "expect to receive output from child");
795132e16eSMark Johnston 	ATF_CHECK_STREQ("hello, abc", buf);
805132e16eSMark Johnston }
815132e16eSMark Johnston 
82*c0946aeeSMark Johnston static void
myatexit1(void)83*c0946aeeSMark Johnston myatexit1(void)
84*c0946aeeSMark Johnston {
85*c0946aeeSMark Johnston 	exit(12);
86*c0946aeeSMark Johnston }
87*c0946aeeSMark Johnston 
88*c0946aeeSMark Johnston ATF_TC_WITHOUT_HEAD(recursive_exit1);
ATF_TC_BODY(recursive_exit1,tc)89*c0946aeeSMark Johnston ATF_TC_BODY(recursive_exit1, tc)
90*c0946aeeSMark Johnston {
91*c0946aeeSMark Johnston 	pid_t pid;
92*c0946aeeSMark Johnston 	int wstatus;
93*c0946aeeSMark Johnston 
94*c0946aeeSMark Johnston 	pid = fork();
95*c0946aeeSMark Johnston 	if (pid == 0) {
96*c0946aeeSMark Johnston 		atexit(myatexit1);
97*c0946aeeSMark Johnston 		exit(1);
98*c0946aeeSMark Johnston 	}
99*c0946aeeSMark Johnston 	ATF_REQUIRE_MSG(pid > 0,
100*c0946aeeSMark Johnston 	    "expect fork() to succeed");
101*c0946aeeSMark Johnston 	ATF_CHECK_EQ_MSG(pid, waitpid(pid, &wstatus, 0),
102*c0946aeeSMark Johnston 	    "expect to collect child process");
103*c0946aeeSMark Johnston 	ATF_CHECK(WIFEXITED(wstatus));
104*c0946aeeSMark Johnston 	ATF_CHECK_EQ(WEXITSTATUS(wstatus), 12);
105*c0946aeeSMark Johnston }
106*c0946aeeSMark Johnston 
107*c0946aeeSMark Johnston static pthread_barrier_t barrier;
108*c0946aeeSMark Johnston 
109*c0946aeeSMark Johnston static void
myatexit2(void)110*c0946aeeSMark Johnston myatexit2(void)
111*c0946aeeSMark Johnston {
112*c0946aeeSMark Johnston 	pthread_barrier_wait(&barrier);
113*c0946aeeSMark Johnston 	exit(12);
114*c0946aeeSMark Johnston }
115*c0946aeeSMark Johnston 
116*c0946aeeSMark Johnston static void *
mythreadexit(void * arg)117*c0946aeeSMark Johnston mythreadexit(void *arg)
118*c0946aeeSMark Johnston {
119*c0946aeeSMark Johnston 	pthread_barrier_wait(&barrier);
120*c0946aeeSMark Johnston 	exit(15);
121*c0946aeeSMark Johnston }
122*c0946aeeSMark Johnston 
123*c0946aeeSMark Johnston ATF_TC_WITHOUT_HEAD(recursive_exit2);
ATF_TC_BODY(recursive_exit2,tc)124*c0946aeeSMark Johnston ATF_TC_BODY(recursive_exit2, tc)
125*c0946aeeSMark Johnston {
126*c0946aeeSMark Johnston 	pid_t pid;
127*c0946aeeSMark Johnston 	int wstatus;
128*c0946aeeSMark Johnston 
129*c0946aeeSMark Johnston 	pid = fork();
130*c0946aeeSMark Johnston 	if (pid == 0) {
131*c0946aeeSMark Johnston 		pthread_t thr;
132*c0946aeeSMark Johnston 
133*c0946aeeSMark Johnston 		atexit(myatexit2);
134*c0946aeeSMark Johnston 
135*c0946aeeSMark Johnston 		pthread_barrier_init(&barrier, NULL, 2);
136*c0946aeeSMark Johnston 		pthread_create(&thr, NULL, mythreadexit, NULL);
137*c0946aeeSMark Johnston 
138*c0946aeeSMark Johnston 		exit(1);
139*c0946aeeSMark Johnston 	}
140*c0946aeeSMark Johnston 	ATF_REQUIRE_MSG(pid > 0,
141*c0946aeeSMark Johnston 	    "expect fork() to succeed");
142*c0946aeeSMark Johnston 	ATF_CHECK_EQ_MSG(pid, waitpid(pid, &wstatus, 0),
143*c0946aeeSMark Johnston 	    "expect to collect child process");
144*c0946aeeSMark Johnston 	ATF_CHECK(WIFEXITED(wstatus));
145*c0946aeeSMark Johnston 	ATF_CHECK_EQ(WEXITSTATUS(wstatus), 12);
146*c0946aeeSMark Johnston }
147*c0946aeeSMark Johnston 
ATF_TP_ADD_TCS(tp)1485132e16eSMark Johnston ATF_TP_ADD_TCS(tp)
1495132e16eSMark Johnston {
1505132e16eSMark Johnston 	ATF_TP_ADD_TC(tp, quick_exit);
151*c0946aeeSMark Johnston 	ATF_TP_ADD_TC(tp, recursive_exit1);
152*c0946aeeSMark Johnston 	ATF_TP_ADD_TC(tp, recursive_exit2);
1535132e16eSMark Johnston 	return (atf_no_error());
1545132e16eSMark Johnston }
155