From bbeb06a37ba58f6905803d32a26fb00953459301 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Thu, 20 Mar 2014 07:56:30 -0700 Subject: [PATCH 1/8] 32500: handle interrupts during pattern matching Upstream-commit: 8672d19f0c0f25569e233bbd466b6c39f60c7a55 Signed-off-by: Kamil Dudka --- Src/pattern.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Src/pattern.c b/Src/pattern.c index b74a08a..b93b064 100644 --- a/Src/pattern.c +++ b/Src/pattern.c @@ -2128,6 +2128,8 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, return ret; } else { + int q = queue_signal_level(); + /* * Test for a `must match' string, unless we're scanning for a match * in which case we don't need to do this each time. @@ -2175,6 +2177,8 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, patinput = patinstart; + dont_queue_signals(); + if (patmatch((Upat)progstr)) { /* * we were lazy and didn't save the globflags if an exclusion @@ -2311,6 +2315,8 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, } else ret = 0; + restore_queue_signals(q); + if (tryalloced) zfree(tryalloced, unmetalen + unmetalenp); @@ -2390,7 +2396,7 @@ patmatch(Upat prog) zrange_t from, to, comp; patint_t nextch; - while (scan) { + while (scan && !errflag) { next = PATNEXT(scan); if (!globdots && P_NOTDOT(scan) && patinput == patinstart && -- 2.5.0 From c3eeba82d560005d830862dace8d771e712693e6 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sun, 9 Aug 2015 00:50:36 -0700 Subject: [PATCH 2/8] 36022 fix bug that some loop constructs could not be interrupted, revise signal queueing There are two underlying ideas here: (1) Keeping signals queued around anything that's doing memory management (including push/pop of the heap) has become crucial. (2) Anytime the shell is going to run a command, be it buitin or external, it must be both safe and necessary to process any queued signals, so that the apparent order of signal arrival and command execution is preserved. Upstream-commit: 9958684574bf8b0ecec6983cca57f3fa3dd7cd63 Signed-off-by: Kamil Dudka --- Src/exec.c | 43 ++++++++++++++++++++++++++++++++++++++----- Src/init.c | 5 +++++ Src/input.c | 9 +++++++++ Src/loop.c | 36 ++++++++++++++++++++++++++++++++++-- Src/parse.c | 8 ++++++++ Src/signals.c | 8 ++++++-- 6 files changed, 100 insertions(+), 9 deletions(-) diff --git a/Src/exec.c b/Src/exec.c index 7817a64..cff1a24 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1108,8 +1108,12 @@ execsimple(Estate state) fflush(xtrerr); } lv = (errflag ? errflag : cmdoutval); - } else + } else { + int q = queue_signal_level(); + dont_queue_signals(); lv = (execfuncs[code - WC_CURSH])(state, 0); + restore_queue_signals(q); + } thisjob = otj; @@ -1141,6 +1145,8 @@ execlist(Estate state, int dont_change_job, int exiting) */ int oldnoerrexit = noerrexit; + queue_signals(); + cj = thisjob; old_pline_level = pline_level; old_list_pipe = list_pipe; @@ -1391,6 +1397,8 @@ sublist_done: /* Make sure this doesn't get executed again. */ sigtrapped[SIGEXIT] = 0; } + + unqueue_signals(); } /* Execute a pipeline. * @@ -1419,6 +1427,14 @@ execpline(Estate state, wordcode slcode, int how, int last1) else if (slflags & WC_SUBLIST_NOT) last1 = 0; + /* If trap handlers are allowed to run here, they may start another + * external job in the middle of us starting this one, which can + * result in jobs being reaped before their job table entries have + * been initialized, which in turn leads to waiting forever for + * jobs that no longer exist. So don't do that. + */ + queue_signals(); + pj = thisjob; ipipe[0] = ipipe[1] = opipe[0] = opipe[1] = 0; child_block(); @@ -1431,6 +1447,7 @@ execpline(Estate state, wordcode slcode, int how, int last1) */ if ((thisjob = newjob = initjob()) == -1) { child_unblock(); + unqueue_signals(); return 1; } if (how & Z_TIMED) @@ -1486,6 +1503,7 @@ execpline(Estate state, wordcode slcode, int how, int last1) else spawnjob(); child_unblock(); + unqueue_signals(); /* Executing background code resets shell status */ return lastval = 0; } else { @@ -1543,15 +1561,18 @@ execpline(Estate state, wordcode slcode, int how, int last1) } if (!(jn->stat & STAT_LOCKED)) { updated = hasprocs(thisjob); - waitjobs(); + waitjobs(); /* deals with signal queue */ child_block(); } else updated = 0; if (!updated && list_pipe_job && hasprocs(list_pipe_job) && !(jobtab[list_pipe_job].stat & STAT_STOPPED)) { + int q = queue_signal_level(); child_unblock(); + dont_queue_signals(); child_block(); + restore_queue_signals(q); } if (list_pipe_child && jn->stat & STAT_DONE && @@ -1631,6 +1652,7 @@ execpline(Estate state, wordcode slcode, int how, int last1) break; } child_unblock(); + unqueue_signals(); if (list_pipe && (lastval & 0200) && pj >= 0 && (!(jn->stat & STAT_INUSE) || (jn->stat & STAT_DONE))) { @@ -3192,6 +3214,7 @@ execcmd(Estate state, int input, int output, int how, int last1) fflush(xtrerr); } } else if (isset(EXECOPT) && !errflag) { + int q = queue_signal_level(); /* * We delay the entersubsh() to here when we are exec'ing * the current shell (including a fake exec to run a builtin then @@ -3210,7 +3233,9 @@ execcmd(Estate state, int input, int output, int how, int last1) if (type >= WC_CURSH) { if (last1 == 1) do_exec = 1; + dont_queue_signals(); lastval = (execfuncs[type - WC_CURSH])(state, do_exec); + restore_queue_signals(q); } else if (is_builtin || is_shfunc) { LinkList restorelist = 0, removelist = 0; /* builtin or shell function */ @@ -3269,7 +3294,9 @@ execcmd(Estate state, int input, int output, int how, int last1) /* It's a builtin */ if (forked) closem(FDT_INTERNAL); + dont_queue_signals(); lastval = execbuiltin(args, (Builtin) hn); + restore_queue_signals(q); #ifdef PATH_DEV_FD closem(FDT_PROC_SUBST); #endif @@ -4415,11 +4442,9 @@ execshfunc(Shfunc shf, LinkList args) if ((osfc = sfcontext) == SFC_NONE) sfcontext = SFC_DIRECT; xtrerr = stderr; - unqueue_signals(); doshfunc(shf, args, 0); - queue_signals(); sfcontext = osfc; free(cmdstack); cmdstack = ocs; @@ -4614,6 +4639,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) static int funcdepth; #endif + queue_signals(); /* Lots of memory and global state changes coming */ + pushheap(); oargv0 = NULL; @@ -4814,6 +4841,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) } popheap(); + unqueue_signals(); + if (exit_pending) { if (locallevel > forklevel) { /* Still functions to return: force them to do so. */ @@ -4844,6 +4873,8 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name) int cont, ouu; char *ou; + queue_signals(); + ou = zalloc(ouu = underscoreused); if (ou) memcpy(ou, zunderscore, underscoreused); @@ -4865,12 +4896,14 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name) wrap = wrap->next; } startparamscope(); - execode(prog, 1, 0, "shfunc"); + execode(prog, 1, 0, "shfunc"); /* handles signal unqueueing */ if (ou) { setunderscore(ou); zfree(ou, ouu); } endparamscope(); + + unqueue_signals(); } /* Search fpath for an undefined function. Finds the file, and returns the * diff --git a/Src/init.c b/Src/init.c index 78f171d..df42349 100644 --- a/Src/init.c +++ b/Src/init.c @@ -105,6 +105,7 @@ loop(int toplevel, int justonce) Eprog prog; int err, non_empty = 0; + queue_signals(); pushheap(); if (!toplevel) lexsave(); @@ -118,7 +119,9 @@ loop(int toplevel, int justonce) if (interact && toplevel) { int hstop = stophist; stophist = 3; + unqueue_signals(); preprompt(); + queue_signals(); if (stophist != 3) hbegin(1); else @@ -197,6 +200,7 @@ loop(int toplevel, int justonce) if (((!interact || sourcelevel) && errflag) || retflag) break; if (isset(SINGLECOMMAND) && toplevel) { + dont_queue_signals(); if (sigtrapped[SIGEXIT]) dotrap(SIGEXIT); exit(lastval); @@ -208,6 +212,7 @@ loop(int toplevel, int justonce) if (!toplevel) lexrestore(); popheap(); + unqueue_signals(); if (err) return LOOP_ERROR; diff --git a/Src/input.c b/Src/input.c index 5b782dc..dcff78a 100644 --- a/Src/input.c +++ b/Src/input.c @@ -140,14 +140,17 @@ shingetline(void) int c; char buf[BUFSIZ]; char *p; + int q = queue_signal_level(); p = buf; for (;;) { + dont_queue_signals(); do { errno = 0; c = fgetc(bshin); } while (c < 0 && errno == EINTR); if (c < 0 || c == '\n') { + restore_queue_signals(q); if (c == '\n') *p++ = '\n'; if (p > buf) { @@ -163,11 +166,13 @@ shingetline(void) } else *p++ = c; if (p >= buf + BUFSIZ - 1) { + queue_signals(); line = zrealloc(line, ll + (p - buf) + 1); memcpy(line + ll, buf, p - buf); ll += p - buf; line[ll] = '\0'; p = buf; + unqueue_signals(); } } } @@ -340,6 +345,8 @@ inputline(void) static void inputsetline(char *str, int flags) { + queue_signals(); + if ((inbufflags & INP_FREE) && inbuf) { free(inbuf); } @@ -357,6 +364,8 @@ inputsetline(char *str, int flags) else inbufct = inbufleft; inbufflags = flags; + + unqueue_signals(); } /* diff --git a/Src/loop.c b/Src/loop.c index 90a0761..0c07c73 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -56,6 +56,10 @@ execfor(Estate state, int do_exec) char *name, *str, *cond = NULL, *advance = NULL; zlong val = 0; LinkList vars = NULL, args = NULL; + int old_simple_pline = simple_pline; + + /* See comments in execwhile() */ + simple_pline = 1; end = state->pc + WC_FOR_SKIP(code); @@ -73,6 +77,7 @@ execfor(Estate state, int do_exec) matheval(str); if (errflag) { state->pc = end; + simple_pline = old_simple_pline; return lastval = errflag; } cond = ecgetstr(state, EC_NODUP, &ctok); @@ -85,6 +90,7 @@ execfor(Estate state, int do_exec) if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { state->pc = end; + simple_pline = old_simple_pline; return 0; } if (htok) @@ -190,6 +196,7 @@ execfor(Estate state, int do_exec) popheap(); cmdpop(); loops--; + simple_pline = old_simple_pline; state->pc = end; return lastval; } @@ -206,6 +213,10 @@ execselect(Estate state, UNUSED(int do_exec)) FILE *inp; size_t more; LinkList args; + int old_simple_pline = simple_pline; + + /* See comments in execwhile() */ + simple_pline = 1; end = state->pc + WC_FOR_SKIP(code); name = ecgetstr(state, EC_NODUP, NULL); @@ -221,6 +232,7 @@ execselect(Estate state, UNUSED(int do_exec)) if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { state->pc = end; + simple_pline = old_simple_pline; return 0; } if (htok) @@ -228,6 +240,7 @@ execselect(Estate state, UNUSED(int do_exec)) } if (!args || empty(args)) { state->pc = end; + simple_pline = old_simple_pline; return 1; } loops++; @@ -301,6 +314,7 @@ execselect(Estate state, UNUSED(int do_exec)) popheap(); fclose(inp); loops--; + simple_pline = old_simple_pline; state->pc = end; return lastval; } @@ -368,6 +382,7 @@ execwhile(Estate state, UNUSED(int do_exec)) Wordcode end, loop; wordcode code = state->pc[-1]; int olderrexit, oldval, isuntil = (WC_WHILE_TYPE(code) == WC_WHILE_UNTIL); + int old_simple_pline = simple_pline; end = state->pc + WC_WHILE_SKIP(code); olderrexit = noerrexit; @@ -382,8 +397,6 @@ execwhile(Estate state, UNUSED(int do_exec)) /* This is an empty loop. Make sure the signal handler sets the * flags and then just wait for someone hitting ^C. */ - int old_simple_pline = simple_pline; - simple_pline = 1; while (!breaks) @@ -395,7 +408,14 @@ execwhile(Estate state, UNUSED(int do_exec)) for (;;) { state->pc = loop; noerrexit = 1; + + /* In case the test condition is a functional no-op, + * make sure signal handlers recognize ^C to end the loop. */ + simple_pline = 1; + execlist(state, 1, 0); + + simple_pline = old_simple_pline; noerrexit = olderrexit; if (!((lastval == 0) ^ isuntil)) { if (breaks) @@ -407,7 +427,14 @@ execwhile(Estate state, UNUSED(int do_exec)) lastval = oldval; break; } + + /* In case the loop body is also a functional no-op, + * make sure signal handlers recognize ^C as above. */ + simple_pline = 1; + execlist(state, 1, 0); + + simple_pline = old_simple_pline; if (breaks) { breaks--; if (breaks || !contflag) @@ -438,6 +465,10 @@ execrepeat(Estate state, UNUSED(int do_exec)) wordcode code = state->pc[-1]; int count, htok = 0; char *tmp; + int old_simple_pline = simple_pline; + + /* See comments in execwhile() */ + simple_pline = 1; end = state->pc + WC_REPEAT_SKIP(code); @@ -470,6 +501,7 @@ execrepeat(Estate state, UNUSED(int do_exec)) cmdpop(); popheap(); loops--; + simple_pline = old_simple_pline; state->pc = end; return lastval; } diff --git a/Src/parse.c b/Src/parse.c index b0a7624..04d2707 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -379,6 +379,8 @@ init_parse_status(void) void init_parse(void) { + queue_signals(); + if (ecbuf) zfree(ecbuf, eclen); ecbuf = (Wordcode) zalloc((eclen = EC_INIT_SIZE) * sizeof(wordcode)); @@ -389,6 +391,8 @@ init_parse(void) ecnfunc = 0; init_parse_status(); + + unqueue_signals(); } /* Build eprog. */ @@ -409,6 +413,8 @@ bld_eprog(void) Eprog ret; int l; + queue_signals(); + ecadd(WCB_END()); ret = (Eprog) zhalloc(sizeof(*ret)); @@ -431,6 +437,8 @@ bld_eprog(void) zfree(ecbuf, eclen); ecbuf = NULL; + unqueue_signals(); + return ret; } diff --git a/Src/signals.c b/Src/signals.c index c539063..73b41b1 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -1194,6 +1194,8 @@ dotrapargs(int sig, int *sigtr, void *sigfn) } } + queue_signals(); /* Any time we manage memory or global state */ + intrap++; *sigtr |= ZSIG_IGNORED; @@ -1231,7 +1233,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn) sfcontext = SFC_SIGNAL; incompfunc = 0; - doshfunc((Shfunc)sigfn, args, 1); + doshfunc((Shfunc)sigfn, args, 1); /* manages signal queueing */ sfcontext = osc; incompfunc= old_incompfunc; freelinklist(args, (FreeFunc) NULL); @@ -1241,7 +1243,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn) trap_state = TRAP_STATE_PRIMED; trapisfunc = isfunc = 0; - execode((Eprog)sigfn, 1, 0, "trap"); + execode((Eprog)sigfn, 1, 0, "trap"); /* manages signal queueing */ } runhookdef(AFTERTRAPHOOK, NULL); @@ -1286,6 +1288,8 @@ dotrapargs(int sig, int *sigtr, void *sigfn) if (*sigtr != ZSIG_IGNORED) *sigtr &= ~ZSIG_IGNORED; intrap--; + + unqueue_signals(); } /* Standard call to execute a trap for a given signal. */ -- 2.5.0 From 33905958a1b94e83ca1c32bc6849906da94b91a6 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sun, 9 Aug 2015 17:37:23 -0700 Subject: [PATCH 3/8] 36033: a few more queue_signals() to protect global state changes Upstream-commit: df5f825538720a9422859200d58d075d1dd075fc Signed-off-by: Kamil Dudka --- Src/glob.c | 4 ++++ Src/pattern.c | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Src/glob.c b/Src/glob.c index ca2ffaf..9135fce 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -213,22 +213,26 @@ static struct globdata curglobdata; #define save_globstate(N) \ do { \ + queue_signals(); \ memcpy(&(N), &curglobdata, sizeof(struct globdata)); \ (N).gd_pathpos = pathpos; \ (N).gd_pathbuf = pathbuf; \ (N).gd_glob_pre = glob_pre; \ (N).gd_glob_suf = glob_suf; \ pathbuf = NULL; \ + unqueue_signals(); \ } while (0) #define restore_globstate(N) \ do { \ + queue_signals(); \ zfree(pathbuf, pathbufsz); \ memcpy(&curglobdata, &(N), sizeof(struct globdata)); \ pathpos = (N).gd_pathpos; \ pathbuf = (N).gd_pathbuf; \ glob_pre = (N).gd_glob_pre; \ glob_suf = (N).gd_glob_suf; \ + unqueue_signals(); \ } while (0) /* pathname component in filename patterns */ diff --git a/Src/pattern.c b/Src/pattern.c index b74a08a..52774c0 100644 --- a/Src/pattern.c +++ b/Src/pattern.c @@ -452,6 +452,8 @@ patcompile(char *exp, int inflags, char **endexp) char *lng, *strp = NULL; Patprog p; + queue_signals(); + startoff = sizeof(struct patprog); /* Ensure alignment of start of program string */ startoff = (startoff + sizeof(union upat) - 1) & ~(sizeof(union upat) - 1); @@ -521,8 +523,10 @@ patcompile(char *exp, int inflags, char **endexp) if (!strp || (*strp && *strp != '/')) { /* No, do normal compilation. */ strp = NULL; - if (patcompswitch(0, &flags) == 0) + if (patcompswitch(0, &flags) == 0) { + unqueue_signals(); return NULL; + } } else { /* * Yes, copy the string, and skip compilation altogether. @@ -654,6 +658,8 @@ patcompile(char *exp, int inflags, char **endexp) if (endexp) *endexp = patparse; + + unqueue_signals(); return p; } -- 2.5.0 From bba38460c88c36fb529ee7494570cb2cfc68641a Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 10 Aug 2015 16:59:55 +0100 Subject: [PATCH 4/8] Don't rely on implicit value when saving background process status Upstream-commit: a07f74fadd1180b42258d1fcec5359afe3f9ba00 Signed-off-by: Kamil Dudka --- Src/signals.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Src/signals.c b/Src/signals.c index 73b41b1..2e7304f 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -533,7 +533,14 @@ wait_for_processes(void) */ if (jn && !(jn->stat & (STAT_CURSH|STAT_BUILTIN)) && jn - jobtab != thisjob) - addbgstatus(pid, (int)lastval2); + { + int val = (WIFSIGNALED(status) ? + 0200 | WTERMSIG(status) : + (WIFSTOPPED(status) ? + 0200 | WEXITSTATUS(status) : + WEXITSTATUS(status))); + addbgstatus(pid, val); + } unqueue_signals(); } -- 2.5.0 From 530b59d58273c9f11cd1443c0865f6420eafcbf0 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Tue, 11 Aug 2015 08:44:15 -0700 Subject: [PATCH 5/8] 36090: keep signals queued for preprompt() Upstream-commit: 1af2e6e02d5cb8ca8d11f107b670cddfd10a7e81 Signed-off-by: Kamil Dudka --- Src/init.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/Src/init.c b/Src/init.c index df42349..ca616d3 100644 --- a/Src/init.c +++ b/Src/init.c @@ -119,9 +119,7 @@ loop(int toplevel, int justonce) if (interact && toplevel) { int hstop = stophist; stophist = 3; - unqueue_signals(); preprompt(); - queue_signals(); if (stophist != 3) hbegin(1); else -- 2.5.0 From b2994c9f3ef36c3ee3286a08736da1e2c8d65f0b Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Tue, 11 Aug 2015 08:53:12 -0700 Subject: [PATCH 6/8] 36104: change order of child_block() and dont_queue_signals() to resolve yet another race condition Upstream-commit: 128bf385b1e8256e412d732fa9b80ecd7c5e2c73 Signed-off-by: Kamil Dudka --- Src/exec.c | 2 +- Src/jobs.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Src/exec.c b/Src/exec.c index cff1a24..70e2279 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1570,8 +1570,8 @@ execpline(Estate state, wordcode slcode, int how, int last1) !(jobtab[list_pipe_job].stat & STAT_STOPPED)) { int q = queue_signal_level(); child_unblock(); - dont_queue_signals(); child_block(); + dont_queue_signals(); restore_queue_signals(q); } if (list_pipe_child && diff --git a/Src/jobs.c b/Src/jobs.c index 24b8494..e711a9b 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -1312,9 +1312,9 @@ zwaitjob(int job, int wait_cmd) int q = queue_signal_level(); Job jn = jobtab + job; - dont_queue_signals(); child_block(); /* unblocked during signal_suspend() */ queue_traps(wait_cmd); + dont_queue_signals(); if (jn->procs || jn->auxprocs) { /* if any forks were done */ jn->stat |= STAT_LOCKED; if (jn->stat & STAT_CHANGED) @@ -1350,9 +1350,9 @@ zwaitjob(int job, int wait_cmd) pipestats[0] = lastval; numpipestats = 1; } + restore_queue_signals(q); unqueue_traps(); child_unblock(); - restore_queue_signals(q); return 0; } -- 2.5.0 From 6a0fd02f08972875cc138e783e28515a5c7a7e04 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sat, 15 Aug 2015 10:15:30 -0700 Subject: [PATCH 7/8] 36180: avoid infinite job stop/continue loop on "wait PID" for a background job Upstream-commit: 5d019f426af8b2a600ee03e43782c24b357d1401 Signed-off-by: Kamil Dudka --- Src/jobs.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Src/jobs.c b/Src/jobs.c index e711a9b..9b94a1f 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -1276,10 +1276,17 @@ waitforpid(pid_t pid, int wait_cmd) dont_queue_signals(); child_block(); /* unblocked in signal_suspend() */ queue_traps(wait_cmd); + + /* This function should never be called with a pid that is not a + * child of the current shell. Consequently, if kill(0, pid) + * fails here with ESRCH, the child has already been reaped. In + * the loop body, we expect this to happen in signal_suspend() + * via zhandler(), after which this test terminates the loop. + */ while (!errflag && (kill(pid, 0) >= 0 || errno != ESRCH)) { if (first) first = 0; - else + else if (!wait_cmd) kill(pid, SIGCONT); last_signal = -1; -- 2.5.0 From d184dd8673c93d35855b4a04613ae09277214df5 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Wed, 2 Sep 2015 19:11:54 -0700 Subject: [PATCH 8/8] 36393: process queued signals during dotrap() Upstream-commit: 9f5dffa1f33ec43c306bdf3c87cebba5fcc95b64 Signed-off-by: Kamil Dudka --- Src/signals.c | 5 +++++ Test/A05execution.ztst | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/Src/signals.c b/Src/signals.c index 2e7304f..dbc84af 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -1306,6 +1306,7 @@ void dotrap(int sig) { void *funcprog; + int q = queue_signal_level(); if (sigtrapped[sig] & ZSIG_FUNC) { HashNode hn = gettrapnode(sig, 0); @@ -1328,5 +1329,9 @@ dotrap(int sig) if ((sigtrapped[sig] & ZSIG_IGNORED) || !funcprog || errflag) return; + dont_queue_signals(); + dotrapargs(sig, sigtrapped+sig, funcprog); + + restore_queue_signals(q); } diff --git a/Test/A05execution.ztst b/Test/A05execution.ztst index 77c569c..3b39c75 100644 --- a/Test/A05execution.ztst +++ b/Test/A05execution.ztst @@ -203,3 +203,12 @@ 1:The status of recently exited background jobs is recorded >3 >2 + +# Regression test for workers/36392 + print -u $ZTST_fd 'This test takes 3 seconds and hangs the shell when it fails...' + callfromchld() { true && { print CHLD } } + TRAPCHLD() { callfromchld } + sleep 2 & sleep 3; print OK +0:Background job exit does not affect reaping foreground job +>CHLD +>OK -- 2.5.0