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
---
 tests/timeout.test   | 15 +++++++++++++++
 toys/other/timeout.c |  5 +++++
 2 files changed, 20 insertions(+)
From d2a6c75167884f1d3ed036aa4be73ac7c70bcda7 Mon Sep 17 00:00:00 2001
From: Elliott Hughes <[email protected]>
Date: Fri, 13 Sep 2019 15:33:04 -0700
Subject: [PATCH] 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
---
 tests/timeout.test   | 15 +++++++++++++++
 toys/other/timeout.c |  5 +++++
 2 files changed, 20 insertions(+)

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;
   }
 }
-- 
2.23.0.237.gc6a4ce50a0-goog

_______________________________________________
Toybox mailing list
[email protected]
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to