aboutsummaryrefslogtreecommitdiff
path: root/utils/process/executor_pid_test.cpp
diff options
context:
space:
mode:
authorMuhammad Moinur Rahman <bofh@FreeBSD.org>2024-01-12 20:27:36 +0000
committerMuhammad Moinur Rahman <bofh@FreeBSD.org>2024-01-12 20:27:36 +0000
commit5f174897f67783925f4ec69122673f9bad6ee6fe (patch)
tree2976ff4ea329a1f2a6d61392a2c89485cd408f18 /utils/process/executor_pid_test.cpp
parentd0738729dab0c60d6c695966157b3e9551be0861 (diff)
Diffstat (limited to 'utils/process/executor_pid_test.cpp')
-rw-r--r--utils/process/executor_pid_test.cpp208
1 files changed, 208 insertions, 0 deletions
diff --git a/utils/process/executor_pid_test.cpp b/utils/process/executor_pid_test.cpp
new file mode 100644
index 000000000000..22e0b90ba14b
--- /dev/null
+++ b/utils/process/executor_pid_test.cpp
@@ -0,0 +1,208 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Dell Inc.
+ * Author: Eric van Gyzen
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#if 0
+
+1. Run some "bad" tests that prevent kyua from removing the work directory.
+ We use "chflags uunlink". Mounting a file system from an md(4) device
+ is another common use case.
+2. Fork a lot, nearly wrapping the PID number space, so step 3 will re-use
+ a PID from step 1. Running the entire FreeBSD test suite is a more
+ realistic scenario for this step.
+3. Run some more tests. If the stars align, the bug is not fixed yet, and
+ kyua is built with debugging, kyua will abort with the following messages.
+ Without debugging, the tests in step 3 will reuse the context from step 1,
+ including stdout, stderr, and working directory, which are still populated
+ with stuff from step 1. When I found this bug, step 3 was
+ __test_cases_list__, which expects a certain format in stdout and failed
+ when it found something completely unrelated.
+4. You can clean up with: chflags -R nouunlink /tmp/kyua.*; rm -rf /tmp/kyua.*
+
+$ cc -o pid_wrap -latf-c pid_wrap.c
+$ kyua test
+pid_wrap:leak_0 -> passed [0.001s]
+pid_wrap:leak_1 -> passed [0.001s]
+pid_wrap:leak_2 -> passed [0.001s]
+pid_wrap:leak_3 -> passed [0.001s]
+pid_wrap:leak_4 -> passed [0.001s]
+pid_wrap:leak_5 -> passed [0.001s]
+pid_wrap:leak_6 -> passed [0.001s]
+pid_wrap:leak_7 -> passed [0.001s]
+pid_wrap:leak_8 -> passed [0.001s]
+pid_wrap:leak_9 -> passed [0.001s]
+pid_wrap:pid_wrap -> passed [1.113s]
+pid_wrap:pid_wrap_0 -> passed [0.001s]
+pid_wrap:pid_wrap_1 -> passed [0.001s]
+pid_wrap:pid_wrap_2 -> passed [0.001s]
+pid_wrap:pid_wrap_3 -> *** /usr/src/main/contrib/kyua/utils/process/executor.cpp:779: Invariant check failed: PID 60876 already in all_exec_handles; not properly cleaned up or reused too fast
+*** Fatal signal 6 received
+*** Log file is /home/vangyzen/.kyua/logs/kyua.20221006-193544.log
+*** Please report this problem to kyua-discuss@googlegroups.com detailing what you were doing before the crash happened; if possible, include the log file mentioned above
+Abort trap (core dumped)
+
+#endif
+
+#include <sys/stat.h>
+
+#include <atf-c++.hpp>
+
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <cerrno>
+#include <cstring>
+
+void
+leak_work_dir()
+{
+ int fd;
+
+ ATF_REQUIRE((fd = open("unforgettable", O_CREAT|O_EXCL|O_WRONLY, 0600))
+ >= 0);
+ ATF_REQUIRE_EQ(0, fchflags(fd, UF_NOUNLINK));
+ ATF_REQUIRE_EQ(0, close(fd));
+}
+
+void
+wrap_pids()
+{
+ pid_t begin, current, target;
+ bool wrapped;
+
+ begin = getpid();
+ target = begin - 15;
+ if (target <= 1) {
+ target += 99999; // PID_MAX
+ wrapped = true;
+ } else {
+ wrapped = false;
+ }
+
+ ATF_REQUIRE(signal(SIGCHLD, SIG_IGN) != SIG_ERR);
+
+ do {
+ current = vfork();
+ if (current == 0) {
+ _exit(0);
+ }
+ ATF_REQUIRE(current != -1);
+ if (current < begin) {
+ wrapped = true;
+ }
+ } while (!wrapped || current < target);
+}
+
+void
+test_work_dir_reuse()
+{
+ // If kyua is built with debugging, it would abort here before the fix.
+}
+
+void
+clean_up()
+{
+ (void)system("chflags -R nouunlink ../..");
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(leak_0);
+ATF_TEST_CASE_BODY(leak_0) { leak_work_dir(); }
+ATF_TEST_CASE_WITHOUT_HEAD(leak_1);
+ATF_TEST_CASE_BODY(leak_1) { leak_work_dir(); }
+ATF_TEST_CASE_WITHOUT_HEAD(leak_2);
+ATF_TEST_CASE_BODY(leak_2) { leak_work_dir(); }
+ATF_TEST_CASE_WITHOUT_HEAD(leak_3);
+ATF_TEST_CASE_BODY(leak_3) { leak_work_dir(); }
+ATF_TEST_CASE_WITHOUT_HEAD(leak_4);
+ATF_TEST_CASE_BODY(leak_4) { leak_work_dir(); }
+ATF_TEST_CASE_WITHOUT_HEAD(leak_5);
+ATF_TEST_CASE_BODY(leak_5) { leak_work_dir(); }
+ATF_TEST_CASE_WITHOUT_HEAD(leak_6);
+ATF_TEST_CASE_BODY(leak_6) { leak_work_dir(); }
+ATF_TEST_CASE_WITHOUT_HEAD(leak_7);
+ATF_TEST_CASE_BODY(leak_7) { leak_work_dir(); }
+ATF_TEST_CASE_WITHOUT_HEAD(leak_8);
+ATF_TEST_CASE_BODY(leak_8) { leak_work_dir(); }
+ATF_TEST_CASE_WITHOUT_HEAD(leak_9);
+ATF_TEST_CASE_BODY(leak_9) { leak_work_dir(); }
+
+ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap);
+ATF_TEST_CASE_BODY(pid_wrap) { wrap_pids(); }
+
+ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_0);
+ATF_TEST_CASE_BODY(pid_wrap_0) { test_work_dir_reuse(); }
+ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_1);
+ATF_TEST_CASE_BODY(pid_wrap_1) { test_work_dir_reuse(); }
+ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_2);
+ATF_TEST_CASE_BODY(pid_wrap_2) { test_work_dir_reuse(); }
+ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_3);
+ATF_TEST_CASE_BODY(pid_wrap_3) { test_work_dir_reuse(); }
+ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_4);
+ATF_TEST_CASE_BODY(pid_wrap_4) { test_work_dir_reuse(); }
+ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_5);
+ATF_TEST_CASE_BODY(pid_wrap_5) { test_work_dir_reuse(); }
+ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_6);
+ATF_TEST_CASE_BODY(pid_wrap_6) { test_work_dir_reuse(); }
+ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_7);
+ATF_TEST_CASE_BODY(pid_wrap_7) { test_work_dir_reuse(); }
+ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_8);
+ATF_TEST_CASE_BODY(pid_wrap_8) { test_work_dir_reuse(); }
+ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_9);
+ATF_TEST_CASE_BODY(pid_wrap_9) { test_work_dir_reuse(); }
+
+ATF_TEST_CASE_WITHOUT_HEAD(really_clean_up);
+ATF_TEST_CASE_BODY(really_clean_up) { clean_up(); }
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ ATF_ADD_TEST_CASE(tcs, leak_0);
+ ATF_ADD_TEST_CASE(tcs, leak_1);
+ ATF_ADD_TEST_CASE(tcs, leak_2);
+ ATF_ADD_TEST_CASE(tcs, leak_3);
+ ATF_ADD_TEST_CASE(tcs, leak_4);
+ ATF_ADD_TEST_CASE(tcs, leak_5);
+ ATF_ADD_TEST_CASE(tcs, leak_6);
+ ATF_ADD_TEST_CASE(tcs, leak_7);
+ ATF_ADD_TEST_CASE(tcs, leak_8);
+ ATF_ADD_TEST_CASE(tcs, leak_9);
+
+ ATF_ADD_TEST_CASE(tcs, pid_wrap);
+
+ ATF_ADD_TEST_CASE(tcs, pid_wrap_0);
+ ATF_ADD_TEST_CASE(tcs, pid_wrap_1);
+ ATF_ADD_TEST_CASE(tcs, pid_wrap_2);
+ ATF_ADD_TEST_CASE(tcs, pid_wrap_3);
+ ATF_ADD_TEST_CASE(tcs, pid_wrap_4);
+ ATF_ADD_TEST_CASE(tcs, pid_wrap_5);
+ ATF_ADD_TEST_CASE(tcs, pid_wrap_6);
+ ATF_ADD_TEST_CASE(tcs, pid_wrap_7);
+ ATF_ADD_TEST_CASE(tcs, pid_wrap_8);
+ ATF_ADD_TEST_CASE(tcs, pid_wrap_9);
+
+ ATF_ADD_TEST_CASE(tcs, really_clean_up);
+}