diff options
Diffstat (limited to 'lib/libc/tests/stdlib/libc_exit_test.c')
-rw-r--r-- | lib/libc/tests/stdlib/libc_exit_test.c | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/lib/libc/tests/stdlib/libc_exit_test.c b/lib/libc/tests/stdlib/libc_exit_test.c new file mode 100644 index 000000000000..12965261bdb3 --- /dev/null +++ b/lib/libc/tests/stdlib/libc_exit_test.c @@ -0,0 +1,154 @@ +/*- + * Copyright (c) 2023 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/wait.h> + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <atf-c.h> + +static void +func_a(void) +{ + if (write(STDOUT_FILENO, "a", 1) != 1) + _Exit(1); +} + +static void +func_b(void) +{ + if (write(STDOUT_FILENO, "b", 1) != 1) + _Exit(1); +} + +static void +func_c(void) +{ + if (write(STDOUT_FILENO, "c", 1) != 1) + _Exit(1); +} + +static void +child(void) +{ + /* this will be received by the parent */ + printf("hello, "); + fflush(stdout); + /* this won't, because quick_exit() does not flush */ + printf("world"); + /* these will be called in reverse order, producing "abc" */ + if (at_quick_exit(func_c) != 0 || + at_quick_exit(func_b) != 0 || + at_quick_exit(func_a) != 0) + _Exit(1); + quick_exit(0); +} + +ATF_TC_WITHOUT_HEAD(quick_exit); +ATF_TC_BODY(quick_exit, tc) +{ + char buf[100] = ""; + ssize_t len; + int p[2], wstatus = 0; + pid_t pid; + + ATF_REQUIRE(pipe(p) == 0); + pid = fork(); + if (pid == 0) { + if (dup2(p[1], STDOUT_FILENO) < 0) + _Exit(1); + (void)close(p[1]); + (void)close(p[0]); + child(); + _Exit(1); + } + ATF_REQUIRE_MSG(pid > 0, + "expect fork() to succeed"); + ATF_CHECK_EQ_MSG(pid, waitpid(pid, &wstatus, 0), + "expect to collect child process"); + ATF_CHECK_EQ_MSG(0, wstatus, + "expect child to exit cleanly"); + ATF_CHECK_MSG((len = read(p[0], buf, sizeof(buf))) > 0, + "expect to receive output from child"); + ATF_CHECK_STREQ("hello, abc", buf); +} + +static void +myatexit1(void) +{ + exit(12); +} + +ATF_TC_WITHOUT_HEAD(recursive_exit1); +ATF_TC_BODY(recursive_exit1, tc) +{ + pid_t pid; + int wstatus; + + pid = fork(); + if (pid == 0) { + atexit(myatexit1); + exit(1); + } + ATF_REQUIRE_MSG(pid > 0, + "expect fork() to succeed"); + ATF_CHECK_EQ_MSG(pid, waitpid(pid, &wstatus, 0), + "expect to collect child process"); + ATF_CHECK(WIFEXITED(wstatus)); + ATF_CHECK_EQ(WEXITSTATUS(wstatus), 12); +} + +static pthread_barrier_t barrier; + +static void +myatexit2(void) +{ + pthread_barrier_wait(&barrier); + exit(12); +} + +static void * +mythreadexit(void *arg) +{ + pthread_barrier_wait(&barrier); + exit(15); +} + +ATF_TC_WITHOUT_HEAD(recursive_exit2); +ATF_TC_BODY(recursive_exit2, tc) +{ + pid_t pid; + int wstatus; + + pid = fork(); + if (pid == 0) { + pthread_t thr; + + atexit(myatexit2); + + pthread_barrier_init(&barrier, NULL, 2); + pthread_create(&thr, NULL, mythreadexit, NULL); + + exit(1); + } + ATF_REQUIRE_MSG(pid > 0, + "expect fork() to succeed"); + ATF_CHECK_EQ_MSG(pid, waitpid(pid, &wstatus, 0), + "expect to collect child process"); + ATF_CHECK(WIFEXITED(wstatus)); + ATF_CHECK_EQ(WEXITSTATUS(wstatus), 12); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, quick_exit); + ATF_TP_ADD_TC(tp, recursive_exit1); + ATF_TP_ADD_TC(tp, recursive_exit2); + return (atf_no_error()); +} |