commit: 08147ec21ddca45950d806e72ebfba30f44dc3c3
parent bc2f5cfd41483c1a280c4c8cc36a2d90268db0de
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Sat, 13 Dec 2025 15:56:05 +0100
cmd/timeout: Fix SIGCHLD handler not exiting with timeout return code
Race-condition found via testing on OpenBSD
Diffstat:
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/cmd/timeout.c b/cmd/timeout.c
@@ -35,16 +35,21 @@ extern char **environ;
pid_t child = 0;
const char *argv0 = "timeout";
+static bool timeout = false;
+static int cmd_exit_timeout = CMD_EXIT_TIMEOUT;
static void
handle_sigchld(int sig)
{
+ // Doesn't uses exit() to avoid running the atexit handlers
+ // one of which being gcc --coverage handler which causes a hang
(void)sig;
int stat_loc = 0;
+
+ if(timeout && cmd_exit_timeout != 0) _Exit(CMD_EXIT_TIMEOUT);
+
waitpid(child, &stat_loc, WNOHANG);
- // Not exit() to avoid running the atexit handlers
- // one of which being gcc --coverage handler which causes a hang
_Exit(WEXITSTATUS(stat_loc));
}
@@ -62,7 +67,6 @@ main(int argc, char *argv[])
int term_sig = SIGTERM;
const char *term_signame = "SIGTERM";
bool kill_child = true;
- int cmd_exit_timeout = CMD_EXIT_TIMEOUT;
char *arg = NULL;
@@ -184,8 +188,8 @@ main(int argc, char *argv[])
argc--;
struct sigaction sa = {
- .sa_handler = handle_sigchld,
- .sa_flags = 0,
+ .sa_handler = handle_sigchld,
+ .sa_flags = 0,
};
if(sigaction(SIGCHLD, &sa, NULL) != 0)
{
@@ -222,6 +226,8 @@ main(int argc, char *argv[])
}
}
+ timeout = true;
+
if(!kill_child)
{
return cmd_exit_timeout;