1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2022 Dell Inc.
5 * Author: Eric van Gyzen
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#if 0
30
311. Run some "bad" tests that prevent kyua from removing the work directory.
32   We use "chflags uunlink".  Mounting a file system from an md(4) device
33   is another common use case.
342. Fork a lot, nearly wrapping the PID number space, so step 3 will re-use
35   a PID from step 1.  Running the entire FreeBSD test suite is a more
36   realistic scenario for this step.
373. Run some more tests.  If the stars align, the bug is not fixed yet, and
38   kyua is built with debugging, kyua will abort with the following messages.
39   Without debugging, the tests in step 3 will reuse the context from step 1,
40   including stdout, stderr, and working directory, which are still populated
41   with stuff from step 1.  When I found this bug, step 3 was
42   __test_cases_list__, which expects a certain format in stdout and failed
43   when it found something completely unrelated.
444. You can clean up with: chflags -R nouunlink /tmp/kyua.*; rm -rf /tmp/kyua.*
45
46$ cc -o pid_wrap -latf-c pid_wrap.c
47$ kyua test
48pid_wrap:leak_0  ->  passed  [0.001s]
49pid_wrap:leak_1  ->  passed  [0.001s]
50pid_wrap:leak_2  ->  passed  [0.001s]
51pid_wrap:leak_3  ->  passed  [0.001s]
52pid_wrap:leak_4  ->  passed  [0.001s]
53pid_wrap:leak_5  ->  passed  [0.001s]
54pid_wrap:leak_6  ->  passed  [0.001s]
55pid_wrap:leak_7  ->  passed  [0.001s]
56pid_wrap:leak_8  ->  passed  [0.001s]
57pid_wrap:leak_9  ->  passed  [0.001s]
58pid_wrap:pid_wrap  ->  passed  [1.113s]
59pid_wrap:pid_wrap_0  ->  passed  [0.001s]
60pid_wrap:pid_wrap_1  ->  passed  [0.001s]
61pid_wrap:pid_wrap_2  ->  passed  [0.001s]
62pid_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
63*** Fatal signal 6 received
64*** Log file is /home/vangyzen/.kyua/logs/kyua.20221006-193544.log
65*** 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
66Abort trap (core dumped)
67
68#endif
69
70#include <sys/stat.h>
71
72#include <atf-c++.hpp>
73
74#include <fcntl.h>
75#include <signal.h>
76#include <unistd.h>
77
78#include <cerrno>
79#include <cstring>
80
81void
82leak_work_dir()
83{
84	int fd;
85
86	ATF_REQUIRE((fd = open("unforgettable", O_CREAT|O_EXCL|O_WRONLY, 0600))
87	    >= 0);
88	ATF_REQUIRE_EQ(0, fchflags(fd, UF_NOUNLINK));
89	ATF_REQUIRE_EQ(0, close(fd));
90}
91
92void
93wrap_pids()
94{
95	pid_t begin, current, target;
96	bool wrapped;
97
98	begin = getpid();
99	target = begin - 15;
100	if (target <= 1) {
101		target += 99999;    // PID_MAX
102		wrapped = true;
103	} else {
104		wrapped = false;
105	}
106
107	ATF_REQUIRE(signal(SIGCHLD, SIG_IGN) != SIG_ERR);
108
109	do {
110		current = vfork();
111		if (current == 0) {
112			_exit(0);
113		}
114		ATF_REQUIRE(current != -1);
115		if (current < begin) {
116			wrapped = true;
117		}
118	} while (!wrapped || current < target);
119}
120
121void
122test_work_dir_reuse()
123{
124	// If kyua is built with debugging, it would abort here before the fix.
125}
126
127void
128clean_up()
129{
130	(void)system("chflags -R nouunlink ../..");
131}
132
133ATF_TEST_CASE_WITHOUT_HEAD(leak_0);
134ATF_TEST_CASE_BODY(leak_0) { leak_work_dir(); }
135ATF_TEST_CASE_WITHOUT_HEAD(leak_1);
136ATF_TEST_CASE_BODY(leak_1) { leak_work_dir(); }
137ATF_TEST_CASE_WITHOUT_HEAD(leak_2);
138ATF_TEST_CASE_BODY(leak_2) { leak_work_dir(); }
139ATF_TEST_CASE_WITHOUT_HEAD(leak_3);
140ATF_TEST_CASE_BODY(leak_3) { leak_work_dir(); }
141ATF_TEST_CASE_WITHOUT_HEAD(leak_4);
142ATF_TEST_CASE_BODY(leak_4) { leak_work_dir(); }
143ATF_TEST_CASE_WITHOUT_HEAD(leak_5);
144ATF_TEST_CASE_BODY(leak_5) { leak_work_dir(); }
145ATF_TEST_CASE_WITHOUT_HEAD(leak_6);
146ATF_TEST_CASE_BODY(leak_6) { leak_work_dir(); }
147ATF_TEST_CASE_WITHOUT_HEAD(leak_7);
148ATF_TEST_CASE_BODY(leak_7) { leak_work_dir(); }
149ATF_TEST_CASE_WITHOUT_HEAD(leak_8);
150ATF_TEST_CASE_BODY(leak_8) { leak_work_dir(); }
151ATF_TEST_CASE_WITHOUT_HEAD(leak_9);
152ATF_TEST_CASE_BODY(leak_9) { leak_work_dir(); }
153
154ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap);
155ATF_TEST_CASE_BODY(pid_wrap) { wrap_pids(); }
156
157ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_0);
158ATF_TEST_CASE_BODY(pid_wrap_0) { test_work_dir_reuse(); }
159ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_1);
160ATF_TEST_CASE_BODY(pid_wrap_1) { test_work_dir_reuse(); }
161ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_2);
162ATF_TEST_CASE_BODY(pid_wrap_2) { test_work_dir_reuse(); }
163ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_3);
164ATF_TEST_CASE_BODY(pid_wrap_3) { test_work_dir_reuse(); }
165ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_4);
166ATF_TEST_CASE_BODY(pid_wrap_4) { test_work_dir_reuse(); }
167ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_5);
168ATF_TEST_CASE_BODY(pid_wrap_5) { test_work_dir_reuse(); }
169ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_6);
170ATF_TEST_CASE_BODY(pid_wrap_6) { test_work_dir_reuse(); }
171ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_7);
172ATF_TEST_CASE_BODY(pid_wrap_7) { test_work_dir_reuse(); }
173ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_8);
174ATF_TEST_CASE_BODY(pid_wrap_8) { test_work_dir_reuse(); }
175ATF_TEST_CASE_WITHOUT_HEAD(pid_wrap_9);
176ATF_TEST_CASE_BODY(pid_wrap_9) { test_work_dir_reuse(); }
177
178ATF_TEST_CASE_WITHOUT_HEAD(really_clean_up);
179ATF_TEST_CASE_BODY(really_clean_up) { clean_up(); }
180
181ATF_INIT_TEST_CASES(tcs)
182{
183	ATF_ADD_TEST_CASE(tcs, leak_0);
184	ATF_ADD_TEST_CASE(tcs, leak_1);
185	ATF_ADD_TEST_CASE(tcs, leak_2);
186	ATF_ADD_TEST_CASE(tcs, leak_3);
187	ATF_ADD_TEST_CASE(tcs, leak_4);
188	ATF_ADD_TEST_CASE(tcs, leak_5);
189	ATF_ADD_TEST_CASE(tcs, leak_6);
190	ATF_ADD_TEST_CASE(tcs, leak_7);
191	ATF_ADD_TEST_CASE(tcs, leak_8);
192	ATF_ADD_TEST_CASE(tcs, leak_9);
193
194	ATF_ADD_TEST_CASE(tcs, pid_wrap);
195
196	ATF_ADD_TEST_CASE(tcs, pid_wrap_0);
197	ATF_ADD_TEST_CASE(tcs, pid_wrap_1);
198	ATF_ADD_TEST_CASE(tcs, pid_wrap_2);
199	ATF_ADD_TEST_CASE(tcs, pid_wrap_3);
200	ATF_ADD_TEST_CASE(tcs, pid_wrap_4);
201	ATF_ADD_TEST_CASE(tcs, pid_wrap_5);
202	ATF_ADD_TEST_CASE(tcs, pid_wrap_6);
203	ATF_ADD_TEST_CASE(tcs, pid_wrap_7);
204	ATF_ADD_TEST_CASE(tcs, pid_wrap_8);
205	ATF_ADD_TEST_CASE(tcs, pid_wrap_9);
206
207	ATF_ADD_TEST_CASE(tcs, really_clean_up);
208}
209