[git commit branch/1_32_stable] ash: jobs: Fix infinite loop in waitproc

Denys Vlasenko vda.linux at googlemail.com
Fri Jan 1 13:30:58 UTC 2021


commit: https://git.busybox.net/busybox/commit/?id=e4c7cf3f8cc67bd2b9aeb4d622c38bad515b09a0
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/1_32_stable

Upstream commit:

    Date: Fri, 10 Apr 2020 21:03:09 +1000
    jobs: Fix infinite loop in waitproc

    After we changed the resetting of gotsigchld so that it is only
    done if jp is NULL, we can now get an infinite loop in waitproc
    if gotsigchld is set but there is no outstanding child because
    everything had been waited for previously without gotsigchld being
    zeroed.

    This patch fixes it by always zeroing gotsigchld as we did before.
    The bug that the previous patch was trying to fix is now resolved
    by switching the blocking mode to DOWAIT_NORMAL after the specified
    job has been completed so that we really do wait for all outstanding
    dead children.

    Reported-by: Harald van Dijk <harald at gigawatt.nl>
    Fixes: 6c691b3e5099 ("jobs: Only clear gotsigchld when waiting...")
    Signed-off-by: Herbert Xu <herbert at gondor.apana.org.au>

function                                             old     new   delta
dowait                                               553     631     +78

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/ash.c | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index ac25866ec..13470b2fa 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -4453,15 +4453,28 @@ waitone(int block, struct job *job)
 static int
 dowait(int block, struct job *jp)
 {
-	int pid = block == DOWAIT_NONBLOCK ? got_sigchld : 1;
+	smallint gotchld = *(volatile smallint *)&got_sigchld;
+	int rpid;
+	int pid;
+
+	if (jp && jp->state != JOBRUNNING)
+		block = DOWAIT_NONBLOCK;
+
+	if (block == DOWAIT_NONBLOCK && !gotchld)
+		return 1;
+
+	rpid = 1;
 
-	while (jp ? jp->state == JOBRUNNING : pid > 0) {
-		if (!jp)
-			got_sigchld = 0;
+	do {
+		got_sigchld = 0;
 		pid = waitone(block, jp);
-	}
+		rpid &= !!pid;
 
-	return pid;
+		if (!pid || (jp && jp->state != JOBRUNNING))
+			block = DOWAIT_NONBLOCK;
+	} while (pid >= 0);
+
+	return rpid;
 }
 
 #if JOBS


More information about the busybox-cvs mailing list