]> git.ipfire.org Git - thirdparty/systemd.git/commit
tests: ASSERT_SIGNAL: Do not allow parent to hallucinate it is the child 39807/head
authorChris Down <chris@chrisdown.name>
Wed, 19 Nov 2025 14:06:03 +0000 (22:06 +0800)
committerChris Down <chris@chrisdown.name>
Wed, 19 Nov 2025 18:40:07 +0000 (02:40 +0800)
commite21a431ec45ef11f1dffddef0d16fa4fcaece535
treea1679f9f1760558d3a0e816616556776c7c09aed
parentd759ed527c7c75cffcc9b72dd7b3fcf0854bec2f
tests: ASSERT_SIGNAL: Do not allow parent to hallucinate it is the child

assert_signal_internal() returns 0 in two distinct cases:

1. In the child process (immediately after fork returns 0).
2. In the parent process, if the child exited normally (no signal).

ASSERT_SIGNAL fails to distinguish these cases. When a child exited
normally (case 2), the parent process receives 0, incorrectly interprets
it as meaning it is the child, and re-executes the test expression
inside the parent process. Goodness gracious!

This causes two severe test integrity issues:

1. False positives. The parent can run the expression, succeed, and call
   _exit(EXIT_SUCCESS), causing the test to pass even though no signal
   was raised.
2. Silent truncation. The _exit() call in the parent terminates the test
   runner prematurely, preventing subsequent tests in the same file from
   running.

Example of the bug in action, from #39674:

    ASSERT_SIGNAL(fd_is_writable(closed_fd), SIGABRT)

This test should fail (fd_is_writable does not SIGABRT here), but with
the bug, the parent hallucinated being the child, re-ran the expression
successfully, and exited with success.

Fix this by refactoring assert_signal_internal() to be much more strict
about separating control flow from data.

The signal status is now returned via a strictly typed output parameter,
guaranteeing that determining whether we are the child is never
conflated with whether the child exited cleanly.
src/shared/tests.c
src/shared/tests.h
src/test/test-tests.c