aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2020-02-18 14:28:30 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2020-02-18 14:28:30 +0100
commitd81af7216b3305a1aac211dc847dd1c191f3b307 (patch)
tree3ff0488dfe7ee89a7a5472c2f75e9c8cecc99554
parent22c75924daa41b7ea097796afd4baafa2fc99d05 (diff)
downloadbusybox-w32-d81af7216b3305a1aac211dc847dd1c191f3b307.tar.gz
busybox-w32-d81af7216b3305a1aac211dc847dd1c191f3b307.tar.bz2
busybox-w32-d81af7216b3305a1aac211dc847dd1c191f3b307.zip
ash: eval: Reap zombies after built-in commands and functions
Upstream commit: Date: Mon, 26 Mar 2018 23:55:50 +0800 eval: Reap zombies after built-in commands and functions Currently dash does not reap dead children after built-in commands or functions. This means that if you construct a loop consisting of solely built-in commands and functions, then zombies can hang around indefinitely. This patch fixes this by reaping when necessary after each built-in command and function. Reported-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/ash.c26
1 files changed, 10 insertions, 16 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 389db3cd0..8047cf98f 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -5355,10 +5355,10 @@ waitforjob(struct job *jp)
5355{ 5355{
5356 int st; 5356 int st;
5357 5357
5358 TRACE(("waitforjob(%%%d) called\n", jobno(jp))); 5358 TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0));
5359 5359
5360 INT_OFF; 5360 INT_OFF;
5361 while (jp->state == JOBRUNNING) { 5361 while ((jp && jp->state == JOBRUNNING) || got_sigchld) {
5362 /* In non-interactive shells, we _can_ get 5362 /* In non-interactive shells, we _can_ get
5363 * a keyboard signal here and be EINTRed, 5363 * a keyboard signal here and be EINTRed,
5364 * but we just loop back, waiting for command to complete. 5364 * but we just loop back, waiting for command to complete.
@@ -5393,6 +5393,8 @@ waitforjob(struct job *jp)
5393 } 5393 }
5394 INT_ON; 5394 INT_ON;
5395 5395
5396 if (!jp)
5397 return exitstatus;
5396 st = getstatus(jp); 5398 st = getstatus(jp);
5397#if JOBS 5399#if JOBS
5398 if (jp->jobctl) { 5400 if (jp->jobctl) {
@@ -10311,6 +10313,8 @@ evalcommand(union node *cmd, int flags)
10311 goto out; 10313 goto out;
10312 } 10314 }
10313 10315
10316 jp = NULL;
10317
10314 /* Execute the command. */ 10318 /* Execute the command. */
10315 switch (cmdentry.cmdtype) { 10319 switch (cmdentry.cmdtype) {
10316 default: { 10320 default: {
@@ -10365,7 +10369,6 @@ evalcommand(union node *cmd, int flags)
10365 jp = makejob(/*cmd,*/ 1); 10369 jp = makejob(/*cmd,*/ 1);
10366 if (forkshell(jp, cmd, FORK_FG) != 0) { 10370 if (forkshell(jp, cmd, FORK_FG) != 0) {
10367 /* parent */ 10371 /* parent */
10368 status = waitforjob(jp);
10369 INT_ON; 10372 INT_ON;
10370 TRACE(("forked child exited with %d\n", status)); 10373 TRACE(("forked child exited with %d\n", status));
10371 break; 10374 break;
@@ -10384,33 +10387,24 @@ evalcommand(union node *cmd, int flags)
10384 if (cmd_is_exec && argc > 1) 10387 if (cmd_is_exec && argc > 1)
10385 listsetvar(varlist.list, VEXPORT); 10388 listsetvar(varlist.list, VEXPORT);
10386 } 10389 }
10387
10388 /* Tight loop with builtins only:
10389 * "while kill -0 $child; do true; done"
10390 * will never exit even if $child died, unless we do this
10391 * to reap the zombie and make kill detect that it's gone: */
10392 dowait(DOWAIT_NONBLOCK, NULL);
10393
10394 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) { 10390 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
10395 if (exception_type == EXERROR && spclbltin <= 0) { 10391 if (exception_type == EXERROR && spclbltin <= 0) {
10396 FORCE_INT_ON; 10392 FORCE_INT_ON;
10397 goto readstatus; 10393 break;
10398 } 10394 }
10399 raise: 10395 raise:
10400 longjmp(exception_handler->loc, 1); 10396 longjmp(exception_handler->loc, 1);
10401 } 10397 }
10402 goto readstatus; 10398 break;
10403 10399
10404 case CMDFUNCTION: 10400 case CMDFUNCTION:
10405 /* See above for the rationale */
10406 dowait(DOWAIT_NONBLOCK, NULL);
10407 if (evalfun(cmdentry.u.func, argc, argv, flags)) 10401 if (evalfun(cmdentry.u.func, argc, argv, flags))
10408 goto raise; 10402 goto raise;
10409 readstatus:
10410 status = exitstatus;
10411 break; 10403 break;
10412 } /* switch */ 10404 } /* switch */
10413 10405
10406 status = waitforjob(jp);
10407
10414 out: 10408 out:
10415 if (cmd->ncmd.redirect) 10409 if (cmd->ncmd.redirect)
10416 popredir(/*drop:*/ cmd_is_exec); 10410 popredir(/*drop:*/ cmd_is_exec);