Module Name:    src
Committed By:   kamil
Date:           Fri May 18 06:39:59 UTC 2018

Modified Files:
        src/distrib/sets/lists/debug: mi
        src/distrib/sets/lists/tests: mi
        src/tests/lib/libc/sys: Makefile
Added Files:
        src/tests/lib/libc/sys: t_fork.c t_vfork.c

Log Message:
Add new ATF tests: t_fork and t_vfork

Test behavior of raise(signal) in either fork(2)ed or vfork(2)ed child.

Tests:
 - raise1 SIGKILL
 - raise2 SIGSTOP
 - raise3 SIGTSTP
 - raise4 SIGTTIN
 - raise5 SIGTTOU
 - raise6 SIGABRT
 - raise7 SIGHUP
 - raise8 SIGCONT

t_vfork:raise2 fails ignoring non-maskable SIGSTOP.

The remaining ones pass.

Sponsored by <The NetBSD Foundation>


To generate a diff of this commit:
cvs rdiff -u -r1.247 -r1.248 src/distrib/sets/lists/debug/mi
cvs rdiff -u -r1.782 -r1.783 src/distrib/sets/lists/tests/mi
cvs rdiff -u -r1.50 -r1.51 src/tests/lib/libc/sys/Makefile
cvs rdiff -u -r0 -r1.1 src/tests/lib/libc/sys/t_fork.c \
    src/tests/lib/libc/sys/t_vfork.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/distrib/sets/lists/debug/mi
diff -u src/distrib/sets/lists/debug/mi:1.247 src/distrib/sets/lists/debug/mi:1.248
--- src/distrib/sets/lists/debug/mi:1.247	Fri May  4 12:44:40 2018
+++ src/distrib/sets/lists/debug/mi	Fri May 18 06:39:58 2018
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.247 2018/05/04 12:44:40 sevan Exp $
+# $NetBSD: mi,v 1.248 2018/05/18 06:39:58 kamil Exp $
 ./etc/mtree/set.debug                           comp-sys-root
 ./usr/lib					comp-sys-usr		compatdir
 ./usr/lib/i18n/libBIG5_g.a			comp-c-debuglib		debuglib,compatfile
@@ -2073,6 +2073,7 @@
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_connect.debug		tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_context.debug		tests-obsolete		obsolete,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_dup.debug			tests-lib-debug		debug,atf,compattestfile
+./usr/libdata/debug/usr/tests/lib/libc/sys/t_fork.debug			tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_fsync.debug		tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_getcontext.debug		tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_getgroups.debug		tests-lib-debug		debug,atf,compattestfile
@@ -2133,6 +2134,7 @@
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_ucontext.debug		tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_umask.debug		tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_unlink.debug		tests-lib-debug		debug,atf,compattestfile
+./usr/libdata/debug/usr/tests/lib/libc/sys/t_vfork.debug		tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_wait.debug			tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_wait_noproc.debug		tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/sys/t_wait_noproc_wnohang.debug	tests-lib-debug		debug,atf,compattestfile

Index: src/distrib/sets/lists/tests/mi
diff -u src/distrib/sets/lists/tests/mi:1.782 src/distrib/sets/lists/tests/mi:1.783
--- src/distrib/sets/lists/tests/mi:1.782	Wed May  2 18:46:05 2018
+++ src/distrib/sets/lists/tests/mi	Fri May 18 06:39:59 2018
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.782 2018/05/02 18:46:05 kamil Exp $
+# $NetBSD: mi,v 1.783 2018/05/18 06:39:59 kamil Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -2757,6 +2757,7 @@
 ./usr/tests/lib/libc/sys/t_connect		tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/sys/t_context		tests-obsolete		obsolete
 ./usr/tests/lib/libc/sys/t_dup			tests-lib-tests		compattestfile,atf
+./usr/tests/lib/libc/sys/t_fork			tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/sys/t_fsync		tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/sys/t_getcontext		tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/sys/t_getgroups		tests-lib-tests		compattestfile,atf
@@ -2817,6 +2818,7 @@
 ./usr/tests/lib/libc/sys/t_ucontext		tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/sys/t_umask		tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/sys/t_unlink		tests-lib-tests		compattestfile,atf
+./usr/tests/lib/libc/sys/t_vfork		tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/sys/t_wait			tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/sys/t_wait_noproc		tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/sys/t_wait_noproc_wnohang	tests-lib-tests		compattestfile,atf

Index: src/tests/lib/libc/sys/Makefile
diff -u src/tests/lib/libc/sys/Makefile:1.50 src/tests/lib/libc/sys/Makefile:1.51
--- src/tests/lib/libc/sys/Makefile:1.50	Sun Feb 25 14:27:07 2018
+++ src/tests/lib/libc/sys/Makefile	Fri May 18 06:39:58 2018
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.50 2018/02/25 14:27:07 kamil Exp $
+# $NetBSD: Makefile,v 1.51 2018/05/18 06:39:58 kamil Exp $
 
 MKMAN=	no
 
@@ -16,6 +16,7 @@ TESTS_C+=		t_clock_nanosleep
 TESTS_C+=		t_clone
 TESTS_C+=		t_connect
 TESTS_C+=		t_dup
+TESTS_C+=		t_fork
 TESTS_C+=		t_fsync
 TESTS_C+=		t_getcontext
 TESTS_C+=		t_getgroups
@@ -74,6 +75,7 @@ TESTS_C+=		t_truncate
 TESTS_C+=		t_ucontext
 TESTS_C+=		t_umask
 TESTS_C+=		t_unlink
+TESTS_C+=		t_vfork
 TESTS_C+=		t_wait
 TESTS_C+=		t_wait_noproc
 TESTS_C+=		t_wait_noproc_wnohang

Added files:

Index: src/tests/lib/libc/sys/t_fork.c
diff -u /dev/null src/tests/lib/libc/sys/t_fork.c:1.1
--- /dev/null	Fri May 18 06:39:59 2018
+++ src/tests/lib/libc/sys/t_fork.c	Fri May 18 06:39:58 2018
@@ -0,0 +1,281 @@
+/*	$NetBSD: t_fork.c,v 1.1 2018/05/18 06:39:58 kamil Exp $	*/
+
+/*-
+ * Copyright (c) 2018 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__COPYRIGHT("@(#) Copyright (c) 2018\
+ The NetBSD Foundation, inc. All rights reserved.");
+__RCSID("$NetBSD: t_fork.c,v 1.1 2018/05/18 06:39:58 kamil Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include <atf-c.h>
+
+#ifdef VFORK
+#define FORK vfork
+#else
+#define FORK fork
+#endif
+
+/*
+ * A child process cannot call atf functions and expect them to magically
+ * work like in the parent.
+ * The printf(3) messaging from a child will not work out of the box as well
+ * without estabilishing a communication protocol with its parent. To not
+ * overcomplicate the tests - do not log from a child and use err(3)/errx(3)
+ * wrapped with ASSERT_EQ()/ASSERT_NEQ() as that is guaranteed to work.
+ */
+#define ASSERT_EQ(x, y)								\
+do {										\
+	uintmax_t vx = (x);							\
+	uintmax_t vy = (y);							\
+	int ret = vx == vy;							\
+	if (!ret)								\
+		errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: "		\
+		    "%s(%ju) == %s(%ju)", __FILE__, __LINE__, __func__,		\
+		    #x, vx, #y, vy);						\
+} while (/*CONSTCOND*/0)
+
+#define ASSERT_NEQ(x, y)							\
+do {										\
+	uintmax_t vx = (x);							\
+	uintmax_t vy = (y);							\
+	int ret = vx != vy;							\
+	if (!ret)								\
+		errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: "		\
+		    "%s(%ju) != %s(%ju)", __FILE__, __LINE__, __func__,		\
+		    #x, vx, #y, vy);						\
+} while (/*CONSTCOND*/0)
+
+static pid_t
+await_stopped_child(pid_t process)
+{
+	struct kinfo_proc2 *p = NULL;
+	size_t i, len;
+	pid_t child = -1;
+
+	int name[] = {
+		[0] = CTL_KERN,
+		[1] = KERN_PROC2,
+		[2] = KERN_PROC_ALL,
+		[3] = 0,
+		[4] = sizeof(struct kinfo_proc2),
+		[5] = 0
+	};
+
+	const size_t namelen = __arraycount(name);
+
+	/* Await the process becoming a zombie */
+	while(1) {
+		name[5] = 0;
+
+		ASSERT_EQ(sysctl(name, namelen, 0, &len, NULL, 0), 0);
+
+		ASSERT_EQ(reallocarr(&p, len, sizeof(struct kinfo_proc2)), 0);
+
+		name[5] = len;
+
+		ASSERT_EQ(sysctl(name, namelen, p, &len, NULL, 0), 0);
+
+		for (i = 0; i < len/sizeof(struct kinfo_proc2); i++) {
+			if (p[i].p_pid == getpid())
+				continue;
+			if (p[i].p_ppid != process)
+				continue;
+			if (p[i].p_stat != LSSTOP)
+				continue;
+			child = p[i].p_pid;
+			break;
+		}
+
+		if (child != -1)
+			break;
+
+		ASSERT_EQ(usleep(1000), 0);
+	}
+
+	/* Free the buffer */
+	ASSERT_EQ(reallocarr(&p, 0, sizeof(struct kinfo_proc2)), 0);
+
+	return child;
+}
+
+static void
+raise_raw(int sig)
+{
+	int rv, status;
+	pid_t child, parent, watcher, wpid;
+	int expect_core = (sig == SIGABRT) ? 1 : 0;
+
+#ifdef VFORK
+	if (sig == SIGSTOP) {
+		atf_tc_expect_fail("SIGSTOP shall not be ignored");
+	}
+#endif
+
+	/*
+	 * Spawn a dedicated thread to watch for a stopped child and emit
+	 * the SIGTERM signal to it.
+	 *
+	 * This is required in vfork(2)ing parent and optional in fork(2).
+	 *
+	 * vfork(2) might clobber watcher, this means that it's safer and
+	 * simpler to reparent this process to initproc and forget about it.
+	 */
+	if (sig == SIGSTOP
+#ifndef VFORK
+	    || (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
+#endif
+	    ) {
+
+		parent = getpid();
+
+		watcher = fork();
+		ATF_REQUIRE(watcher != 1);
+		if (watcher == 0) {
+			/* Double fork(2) trick to reparent to initproc */
+			watcher = fork();
+			ASSERT_NEQ(watcher, -1);
+			if (watcher != 0)
+				_exit(0);
+
+			child = await_stopped_child(parent);
+
+			errno = 0;
+			rv = kill(child, SIGKILL);
+			ASSERT_EQ(rv, 0);
+			ASSERT_EQ(errno, 0);
+
+			/* This exit value will be collected by initproc */
+			_exit(0);
+		}
+
+		wpid = waitpid(watcher, &status, 0);
+
+		ATF_REQUIRE_EQ(wpid, watcher);
+
+		ATF_REQUIRE(WIFEXITED(status));
+		ATF_REQUIRE(!WIFCONTINUED(status));
+		ATF_REQUIRE(!WIFSIGNALED(status));
+		ATF_REQUIRE(!WIFSTOPPED(status));
+		ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
+	}
+
+	child = FORK();
+	ATF_REQUIRE(child != 1);
+	if (child == 0) {
+		rv = raise(sig);
+		ASSERT_EQ(rv, 0);
+		_exit(0);
+	}
+	wpid = waitpid(child, &status, 0);
+
+	ATF_REQUIRE_EQ(wpid, child);
+
+	switch (sig) {
+	case SIGKILL:
+	case SIGABRT:
+	case SIGHUP:
+		ATF_REQUIRE(!WIFEXITED(status));
+		ATF_REQUIRE(!WIFCONTINUED(status));
+		ATF_REQUIRE(WIFSIGNALED(status));
+		ATF_REQUIRE(!WIFSTOPPED(status));
+		ATF_REQUIRE_EQ(WTERMSIG(status), sig);
+		ATF_REQUIRE_EQ(!!WCOREDUMP(status), expect_core);
+		break;
+#ifdef VFORK
+	case SIGTSTP:
+	case SIGTTIN:
+	case SIGTTOU:
+#endif
+	case SIGCONT:
+		ATF_REQUIRE(WIFEXITED(status));
+		ATF_REQUIRE(!WIFCONTINUED(status));
+		ATF_REQUIRE(!WIFSIGNALED(status));
+		ATF_REQUIRE(!WIFSTOPPED(status));
+		ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
+		break;
+#ifndef VFORK
+	case SIGTSTP:
+	case SIGTTIN:
+	case SIGTTOU:
+#endif
+	case SIGSTOP:
+		ATF_REQUIRE(!WIFEXITED(status));
+		ATF_REQUIRE(!WIFCONTINUED(status));
+		ATF_REQUIRE(WIFSIGNALED(status));
+		ATF_REQUIRE(!WIFSTOPPED(status));
+		ATF_REQUIRE_EQ(WTERMSIG(status), SIGKILL);
+		ATF_REQUIRE_EQ(!!WCOREDUMP(status), 0);
+	}
+}
+
+#define RAISE(test, sig)							\
+ATF_TC(test);									\
+ATF_TC_HEAD(test, tc)								\
+{										\
+										\
+	atf_tc_set_md_var(tc, "descr",						\
+	    "raise " #sig " in vfork(2)ed child");				\
+}										\
+										\
+ATF_TC_BODY(test, tc)								\
+{										\
+										\
+	raise_raw(sig);								\
+}
+
+RAISE(raise1, SIGKILL) /* non-maskable */
+RAISE(raise2, SIGSTOP) /* non-maskable */
+RAISE(raise3, SIGTSTP) /* ignored in vfork(2) */
+RAISE(raise4, SIGTTIN) /* ignored in vfork(2) */
+RAISE(raise5, SIGTTOU) /* ignored in vfork(2) */
+RAISE(raise6, SIGABRT) /* regular abort trap */
+RAISE(raise7, SIGHUP)  /* hangup */
+RAISE(raise8, SIGCONT) /* continued? */
+
+ATF_TP_ADD_TCS(tp)
+{
+	ATF_TP_ADD_TC(tp, raise1);
+	ATF_TP_ADD_TC(tp, raise2);
+	ATF_TP_ADD_TC(tp, raise3);
+	ATF_TP_ADD_TC(tp, raise4);
+	ATF_TP_ADD_TC(tp, raise5);
+	ATF_TP_ADD_TC(tp, raise6);
+	ATF_TP_ADD_TC(tp, raise7);
+	ATF_TP_ADD_TC(tp, raise8);
+
+	return atf_no_error();
+}
Index: src/tests/lib/libc/sys/t_vfork.c
diff -u /dev/null src/tests/lib/libc/sys/t_vfork.c:1.1
--- /dev/null	Fri May 18 06:39:59 2018
+++ src/tests/lib/libc/sys/t_vfork.c	Fri May 18 06:39:58 2018
@@ -0,0 +1,30 @@
+/*	$NetBSD: t_vfork.c,v 1.1 2018/05/18 06:39:58 kamil Exp $	*/
+
+/*-
+ * Copyright (c) 2018 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define VFORK
+#include "t_fork.c"

Reply via email to