git: c7dd4601aeeb - main - libc: Add a rudimentary test for quick_exit(3).

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Tue, 26 Sep 2023 20:26:34 UTC
The branch main has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=c7dd4601aeebbc1bbe131cbe6747476c124b47fe

commit c7dd4601aeebbc1bbe131cbe6747476c124b47fe
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2023-09-26 20:07:03 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2023-09-26 20:07:10 +0000

    libc: Add a rudimentary test for quick_exit(3).
    
    Sponsored by:   Klara, Inc.
    Reviewed by:    kib
    Differential Revision:  https://reviews.freebsd.org/D41937
---
 lib/libc/tests/stdlib/Makefile          |  1 +
 lib/libc/tests/stdlib/quick_exit_test.c | 81 +++++++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+)

diff --git a/lib/libc/tests/stdlib/Makefile b/lib/libc/tests/stdlib/Makefile
index a2a6420aba41..860e530389df 100644
--- a/lib/libc/tests/stdlib/Makefile
+++ b/lib/libc/tests/stdlib/Makefile
@@ -12,6 +12,7 @@ ATF_TESTS_C+=		qsort_b_test
 ATF_TESTS_C+=		qsort_r_compat_test
 ATF_TESTS_C+=		qsort_r_test
 ATF_TESTS_C+=		qsort_s_test
+ATF_TESTS_C+=		quick_exit_test
 ATF_TESTS_C+=		set_constraint_handler_s_test
 ATF_TESTS_C+=		strfmon_test
 ATF_TESTS_C+=		tsearch_test
diff --git a/lib/libc/tests/stdlib/quick_exit_test.c b/lib/libc/tests/stdlib/quick_exit_test.c
new file mode 100644
index 000000000000..9feed8a6fa63
--- /dev/null
+++ b/lib/libc/tests/stdlib/quick_exit_test.c
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 2023 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/wait.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);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+	ATF_TP_ADD_TC(tp, quick_exit);
+	return (atf_no_error());
+}