Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 04 Mar 2026 14:45:07 +0000
From:      Dag-Erling=?utf-8?Q? Sm=C3=B8rg?=rav <des@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 3d7774db9319 - stable/15 - system(3): Write our own tests
Message-ID:  <69a84573.26c19.1b828c6f@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch stable/15 has been updated by des:

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

commit 3d7774db931939f17d5ad54245735e4223061525
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2026-02-25 21:12:29 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2026-03-04 14:45:00 +0000

    system(3): Write our own tests
    
    Replace the somewhat perfunctory NetBSD tests with our own.
    
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Reviewed by:    bnovkov, kevans
    Differential Revision:  https://reviews.freebsd.org/D55482
    
    (cherry picked from commit 7a1ade5109ac57d1f59eaa75b5d0f13fabecf6ba)
---
 lib/libc/tests/stdlib/Makefile      |   3 +-
 lib/libc/tests/stdlib/system_test.c | 164 ++++++++++++++++++++++++++++++++++++
 2 files changed, 166 insertions(+), 1 deletion(-)

diff --git a/lib/libc/tests/stdlib/Makefile b/lib/libc/tests/stdlib/Makefile
index 9d84becfbd1f..a714a8cab774 100644
--- a/lib/libc/tests/stdlib/Makefile
+++ b/lib/libc/tests/stdlib/Makefile
@@ -17,6 +17,7 @@ ATF_TESTS_C+=		qsort_s_test
 ATF_TESTS_C+=		qsort_bench
 ATF_TESTS_C+=		set_constraint_handler_s_test
 ATF_TESTS_C+=		strfmon_test
+ATF_TESTS_C+=		system_test
 ATF_TESTS_C+=		tsearch_test
 ATF_TESTS_CXX+=		cxa_thread_atexit_test
 ATF_TESTS_CXX+=		cxa_thread_atexit_nothr_test
@@ -44,7 +45,6 @@ NETBSD_ATF_TESTS_C+=	posix_memalign_test
 NETBSD_ATF_TESTS_C+=	random_test
 NETBSD_ATF_TESTS_C+=	strtod_test
 NETBSD_ATF_TESTS_C+=	strtol_test
-NETBSD_ATF_TESTS_C+=	system_test
 
 # TODO: need to come up with a correct explanation of what the patch pho does
 # with h_atexit
@@ -78,6 +78,7 @@ LIBADD.${t}+=	netbsd util
 
 LIBADD.libc_exit_test+=		pthread
 LIBADD.strtod_test+=		m
+LIBADD.system_test+=		pthread
 
 SUBDIR+=	dynthr_mod
 SUBDIR+=	libatexit
diff --git a/lib/libc/tests/stdlib/system_test.c b/lib/libc/tests/stdlib/system_test.c
new file mode 100644
index 000000000000..713e4bb0f87a
--- /dev/null
+++ b/lib/libc/tests/stdlib/system_test.c
@@ -0,0 +1,164 @@
+/*-
+ * Copyright (c) 2026 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+ATF_TC(system_true);
+ATF_TC_HEAD(system_true, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "system(\"true\")");
+}
+ATF_TC_BODY(system_true, tc)
+{
+	ATF_REQUIRE_EQ(W_EXITCODE(0, 0), system("true"));
+}
+
+ATF_TC(system_false);
+ATF_TC_HEAD(system_false, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "system(\"false\")");
+}
+ATF_TC_BODY(system_false, tc)
+{
+	ATF_REQUIRE_EQ(W_EXITCODE(1, 0), system("false"));
+}
+
+ATF_TC(system_touch);
+ATF_TC_HEAD(system_touch, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "system(\"touch file\")");
+}
+ATF_TC_BODY(system_touch, tc)
+{
+	/* The file does not exist */
+	ATF_CHECK_ERRNO(ENOENT, unlink("file"));
+
+	/* Run a command that creates it */
+	ATF_REQUIRE_EQ(W_EXITCODE(0, 0), system("touch file"));
+
+	/* Now the file exists */
+	ATF_CHECK_EQ(0, unlink("file"));
+}
+
+ATF_TC(system_null);
+ATF_TC_HEAD(system_null, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "system(NULL)");
+}
+ATF_TC_BODY(system_null, tc)
+{
+	ATF_REQUIRE_EQ(1, system(NULL));
+}
+
+/*
+ * Define PROCMASK_IS_THREADMASK if sigprocmask() gets / sets the thread
+ * mask in multithreaded programs, which makes it impossible to verify
+ * that system(3) correctly blocks and unblocks SIGCHLD.
+ */
+#ifdef __FreeBSD__
+#define PROCMASK_IS_THREADMASK 1
+#endif
+
+static void *
+system_thread(void *arg)
+{
+	char cmd[64];
+	int i = (int)(intptr_t)arg;
+
+	snprintf(cmd, sizeof(cmd), "rm flag%d ; lockf -ns lock%d true", i, i);
+	return ((void *)(intptr_t)system(cmd));
+}
+
+ATF_TC(system_concurrent);
+ATF_TC_HEAD(system_concurrent, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "Concurrent calls");
+}
+ATF_TC_BODY(system_concurrent, tc)
+{
+#define N 3
+	sigset_t normset, sigset;
+	pthread_t thr[N];
+	char fn[8];
+	int fd[N];
+	void *arg, *ret;
+
+	/* Create and lock the locks */
+	for (int i = 0; i < N; i++) {
+		snprintf(fn, sizeof(fn), "lock%d", i);
+		fd[i] = open(fn, O_CREAT|O_EXCL|O_EXLOCK|O_CLOEXEC, 0644);
+		ATF_REQUIRE_MSG(fd[i] >= 0, "%s: %m", fn);
+	}
+
+	/* Create the flags */
+	for (int i = 0; i < N; i++) {
+		snprintf(fn, sizeof(fn), "flag%d", i);
+		ATF_REQUIRE_EQ(0, symlink(fn, fn));
+	}
+
+	/* Get the current and expected signal mask */
+	sigprocmask(0, NULL, &normset);
+
+	/* Spawn threads which block on these files */
+	for (int i = 0; i < N; i++) {
+		arg = (void *)(intptr_t)i;
+		ATF_REQUIRE_INTEQ(0,
+		    pthread_create(&thr[i], NULL, system_thread, arg));
+	}
+
+	/* Wait until the flags are gone */
+	for (int i = 0; i < N; i++) {
+		snprintf(fn, sizeof(fn), "flag%d", i);
+		while (readlink(fn, fn, sizeof(fn)) > 0)
+			usleep(10000);
+		ATF_REQUIRE_EQ(ENOENT, errno);
+	}
+
+	/* Release the locks */
+	for (int i = 0; i < N; i++) {
+		/* Check the signal dispositions */
+		ATF_CHECK_EQ(SIG_IGN, signal(SIGINT, SIG_IGN));
+		ATF_CHECK_EQ(SIG_IGN, signal(SIGQUIT, SIG_IGN));
+#ifndef PROCMASK_IS_THREADMASK
+		sigprocmask(0, NULL, &sigset);
+		ATF_CHECK(sigismember(&sigset, SIGCHLD));
+#endif
+
+		/* Close the file, releasing the lock */
+		ATF_REQUIRE_INTEQ(0, close(fd[i]));
+
+		/* Join the thread and check the return value */
+		ATF_CHECK_INTEQ(0, pthread_join(thr[i], &ret));
+		ATF_CHECK_INTEQ(W_EXITCODE(0, 0), (int)(intptr_t)ret);
+	}
+
+	/* Check the signal dispositions */
+	ATF_CHECK_EQ(SIG_DFL, signal(SIGINT, SIG_DFL));
+	ATF_CHECK_EQ(SIG_DFL, signal(SIGQUIT, SIG_DFL));
+	sigprocmask(0, NULL, &sigset);
+	ATF_CHECK_EQ(0, memcmp(&sigset, &normset, sizeof(sigset_t)));
+#undef N
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+	ATF_TP_ADD_TC(tp, system_true);
+	ATF_TP_ADD_TC(tp, system_false);
+	ATF_TP_ADD_TC(tp, system_touch);
+	ATF_TP_ADD_TC(tp, system_null);
+	ATF_TP_ADD_TC(tp, system_concurrent);
+	return (atf_no_error());
+}


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69a84573.26c19.1b828c6f>