diff --git a/SOURCES/zsh-5.0.2-cmd-subst.patch b/SOURCES/zsh-5.0.2-cmd-subst.patch index a67f1a7..7bcd95d 100644 --- a/SOURCES/zsh-5.0.2-cmd-subst.patch +++ b/SOURCES/zsh-5.0.2-cmd-subst.patch @@ -1,7 +1,7 @@ From 6b8f3f9906ee44be46e022480b6e01755feeaa99 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 6 Jan 2015 17:05:17 +0000 -Subject: [PATCH 1/4] Fix command substitutions to parse contents as they are +Subject: [PATCH 1/5] Fix command substitutions to parse contents as they are read in. Do this by refactoring misnamed lexsave()/lexrestore() to allow @@ -829,10 +829,92 @@ index 5661b0a..a4c69a0 100644 2.4.3 +From 925112048811087520954e0c739b29371eee188a Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Thu, 8 Jan 2015 21:39:26 +0000 +Subject: [PATCH 2/5] Resolves: #1338689 - better initialize parser state + +This fix is isolated out from a huge upstream commit that includes major +code refactoring changes together with the initialization fix actually +needed to resolve #1338689. + +Upstream-commit: cfd91eac0732da8ece012ca4ab051d928a85c9dd +Signed-off-by: Kamil Dudka +--- + Src/hist.c | 5 +++++ + Src/parse.c | 20 ++++++++++++++++++-- + 2 files changed, 23 insertions(+), 2 deletions(-) + +diff --git a/Src/hist.c b/Src/hist.c +index 561e2ac..4ba61b1 100644 +--- a/Src/hist.c ++++ b/Src/hist.c +@@ -804,6 +804,11 @@ strinbeg(int dohist) + strin++; + hbegin(dohist); + lexinit(); ++ /* ++ * Also initialise some variables owned by the parser but ++ * used for communication between the parser and lexer. ++ */ ++ init_parse_status(); + } + + /* done reading a string */ +diff --git a/Src/parse.c b/Src/parse.c +index b0a7624..b3b004b 100644 +--- a/Src/parse.c ++++ b/Src/parse.c +@@ -358,6 +358,21 @@ ecstrcode(char *s) + } while (0) + + ++/**/ ++mod_export void ++init_parse_status(void) ++{ ++ /* ++ * These variables are currently declared by the parser, so we ++ * initialise them here. Possibly they are more naturally declared ++ * by the lexical anaylser; however, as they are used for signalling ++ * between the two it's a bit ambiguous. We clear them when ++ * using the lexical analyser for strings as well as here. ++ */ ++ incasepat = incond = inredir = infor = 0; ++ incmdpos = 1; ++} ++ + /* Initialise wordcode buffer. */ + + /**/ +@@ -372,6 +387,8 @@ init_parse(void) + ecsoffs = ecnpats = 0; + ecssub = 0; + ecnfunc = 0; ++ ++ init_parse_status(); + } + + /* Build eprog. */ +@@ -535,9 +552,8 @@ parse_list(void) + int c = 0; + + tok = ENDINPUT; +- incmdpos = 1; +- zshlex(); + init_parse(); ++ zshlex(); + par_list(&c); + if (tok != ENDINPUT) { + clear_hdocs(); +-- +2.5.5 + + From 00bc31b497525433dbaeafd3e7b92c7fe364dc8c Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 15 Apr 2015 10:20:06 +0100 -Subject: [PATCH 2/4] 34892 (slightly tweaked): math evaluation fix +Subject: [PATCH 3/5] 34892 (slightly tweaked): math evaluation fix An empty expression resulting from substitution includes a Nularg, which needs handling the same as an empty string. @@ -896,7 +978,7 @@ index 02d1519..33b03ef 100644 From 0c1450a286e578a1cfe266bf743faf2f0719f85b Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Wed, 29 Jul 2015 22:36:45 -0700 -Subject: [PATCH 3/4] 35953: fix handling of command substitution in math +Subject: [PATCH 4/5] 35953: fix handling of command substitution in math context Upstream-commit: c0a80171ee615b52a15a6fc8efe83c2bb53451d2 @@ -969,7 +1051,7 @@ index f04ddda..584ebd6 100644 From 821815bd9c24a84d8bb5796732ab6144b35e7d27 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sat, 10 Jan 2015 20:28:57 +0000 -Subject: [PATCH 4/4] 34220: new $(...) handling needs to back up over alias +Subject: [PATCH 5/5] 34220: new $(...) handling needs to back up over alias expansion Upstream-commit: 3b32abafdb019cfb8f29908bc3d148e01518981d diff --git a/SOURCES/zsh-5.0.2-malloc-signal.patch b/SOURCES/zsh-5.0.2-malloc-signal.patch new file mode 100644 index 0000000..de99f7d --- /dev/null +++ b/SOURCES/zsh-5.0.2-malloc-signal.patch @@ -0,0 +1,70 @@ +From 160c02c8071b8948231a229ec6247cf0792c389a Mon Sep 17 00:00:00 2001 +From: Filip Krska +Date: Tue, 20 Oct 2015 18:25:38 +0200 +Subject: [PATCH 1/2] lex.c: fix malloc() signal leak in lexsave() + +The bug appears not to affect upstream master, where the function + +lexsave(void) + ... 1x malloc, 1x zalloc + +was rewritten to + +lex_context_save(struct lex_stack *ls, int toplevel) + ... no *alloc at all + +Recheck of any possible malloc() signal leaks in current RHEL 6 zsh code needed. +--- + Src/lex.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Src/lex.c b/Src/lex.c +index 33f6430..0c7f539 100644 +--- a/Src/lex.c ++++ b/Src/lex.c +@@ -264,7 +264,7 @@ lexsave_partial(int parts) + { + struct lexstack *ls; + +- ls = (struct lexstack *)malloc(sizeof(struct lexstack)); ++ ls = (struct lexstack *)zalloc(sizeof(struct lexstack)); + + if (parts & ZCONTEXT_LEX) { + ls->incmdpos = incmdpos; +-- +2.5.2 + + +From 861e4cd5f8ba169f5f63ca1efffdc8ebac5a3d61 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Tue, 20 Oct 2015 18:27:15 +0200 +Subject: [PATCH 2/2] mem.c: queue signals while calling malloc() in realloc() + +Bug: https://bugzilla.redhat.com/1267903#c6 +--- + Src/mem.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/Src/mem.c b/Src/mem.c +index 9492a60..75622c6 100644 +--- a/Src/mem.c ++++ b/Src/mem.c +@@ -1513,8 +1513,13 @@ realloc(MALLOC_RET_T p, MALLOC_ARG_T size) + int i, l = 0; + + /* some system..., see above */ +- if (!p && size) +- return (MALLOC_RET_T) malloc(size); ++ if (!p && size) { ++ queue_signals(); ++ r = malloc(size); ++ unqueue_signals(); ++ return (MALLOC_RET_T) r; ++ } ++ + /* and some systems even do this... */ + if (!p || !size) + return (MALLOC_RET_T) p; +-- +2.5.2 + diff --git a/SOURCES/zsh-5.0.2-sigchld-deadlock.patch b/SOURCES/zsh-5.0.2-sigchld-deadlock.patch new file mode 100644 index 0000000..9c2ffbd --- /dev/null +++ b/SOURCES/zsh-5.0.2-sigchld-deadlock.patch @@ -0,0 +1,41 @@ +From 656bc77fe9eb1c8c3eabcbcda131c3cd4dbb3acd Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Mon, 10 Aug 2015 12:54:05 -0700 +Subject: [PATCH] 36079: do not allow update_job() and its helpers to run the + signal queue while we are processing a job exit. + +Upstream-commit: 93ca77f8f73bc58041bcbf8e4319b056504806e5 +Signed-off-by: Kamil Dudka +--- + Src/signals.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/Src/signals.c b/Src/signals.c +index 6b8b773..c539063 100644 +--- a/Src/signals.c ++++ b/Src/signals.c +@@ -485,6 +485,12 @@ wait_for_processes(void) + break; + } + ++ /* This is necessary to be sure queueing_enabled > 0 when ++ * we enter printjob() from update_job(), so that we don't ++ * decrement to zero in should_report_time() and improperly ++ * run other handlers in the middle of processing this one */ ++ queue_signals(); ++ + /* + * Find the process and job containing this pid and + * update it. +@@ -528,6 +534,8 @@ wait_for_processes(void) + if (jn && !(jn->stat & (STAT_CURSH|STAT_BUILTIN)) && + jn - jobtab != thisjob) + addbgstatus(pid, (int)lastval2); ++ ++ unqueue_signals(); + } + } + +-- +2.5.0 + diff --git a/SOURCES/zsh-5.0.2-signal-handling.patch b/SOURCES/zsh-5.0.2-signal-handling.patch new file mode 100644 index 0000000..b605a17 --- /dev/null +++ b/SOURCES/zsh-5.0.2-signal-handling.patch @@ -0,0 +1,870 @@ +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 + diff --git a/SPECS/zsh.spec b/SPECS/zsh.spec index 1f95f82..8edaccf 100644 --- a/SPECS/zsh.spec +++ b/SPECS/zsh.spec @@ -3,7 +3,7 @@ Summary: Powerful interactive shell Name: zsh Version: 5.0.2 -Release: 14%{?dist} +Release: 14%{?dist}.2 License: MIT URL: http://zsh.sourceforge.net/ Group: System Environment/Shells @@ -52,6 +52,15 @@ Patch14: zsh-5.0.2-ksh-syntax-check.patch # fix command substitutions to parse contents as they are read in (#1241023) Patch15: zsh-5.0.2-cmd-subst.patch +# fix malloc() signal leak in lexsave() (#1267912) +Patch16: zsh-5.0.2-malloc-signal.patch + +# queue signals while processing a job exit (#1291782) +Patch17: zsh-5.0.2-sigchld-deadlock.patch + +# signal-handling related fixes collected from upstream (#1198671) +Patch19: zsh-5.0.2-signal-handling.patch + BuildRequires: coreutils sed ncurses-devel libcap-devel BuildRequires: texinfo texi2html gawk hostname Requires(post): /sbin/install-info grep @@ -97,6 +106,9 @@ This package contains the Zsh manual in html format. %patch13 -p1 %patch14 -p1 %patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch19 -p1 cp -p %SOURCE7 . @@ -213,6 +225,14 @@ fi %doc Doc/*.html %changelog +* Wed May 25 2016 Kamil Dudka - 5.0.2-14.el7_2.2 +- fix parse error on a script with unescaped exclamation mark (#1338689) + +* Tue May 24 2016 Kamil Dudka - 5.0.2-14.el7_2.1 +- signal-handling related fixes collected from upstream (#1198671) +- queue signals while processing a job exit (#1291782) +- fix malloc() signal leak in lexsave() (#1267912) + * Fri Aug 14 2015 Kamil Dudka - 5.0.2-14 - fix alias handling in command substitution (#1253555)