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