diff options
author | Elliott Hughes <enh@google.com> | 2019-09-13 15:33:04 -0700 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2019-09-13 21:11:45 -0500 |
commit | 38509d0e217d57d9b7fb18727bd02277cd205566 (patch) | |
tree | 500d34b67fe16b9473bd042e1486b2e0006abd85 | |
parent | dd155a3ba5aae70c0bc0590fd82ed5d7e3a76a22 (diff) | |
download | toybox-38509d0e217d57d9b7fb18727bd02277cd205566.tar.gz |
timeout: fix exit status for sneaky subprocesses.
There's nothing to stop a subprocess from catching our SIGTERM on timeout
and exiting, causing us to incorrectly report that it didn't time out.
Android's ART has a utility that does exactly this.
Explicitly catch this case, and add corresponding tests.
Bug: http://b/141007616
-rw-r--r-- | tests/timeout.test | 15 | ||||
-rw-r--r-- | toys/other/timeout.c | 5 |
2 files changed, 20 insertions, 0 deletions
diff --git a/tests/timeout.test b/tests/timeout.test index 189b592a..18f93790 100644 --- a/tests/timeout.test +++ b/tests/timeout.test @@ -18,3 +18,18 @@ testcmd "exit 1" '.1 false ; echo $?' '1\n' '' '' testcmd "--preserve-status" '--preserve-status .1 sleep 100 ; echo $?' '143\n' '' '' testcmd "--preserve-status killed" '--preserve-status -s 9 .1 sleep 100 ; echo $?' '137\n' '' '' + +# There's another special case where if the subprocess catches our timeout +# signal and exits, we need to report that as a timeout (unless overridden). +cat > loop.sh <<EOF +#!/bin/sh +trap "exit 3" SIGTERM +while true; do + : +done +EOF +chmod a+x loop.sh +testcmd "trap-and-exit" '1 ./loop.sh ; echo $?' '124\n' '' '' +testcmd "trap-and-exit --preserve-status" \ + '--preserve-status 1 ./loop.sh ; echo $?' '3\n' '' '' +rm loop.sh diff --git a/toys/other/timeout.c b/toys/other/timeout.c index dc48f55b..69b4995b 100644 --- a/toys/other/timeout.c +++ b/toys/other/timeout.c @@ -35,6 +35,7 @@ GLOBALS( pid_t pid; struct timeval ktv; struct itimerval itv; + int signaled; ) static void handler(int i) @@ -43,6 +44,7 @@ static void handler(int i) fprintf(stderr, "timeout pid %d signal %d\n", TT.pid, TT.nextsig); kill(TT.pid, TT.nextsig); + if (TT.nextsig != SIGKILL) TT.signaled++; if (TT.k) { TT.k = 0; @@ -88,5 +90,8 @@ void timeout_main(void) if (WIFEXITED(status)) toys.exitval = WEXITSTATUS(status); else if (WTERMSIG(status)==SIGKILL) toys.exitval = 137; else toys.exitval = FLAG(preserve_status) ? 128+WTERMSIG(status) : 124; + + // This is visible if the subprocess catches our timeout signal and exits. + if (TT.signaled && !FLAG(preserve_status)) toys.exitval = 124; } } |