Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src Add new ATF tests: kernel/t_zombie
details: https://anonhg.NetBSD.org/src/rev/1776947f96d2
branches: trunk
changeset: 321382:1776947f96d2
user: kamil <kamil%NetBSD.org@localhost>
date: Wed Mar 14 02:13:47 2018 +0000
description:
Add new ATF tests: kernel/t_zombie
New tests attempting to kill, stop, drop or revive a zombie:
- signal1 (SIGKILL)
- signal2 (SIGSTOP)
- signal3 (SIGABRT)
- signal4 (SIGHUP)
- signal5 (SIGCONT)
New test race1 verifying whether there are any kernel races when processing
signals to zombies, executing in a loop for 5 seconds.
These tests were inspired by a kernel unexpected behavior when a lookup
of a dying process could result in two detected entities once as an alive
process and once as a zombie.
race1 is similar to t_ptrace_wait* race1, however without ptrace(2) involved.
Sponsored by <The NetBSD Foundation>
diffstat:
distrib/sets/lists/debug/mi | 3 +-
distrib/sets/lists/tests/mi | 3 +-
tests/kernel/Makefile | 3 +-
tests/kernel/t_zombie.c | 276 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 282 insertions(+), 3 deletions(-)
diffs (truncated from 331 to 300 lines):
diff -r 735ed7ae8c3d -r 1776947f96d2 distrib/sets/lists/debug/mi
--- a/distrib/sets/lists/debug/mi Tue Mar 13 23:03:21 2018 +0000
+++ b/distrib/sets/lists/debug/mi Wed Mar 14 02:13:47 2018 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.244 2018/03/09 20:20:48 joerg Exp $
+# $NetBSD: mi,v 1.245 2018/03/14 02:13:47 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
@@ -1750,6 +1750,7 @@
./usr/libdata/debug/usr/tests/kernel/t_timeleft.debug tests-kernel-tests debug,atf,compattestfile
./usr/libdata/debug/usr/tests/kernel/t_ucontext.debug tests-obsolete obsolete,compattestfile
./usr/libdata/debug/usr/tests/kernel/t_writev.debug tests-obsolete obsolete,compattestfile
+./usr/libdata/debug/usr/tests/kernel/t_zombie.debug tests-kernel-tests debug,atf,rump
./usr/libdata/debug/usr/tests/kernel/tty/t_pr.debug tests-kernel-tests debug,atf,rump
./usr/libdata/debug/usr/tests/kyua-cli/bootstrap/atf_helpers.debug tests-kyua-tests debug,atf,kyua,compattestfile
./usr/libdata/debug/usr/tests/kyua-cli/bootstrap/plain_helpers.debug tests-kyua-tests debug,atf,kyua,compattestfile
diff -r 735ed7ae8c3d -r 1776947f96d2 distrib/sets/lists/tests/mi
--- a/distrib/sets/lists/tests/mi Tue Mar 13 23:03:21 2018 +0000
+++ b/distrib/sets/lists/tests/mi Wed Mar 14 02:13:47 2018 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.776 2018/03/09 20:20:48 joerg Exp $
+# $NetBSD: mi,v 1.777 2018/03/14 02:13:47 kamil Exp $
#
# Note: don't delete entries from here - mark them as "obsolete" instead.
#
@@ -2197,6 +2197,7 @@
./usr/tests/kernel/t_umount tests-kernel-tests compattestfile,atf
./usr/tests/kernel/t_umountstress tests-kernel-tests compattestfile,atf
./usr/tests/kernel/t_writev tests-obsolete obsolete
+./usr/tests/kernel/t_zombie tests-kernel-tests compattestfile,atf
./usr/tests/kernel/tty tests-kernel-tests compattestfile,atf
./usr/tests/kernel/tty/Atffile tests-kernel-tests atf,rump
./usr/tests/kernel/tty/Kyuafile tests-kernel-tests atf,rump,kyua
diff -r 735ed7ae8c3d -r 1776947f96d2 tests/kernel/Makefile
--- a/tests/kernel/Makefile Tue Mar 13 23:03:21 2018 +0000
+++ b/tests/kernel/Makefile Wed Mar 14 02:13:47 2018 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.52 2017/12/14 14:38:17 nakayama Exp $
+# $NetBSD: Makefile,v 1.53 2018/03/14 02:13:47 kamil Exp $
NOMAN= # defined
@@ -16,6 +16,7 @@
TESTS_C+= t_kauth_pr_47598
TESTS_C+= t_sysctl
TESTS_C+= t_timeleft
+TESTS_C+= t_zombie
TESTS_SH= t_umount
TESTS_SH+= t_umountstress
diff -r 735ed7ae8c3d -r 1776947f96d2 tests/kernel/t_zombie.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/kernel/t_zombie.c Wed Mar 14 02:13:47 2018 +0000
@@ -0,0 +1,276 @@
+/* $NetBSD: t_zombie.c,v 1.1 2018/03/14 02:13:47 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_zombie.c,v 1.1 2018/03/14 02:13:47 kamil Exp $");
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <time.h>
+#include <unistd.h>
+#include <err.h>
+
+#include <atf-c.h>
+
+static int debug = 0;
+
+#define DPRINTF(a, ...) \
+do { \
+ if (debug) printf(a, ##__VA_ARGS__); \
+} while (/*CONSTCOND*/0)
+
+/*
+ * 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)
+
+#define ASSERT(x) \
+do { \
+ int ret = (x); \
+ if (!ret) \
+ errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s", \
+ __FILE__, __LINE__, __func__, #x); \
+} while (/*CONSTCOND*/0)
+
+static bool
+check_zombie(pid_t process)
+{
+ struct kinfo_proc2 p;
+ size_t len = sizeof(p);
+
+ const int name[] = {
+ [0] = CTL_KERN,
+ [1] = KERN_PROC2,
+ [2] = KERN_PROC_PID,
+ [3] = process,
+ [4] = sizeof(p),
+ [5] = 1
+ };
+
+ const size_t namelen = __arraycount(name);
+
+ ASSERT_EQ(sysctl(name, namelen, &p, &len, NULL, 0), 0);
+
+ return (p.p_stat == LSZOMB);
+}
+
+static void __used
+await_zombie(pid_t process)
+{
+
+ /* Await the process becoming a zombie */
+ while (!check_zombie(process)) {
+ ASSERT_EQ(usleep(100), 0);
+ }
+}
+
+static void
+signal_raw(int sig)
+{
+ int status;
+ pid_t child1, child2, pid;
+
+ child1 = atf_utils_fork();
+ ATF_REQUIRE(child1 != 1);
+ if (child1 == 0) {
+ /* Just die and turn into a zombie */
+ _exit(0);
+ }
+
+ child2 = atf_utils_fork();
+ ATF_REQUIRE(child2 != 1);
+ if (child2 == 0) {
+ await_zombie(child1);
+
+ /*
+ * zombie does not process signals
+ * POSIX requires that zombie does not set errno ESRCH
+ * return value of kill() for a zombie is not specified
+ *
+ * Try to emit a signal towards it from an unrelated process.
+ */
+ errno = 0;
+ kill(child1, sig);
+ ASSERT_NEQ(errno, ESRCH);
+
+ /* A zombie is still a zombie waiting for collecting */
+ ASSERT(check_zombie(child1));
+
+ _exit(0);
+ }
+
+ pid = waitpid(child2, &status, WEXITED);
+ ATF_REQUIRE_EQ(pid, child2);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(!WIFCONTINUED(status));
+ ATF_REQUIRE(!WIFSIGNALED(status));
+ ATF_REQUIRE(!WIFSTOPPED(status));
+ ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
+
+ /* Assert that child1 is still a zombie after collecting child2 */
+ ATF_REQUIRE(check_zombie(child1));
+
+ /*
+ * zombie does not process signals
+ * POSIX requires that zombie does not set errno ESRCH
+ * return value of kill() for a zombie is not specified
+ *
+ * Try to emit a signal towards it from the parent.
+ */
+ errno = 0;
+ kill(child1, sig);
+ // ATF_CHECK_NEQ not available
+ ASSERT_NEQ(errno, ESRCH);
+
+ /* Assert that child1 is still a zombie after emitting a signal */
+ ATF_REQUIRE(check_zombie(child1));
+
+ pid = waitpid(child1, &status, WEXITED);
+ ATF_REQUIRE_EQ(pid, child1);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(!WIFCONTINUED(status));
+ ATF_REQUIRE(!WIFSIGNALED(status));
+ ATF_REQUIRE(!WIFSTOPPED(status));
+ ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
+}
+
+#define KILLABLE(test, sig) \
+ATF_TC(test); \
+ATF_TC_HEAD(test, tc) \
+{ \
+ \
+ atf_tc_set_md_var(tc, "descr", \
+ "process is not killable with " #sig); \
+} \
+ \
+ATF_TC_BODY(test, tc) \
+{ \
+ \
+ signal_raw(sig); \
+}
+
+KILLABLE(signal1, SIGKILL) /* non-maskable */
+KILLABLE(signal2, SIGSTOP) /* non-maskable */
+KILLABLE(signal3, SIGABRT) /* regular abort trap */
+KILLABLE(signal4, SIGHUP) /* hangup */
+KILLABLE(signal5, SIGCONT) /* continued? */
+
+ATF_TC(race1);
+ATF_TC_HEAD(race1, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "check if there are any races with sending signals, killing and "
+ "lookup of a zombie");
+}
+
+ATF_TC_BODY(race1, tc)
+{
+ time_t start, end;
+ double diff;
+ unsigned long N = 0;
+ int sig;
+
+ /*
+ * Assert that a dying process can be correctly looked up
+ * with sysctl(3) kern.proc and operation KERN_PROC_PID.
+ *
+ * This test has been inspired by a bug fixed in
+ * sys/kern/kern_proc.c 1.211
+ * "Make sysctl_doeproc() more predictable"
+ */
+
+ start = time(NULL);
+ while (true) {
+ /*
+ * A signal number does not matter, but it does not harm to
Home |
Main Index |
Thread Index |
Old Index