diff --git a/SOURCES/zsh-5.0.2-close-fd.patch b/SOURCES/zsh-5.0.2-close-fd.patch new file mode 100644 index 0000000..ddd233b --- /dev/null +++ b/SOURCES/zsh-5.0.2-close-fd.patch @@ -0,0 +1,97 @@ +From 4f4fc498361ea9965fde31c36cf9971a92479e9f Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Tue, 20 Jan 2015 09:29:22 +0000 +Subject: [PATCH 1/2] users/19751: remove error on failure to close file + descriptor by number. + +Keep it when closing file descriptor stored in a variable, i.e. +explicitly opened by the user. + +Upstream-commit: e6d964246700581fe22ea834b2ea12dd301e8c3d +Signed-off-by: Kamil Dudka +--- + Src/exec.c | 7 ++++++- + Test/A04redirect.ztst | 10 ++++++---- + 2 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/Src/exec.c b/Src/exec.c +index 1a4ffe2..fcdc645 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -3075,7 +3075,12 @@ execcmd(Estate state, int input, int output, int how, int last1) + } + if (fn->fd1 < 10) + closemn(mfds, fn->fd1); +- if (!closed && zclose(fn->fd1) < 0) { ++ /* ++ * Only report failures to close file descriptors ++ * if they're under user control as we don't know ++ * what the previous status of others was. ++ */ ++ if (!closed && zclose(fn->fd1) < 0 && fn->varid) { + zwarn("failed to close file descriptor %d: %e", + fn->fd1, errno); + } +diff --git a/Test/A04redirect.ztst b/Test/A04redirect.ztst +index b8086e7..2f21b95 100644 +--- a/Test/A04redirect.ztst ++++ b/Test/A04redirect.ztst +@@ -152,11 +152,13 @@ + >hello + >goodbye + +- ({ exec 3<&- } 2>/dev/null +- exec 3<&- +- read foo <&-) ++ (exec {varid}<&0 ++ exec {varid}<&- ++ print About to close a second time >&2 ++ read {varid}<&-) + 1:'<&-' redirection +-*?\(eval\):*: failed to close file descriptor 3:* ++?About to close a second time ++*?\(eval\):*: failed to close file descriptor * + + print foo >&- + 0:'>&-' redirection +-- +2.4.0 + + +From 73ea1de52de3f078ef4e6f96ae5042cfe5e79730 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Tue, 20 Jan 2015 11:53:42 +0000 +Subject: [PATCH 2/2] users/19756: test for case of closing fd with no error + message + +Upstream-commit: 638bfa93a009987e57bd7eaa8b2a1c1067a3652a +Signed-off-by: Kamil Dudka +--- + Test/A04redirect.ztst | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/Test/A04redirect.ztst b/Test/A04redirect.ztst +index 2f21b95..70c210d 100644 +--- a/Test/A04redirect.ztst ++++ b/Test/A04redirect.ztst +@@ -152,11 +152,16 @@ + >hello + >goodbye + ++ ({exec 3<&- } 2>/dev/null ++ exec 3<&- ++ read foo <&-) ++1:'<&-' redirection with numeric fd (no error message on failure) ++ + (exec {varid}<&0 + exec {varid}<&- + print About to close a second time >&2 + read {varid}<&-) +-1:'<&-' redirection ++1:'<&-' redirection with fd in variable (error message on failure) + ?About to close a second time + *?\(eval\):*: failed to close file descriptor * + +-- +2.4.0 + diff --git a/SOURCES/zsh-5.0.2-cmd-subst.patch b/SOURCES/zsh-5.0.2-cmd-subst.patch new file mode 100644 index 0000000..a67f1a7 --- /dev/null +++ b/SOURCES/zsh-5.0.2-cmd-subst.patch @@ -0,0 +1,1000 @@ +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 + read in. + +Do this by refactoring misnamed lexsave()/lexrestore() to allow +continuity of history and input. + +Add test. + +Upstream-commit: c0d01a6fe0c67911650730cf13a2b9a0db16e59b +Signed-off-by: Kamil Dudka +--- + Src/init.c | 3 +- + Src/input.c | 13 +- + Src/lex.c | 498 ++++++++++++++++++++++++++++++++------------------ + Src/parse.c | 29 ++- + Src/zsh.h | 9 + + Test/D08cmdsubst.ztst | 42 +++++ + 6 files changed, 401 insertions(+), 193 deletions(-) + +diff --git a/Src/init.c b/Src/init.c +index 0742a9f..78f171d 100644 +--- a/Src/init.c ++++ b/Src/init.c +@@ -129,7 +129,8 @@ loop(int toplevel, int justonce) + use_exit_printed = 0; + intr(); /* interrupts on */ + lexinit(); /* initialize lexical state */ +- if (!(prog = parse_event())) { /* if we couldn't parse a list */ ++ if (!(prog = parse_event(ENDINPUT))) { ++ /* if we couldn't parse a list */ + hend(NULL); + if ((tok == ENDINPUT && !errflag) || + (tok == LEXERR && (!isset(SHINSTDIN) || !toplevel)) || +diff --git a/Src/input.c b/Src/input.c +index 5cff22d..1579762 100644 +--- a/Src/input.c ++++ b/Src/input.c +@@ -175,12 +175,12 @@ shingetline(void) + /* Get the next character from the input. + * Will call inputline() to get a new line where necessary. + */ +- ++ + /**/ + int + ingetc(void) + { +- int lastc; ++ int lastc = ' '; + + if (lexstop) + return ' '; +@@ -192,7 +192,7 @@ ingetc(void) + continue; + if (((inbufflags & INP_LINENO) || !strin) && lastc == '\n') + lineno++; +- return lastc; ++ break; + } + + /* +@@ -204,7 +204,7 @@ ingetc(void) + */ + if (!inbufct && (strin || errflag)) { + lexstop = 1; +- return ' '; ++ break; + } + /* If the next element down the input stack is a continuation of + * this, use it. +@@ -215,8 +215,10 @@ ingetc(void) + } + /* As a last resort, get some more input */ + if (inputline()) +- return ' '; ++ break; + } ++ zshlex_raw_add(lastc); ++ return lastc; + } + + /* Read a line from the current command stream and store it as input */ +@@ -421,6 +423,7 @@ inungetc(int c) + inbufleft = 0; + inbuf = inbufptr = ""; + } ++ zshlex_raw_back(); + } + } + +diff --git a/Src/lex.c b/Src/lex.c +index 82bf848..bcceda6 100644 +--- a/Src/lex.c ++++ b/Src/lex.c +@@ -146,6 +146,16 @@ mod_export int parend; + /**/ + mod_export int nocomments; + ++/* add raw input characters while parsing command substitution */ ++ ++/**/ ++static int lex_add_raw; ++ ++/* variables associated with the above */ ++ ++static char *tokstr_raw, *bptr_raw; ++static int len_raw, bsiz_raw; ++ + /* text of punctuation tokens */ + + /**/ +@@ -214,6 +224,11 @@ struct lexstack { + char *bptr; + int bsiz; + int len; ++ int lex_add_raw; ++ char *tokstr_raw; ++ char *bptr_raw; ++ int bsiz_raw; ++ int len_raw; + short *chwords; + int chwordlen; + int chwordpos; +@@ -239,89 +254,121 @@ struct lexstack { + + static struct lexstack *lstack = NULL; + +-/* save the lexical state */ ++/* save the context or parts thereof */ + + /* is this a hack or what? */ + + /**/ + mod_export void +-lexsave(void) ++lexsave_partial(int parts) + { + struct lexstack *ls; + + ls = (struct lexstack *)malloc(sizeof(struct lexstack)); + +- ls->incmdpos = incmdpos; +- ls->incond = incond; +- ls->incasepat = incasepat; +- ls->dbparens = dbparens; +- ls->isfirstln = isfirstln; +- ls->isfirstch = isfirstch; +- ls->histactive = histactive; +- ls->histdone = histdone; +- ls->lexflags = lexflags; +- ls->stophist = stophist; +- stophist = 0; +- if (!lstack) { +- /* top level, make this version visible to ZLE */ +- zle_chline = chline; +- /* ensure line stored is NULL-terminated */ +- if (hptr) +- *hptr = '\0'; ++ if (parts & ZCONTEXT_LEX) { ++ ls->incmdpos = incmdpos; ++ ls->incond = incond; ++ ls->incasepat = incasepat; ++ ls->dbparens = dbparens; ++ ls->isfirstln = isfirstln; ++ ls->isfirstch = isfirstch; ++ ls->lexflags = lexflags; ++ ++ ls->tok = tok; ++ ls->isnewlin = isnewlin; ++ ls->tokstr = tokstr; ++ ls->zshlextext = zshlextext; ++ ls->bptr = bptr; ++ ls->bsiz = bsiz; ++ ls->len = len; ++ ls->lex_add_raw = lex_add_raw; ++ ls->tokstr_raw = tokstr_raw; ++ ls->bptr_raw = bptr_raw; ++ ls->bsiz_raw = bsiz_raw; ++ ls->len_raw = len_raw; ++ ls->lexstop = lexstop; ++ ls->toklineno = toklineno; ++ ++ tokstr = zshlextext = bptr = NULL; ++ bsiz = 256; ++ tokstr_raw = bptr_raw = NULL; ++ bsiz_raw = len_raw = lex_add_raw = 0; ++ ++ inredir = 0; ++ } ++ if (parts & ZCONTEXT_HIST) { ++ if (!lstack) { ++ /* top level, make this version visible to ZLE */ ++ zle_chline = chline; ++ /* ensure line stored is NULL-terminated */ ++ if (hptr) ++ *hptr = '\0'; ++ } ++ ls->histactive = histactive; ++ ls->histdone = histdone; ++ ls->stophist = stophist; ++ ls->hline = chline; ++ ls->hptr = hptr; ++ ls->chwords = chwords; ++ ls->chwordlen = chwordlen; ++ ls->chwordpos = chwordpos; ++ ls->hwgetword = hwgetword; ++ ls->hgetc = hgetc; ++ ls->hungetc = hungetc; ++ ls->hwaddc = hwaddc; ++ ls->hwbegin = hwbegin; ++ ls->hwend = hwend; ++ ls->addtoline = addtoline; ++ ls->hlinesz = hlinesz; ++ /* ++ * We save and restore the command stack with history ++ * as it's visible to the user interactively, so if ++ * we're preserving history state we'll continue to ++ * show the current set of commands from input. ++ */ ++ ls->cstack = cmdstack; ++ ls->csp = cmdsp; ++ ++ stophist = 0; ++ chline = NULL; ++ hptr = NULL; ++ histactive = 0; ++ cmdstack = (unsigned char *)zalloc(CMDSTACKSZ); ++ cmdsp = 0; ++ } ++ if (parts & ZCONTEXT_PARSE) { ++ ls->hdocs = hdocs; ++ ls->eclen = eclen; ++ ls->ecused = ecused; ++ ls->ecnpats = ecnpats; ++ ls->ecbuf = ecbuf; ++ ls->ecstrs = ecstrs; ++ ls->ecsoffs = ecsoffs; ++ ls->ecssub = ecssub; ++ ls->ecnfunc = ecnfunc; ++ ecbuf = NULL; ++ hdocs = NULL; + } +- ls->hline = chline; +- chline = NULL; +- ls->hptr = hptr; +- hptr = NULL; +- ls->hlinesz = hlinesz; +- ls->cstack = cmdstack; +- ls->csp = cmdsp; +- cmdstack = (unsigned char *)zalloc(CMDSTACKSZ); +- ls->tok = tok; +- ls->isnewlin = isnewlin; +- ls->tokstr = tokstr; +- ls->zshlextext = zshlextext; +- ls->bptr = bptr; +- tokstr = zshlextext = bptr = NULL; +- ls->bsiz = bsiz; +- bsiz = 256; +- ls->len = len; +- ls->chwords = chwords; +- ls->chwordlen = chwordlen; +- ls->chwordpos = chwordpos; +- ls->hwgetword = hwgetword; +- ls->lexstop = lexstop; +- ls->hdocs = hdocs; +- ls->hgetc = hgetc; +- ls->hungetc = hungetc; +- ls->hwaddc = hwaddc; +- ls->hwbegin = hwbegin; +- ls->hwend = hwend; +- ls->addtoline = addtoline; +- ls->eclen = eclen; +- ls->ecused = ecused; +- ls->ecnpats = ecnpats; +- ls->ecbuf = ecbuf; +- ls->ecstrs = ecstrs; +- ls->ecsoffs = ecsoffs; +- ls->ecssub = ecssub; +- ls->ecnfunc = ecnfunc; +- ls->toklineno = toklineno; +- cmdsp = 0; +- inredir = 0; +- hdocs = NULL; +- histactive = 0; +- ecbuf = NULL; + + ls->next = lstack; + lstack = ls; + } + +-/* restore lexical state */ ++/* save context in full */ + + /**/ + mod_export void +-lexrestore(void) ++lexsave(void) ++{ ++ lexsave_partial(ZCONTEXT_HIST|ZCONTEXT_LEX|ZCONTEXT_PARSE); ++} ++ ++/* restore context or part therefore */ ++ ++/**/ ++mod_export void ++lexrestore_partial(int parts) + { + struct lexstack *ln = lstack; + +@@ -330,65 +377,89 @@ lexrestore(void) + queue_signals(); + lstack = lstack->next; + +- if (!lstack) { +- /* Back to top level: don't need special ZLE value */ +- DPUTS(ln->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE"); +- zle_chline = NULL; ++ if (parts & ZCONTEXT_LEX) { ++ incmdpos = ln->incmdpos; ++ incond = ln->incond; ++ incasepat = ln->incasepat; ++ dbparens = ln->dbparens; ++ isfirstln = ln->isfirstln; ++ isfirstch = ln->isfirstch; ++ lexflags = ln->lexflags; ++ tok = ln->tok; ++ isnewlin = ln->isnewlin; ++ tokstr = ln->tokstr; ++ zshlextext = ln->zshlextext; ++ bptr = ln->bptr; ++ bsiz = ln->bsiz; ++ len = ln->len; ++ lex_add_raw = ln->lex_add_raw; ++ tokstr_raw = ln->tokstr_raw; ++ bptr_raw = ln->bptr_raw; ++ bsiz_raw = ln->bsiz_raw; ++ len_raw = ln->len_raw; ++ lexstop = ln->lexstop; ++ toklineno = ln->toklineno; ++ } ++ ++ if (parts & ZCONTEXT_HIST) { ++ if (!lstack) { ++ /* Back to top level: don't need special ZLE value */ ++ DPUTS(ln->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE"); ++ zle_chline = NULL; ++ } ++ histactive = ln->histactive; ++ histdone = ln->histdone; ++ stophist = ln->stophist; ++ chline = ln->hline; ++ hptr = ln->hptr; ++ chwords = ln->chwords; ++ chwordlen = ln->chwordlen; ++ chwordpos = ln->chwordpos; ++ hwgetword = ln->hwgetword; ++ hgetc = ln->hgetc; ++ hungetc = ln->hungetc; ++ hwaddc = ln->hwaddc; ++ hwbegin = ln->hwbegin; ++ hwend = ln->hwend; ++ addtoline = ln->addtoline; ++ hlinesz = ln->hlinesz; ++ if (cmdstack) ++ zfree(cmdstack, CMDSTACKSZ); ++ cmdstack = ln->cstack; ++ cmdsp = ln->csp; ++ } ++ ++ if (parts & ZCONTEXT_PARSE) { ++ if (ecbuf) ++ zfree(ecbuf, eclen); ++ ++ hdocs = ln->hdocs; ++ eclen = ln->eclen; ++ ecused = ln->ecused; ++ ecnpats = ln->ecnpats; ++ ecbuf = ln->ecbuf; ++ ecstrs = ln->ecstrs; ++ ecsoffs = ln->ecsoffs; ++ ecssub = ln->ecssub; ++ ecnfunc = ln->ecnfunc; ++ ++ errflag = 0; + } + +- incmdpos = ln->incmdpos; +- incond = ln->incond; +- incasepat = ln->incasepat; +- dbparens = ln->dbparens; +- isfirstln = ln->isfirstln; +- isfirstch = ln->isfirstch; +- histactive = ln->histactive; +- histdone = ln->histdone; +- lexflags = ln->lexflags; +- stophist = ln->stophist; +- chline = ln->hline; +- hptr = ln->hptr; +- if (cmdstack) +- zfree(cmdstack, CMDSTACKSZ); +- cmdstack = ln->cstack; +- cmdsp = ln->csp; +- tok = ln->tok; +- isnewlin = ln->isnewlin; +- tokstr = ln->tokstr; +- zshlextext = ln->zshlextext; +- bptr = ln->bptr; +- bsiz = ln->bsiz; +- len = ln->len; +- chwords = ln->chwords; +- chwordlen = ln->chwordlen; +- chwordpos = ln->chwordpos; +- hwgetword = ln->hwgetword; +- lexstop = ln->lexstop; +- hdocs = ln->hdocs; +- hgetc = ln->hgetc; +- hungetc = ln->hungetc; +- hwaddc = ln->hwaddc; +- hwbegin = ln->hwbegin; +- hwend = ln->hwend; +- addtoline = ln->addtoline; +- if (ecbuf) +- zfree(ecbuf, eclen); +- eclen = ln->eclen; +- ecused = ln->ecused; +- ecnpats = ln->ecnpats; +- ecbuf = ln->ecbuf; +- ecstrs = ln->ecstrs; +- ecsoffs = ln->ecsoffs; +- ecssub = ln->ecssub; +- ecnfunc = ln->ecnfunc; +- hlinesz = ln->hlinesz; +- toklineno = ln->toklineno; +- errflag = 0; + free(ln); + + unqueue_signals(); + } + ++/* complete restore context */ ++ ++/**/ ++mod_export void ++lexrestore(void) ++{ ++ lexrestore_partial(ZCONTEXT_HIST|ZCONTEXT_LEX|ZCONTEXT_PARSE); ++} ++ + /**/ + void + zshlex(void) +@@ -1889,80 +1960,151 @@ exalias(void) + return 0; + } + +-/* skip (...) */ ++/**/ ++void ++zshlex_raw_add(int c) ++{ ++ if (!lex_add_raw) ++ return; ++ ++ *bptr_raw++ = c; ++ if (bsiz_raw == ++len_raw) { ++ int newbsiz = bsiz_raw * 2; ++ ++ tokstr_raw = (char *)hrealloc(tokstr_raw, bsiz_raw, newbsiz); ++ bptr_raw = tokstr_raw + len_raw; ++ memset(bptr_raw, 0, newbsiz - bsiz_raw); ++ bsiz_raw = newbsiz; ++ } ++} ++ ++/**/ ++void ++zshlex_raw_back(void) ++{ ++ if (!lex_add_raw) ++ return; ++ bptr_raw--; ++ len_raw--; ++} ++ ++/* ++ * Skip (...) for command-style substitutions: $(...), <(...), >(...) ++ * ++ * In order to ensure we don't stop at closing parentheses with ++ * some other syntactic significance, we'll parse the input until ++ * we find an unmatched closing parenthesis. However, we'll throw ++ * away the result of the parsing and just keep the string we've built ++ * up on the way. ++ */ + + /**/ + static int + skipcomm(void) + { +- int pct = 1, c, start = 1; ++ char *new_tokstr, *new_bptr = bptr_raw; ++ int new_len, new_bsiz, new_lexstop, new_lex_add_raw; + + cmdpush(CS_CMDSUBST); + SETPARBEGIN +- c = Inpar; +- do { +- int iswhite; +- add(c); +- c = hgetc(); +- if (itok(c) || lexstop) +- break; +- iswhite = inblank(c); +- switch (c) { +- case '(': +- pct++; +- break; +- case ')': +- pct--; +- break; +- case '\\': +- add(c); +- c = hgetc(); +- break; +- case '\'': { +- int strquote = bptr[-1] == '$'; +- add(c); +- STOPHIST +- while ((c = hgetc()) != '\'' && !lexstop) { +- if (c == '\\' && strquote) { +- add(c); +- c = hgetc(); +- } +- add(c); +- } +- ALLOWHIST +- break; +- } +- case '\"': +- add(c); +- while ((c = hgetc()) != '\"' && !lexstop) +- if (c == '\\') { +- add(c); +- add(hgetc()); +- } else +- add(c); +- break; +- case '`': +- add(c); +- while ((c = hgetc()) != '`' && !lexstop) +- if (c == '\\') +- add(c), add(hgetc()); +- else +- add(c); +- break; +- case '#': +- if (start) { +- add(c); +- while ((c = hgetc()) != '\n' && !lexstop) +- add(c); +- iswhite = 1; +- } +- break; ++ add(Inpar); ++ ++ new_lex_add_raw = lex_add_raw + 1; ++ if (!lex_add_raw) { ++ /* ++ * We'll combine the string so far with the input ++ * read in for the command substitution. To do this ++ * we'll just propagate the current tokstr etc. as the ++ * variables used for adding raw input, and ++ * ensure we swap those for the real tokstr etc. at the end. ++ * ++ * However, we need to save and restore the rest of the ++ * lexical and parse state as we're effectively parsing ++ * an internal string. Because we're still parsing it from ++ * the original input source (we have to --- we don't know ++ * when to stop inputting it otherwise and can't rely on ++ * the input being recoverable until we've read it) we need ++ * to keep the same history context. ++ */ ++ new_tokstr = tokstr; ++ new_bptr = bptr; ++ new_len = len; ++ new_bsiz = bsiz; ++ ++ lexsave_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); ++ } else { ++ /* ++ * Set up for nested command subsitution, however ++ * we don't actually need the string until we get ++ * back to the top level and recover the lot. ++ * The $() body just appears empty. ++ * ++ * We do need to propagate the raw variables which would ++ * otherwise by cleared, though. ++ */ ++ new_tokstr = tokstr_raw; ++ new_bptr = bptr_raw; ++ new_len = len_raw; ++ new_bsiz = bsiz_raw; ++ ++ lexsave_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); ++ } ++ tokstr_raw = new_tokstr; ++ bsiz_raw = new_bsiz; ++ len_raw = new_len; ++ bptr_raw = new_bptr; ++ lex_add_raw = new_lex_add_raw; ++ ++ if (!parse_event(OUTPAR) || tok != OUTPAR) ++ lexstop = 1; ++ /* Outpar lexical token gets added in caller if present */ ++ ++ /* ++ * We're going to keep the full raw input string ++ * as the current token string after popping the stack. ++ */ ++ new_tokstr = tokstr_raw; ++ new_bptr = bptr_raw; ++ new_len = len_raw; ++ new_bsiz = bsiz_raw; ++ /* ++ * We're also going to propagate the lexical state: ++ * if we couldn't parse the command substitution we ++ * can't continue. ++ */ ++ new_lexstop = lexstop; ++ ++ lexrestore_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); ++ ++ if (lex_add_raw) { ++ /* ++ * Keep going, so retain the raw variables. ++ */ ++ tokstr_raw = new_tokstr; ++ bptr_raw = new_bptr; ++ len_raw = new_len; ++ bsiz_raw = new_bsiz; ++ } else { ++ if (!new_lexstop) { ++ /* Ignore the ')' added on input */ ++ new_len--; ++ *--new_bptr = '\0'; + } +- start = iswhite; ++ ++ /* ++ * Convince the rest of lex.c we were examining a string ++ * all along. ++ */ ++ tokstr = new_tokstr; ++ bptr = new_bptr; ++ len = new_len; ++ bsiz = new_bsiz; ++ lexstop = new_lexstop; + } +- while (pct); ++ + if (!lexstop) + SETPAREND + cmdpop(); ++ + return lexstop; + } +diff --git a/Src/parse.c b/Src/parse.c +index 753080d..b0a7624 100644 +--- a/Src/parse.c ++++ b/Src/parse.c +@@ -360,7 +360,8 @@ ecstrcode(char *s) + + /* Initialise wordcode buffer. */ + +-static void ++/**/ ++void + init_parse(void) + { + if (ecbuf) zfree(ecbuf, eclen); +@@ -439,11 +440,15 @@ clear_hdocs() + * event : ENDINPUT + * | SEPER + * | sublist [ SEPER | AMPER | AMPERBANG ] ++ * ++ * cmdsubst indicates our event is part of a command-style ++ * substitution terminated by the token indicationg, usual closing ++ * parenthesis. In other cases endtok is ENDINPUT. + */ + + /**/ + Eprog +-parse_event(void) ++parse_event(int endtok) + { + tok = ENDINPUT; + incmdpos = 1; +@@ -451,36 +456,42 @@ parse_event(void) + zshlex(); + init_parse(); + +- if (!par_event()) { ++ if (!par_event(endtok)) { + clear_hdocs(); + return NULL; + } ++ if (endtok != ENDINPUT) { ++ /* don't need to build an eprog for this */ ++ return &dummy_eprog; ++ } + return bld_eprog(); + } + + /**/ +-static int +-par_event(void) ++int ++par_event(int endtok) + { + int r = 0, p, c = 0; + + while (tok == SEPER) { +- if (isnewlin > 0) ++ if (isnewlin > 0 && endtok == ENDINPUT) + return 0; + zshlex(); + } + if (tok == ENDINPUT) + return 0; ++ if (tok == endtok) ++ return 0; + + p = ecadd(0); + + if (par_sublist(&c)) { +- if (tok == ENDINPUT) { ++ if (tok == ENDINPUT || tok == endtok) { + set_list_code(p, Z_SYNC, c); + r = 1; + } else if (tok == SEPER) { + set_list_code(p, Z_SYNC, c); +- if (isnewlin <= 0) ++ if (isnewlin <= 0 || endtok != ENDINPUT) + zshlex(); + r = 1; + } else if (tok == AMPER) { +@@ -509,7 +520,7 @@ par_event(void) + } else { + int oec = ecused; + +- if (!par_event()) { ++ if (!par_event(endtok)) { + ecused = oec; + ecbuf[p] |= wc_bdata(Z_END); + } +diff --git a/Src/zsh.h b/Src/zsh.h +index 207ef18..b3391ed 100644 +--- a/Src/zsh.h ++++ b/Src/zsh.h +@@ -395,6 +395,15 @@ enum { + #define META_HEAPDUP 6 + #define META_HREALLOC 7 + ++/* Context to save and restore (bit fields) */ ++enum { ++ /* History mechanism */ ++ ZCONTEXT_HIST = (1<<0), ++ /* Lexical analyser */ ++ ZCONTEXT_LEX = (1<<1), ++ /* Parser */ ++ ZCONTEXT_PARSE = (1<<2) ++}; + + /**************************/ + /* Abstract types for zsh */ +diff --git a/Test/D08cmdsubst.ztst b/Test/D08cmdsubst.ztst +index 5661b0a..a4c69a0 100644 +--- a/Test/D08cmdsubst.ztst ++++ b/Test/D08cmdsubst.ztst +@@ -106,3 +106,45 @@ + >34 + >" + >" OK ++ ++ echo $(case foo in ++ foo) ++ echo This test worked. ++ ;; ++ bar) ++ echo This test failed in a rather bizarre way. ++ ;; ++ *) ++ echo This test failed. ++ ;; ++ esac) ++0:Parsing of command substitution with unmatched parentheses: case, basic ++>This test worked. ++ ++ echo "$(case bar in ++ foo) ++ echo This test spoobed. ++ ;; ++ bar) ++ echo This test plurbled. ++ ;; ++ *) ++ echo This test bzonked. ++ ;; ++ esac)" ++0:Parsing of command substitution with unmatched parentheses: case with quotes ++>This test plurbled. ++ ++ echo before $( ++ echo start; echo unpretentious | ++ while read line; do ++ case $line in ++ u*) ++ print Word began with u ++ print and ended with a crunch ++ ;; ++ esac ++ done | sed -e 's/Word/Universe/'; echo end ++ ) after ++0:Parsing of command substitution with ummatched parentheses: with frills ++>before start Universe began with u and ended with a crunch end after +-- +2.4.3 + + +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 + +An empty expression resulting from substitution includes a +Nularg, which needs handling the same as an empty string. + +Upstream-commit: 2ef4b38461dfb554ed2226d9de8958703bc00b98 +Signed-off-by: Kamil Dudka +--- + Src/math.c | 15 ++++++++++++++- + Test/C01arith.ztst | 4 ++++ + 2 files changed, 18 insertions(+), 1 deletion(-) + +diff --git a/Src/math.c b/Src/math.c +index e90d6a5..d6db7d3 100644 +--- a/Src/math.c ++++ b/Src/math.c +@@ -1330,7 +1330,7 @@ matheval(char *s) + if (!mlevel) + outputradix = 0; + +- if (!*s) { ++ if (!*s || *s == Nularg) { + x.type = MN_INTEGER; + x.u.l = 0; + return x; +@@ -1358,6 +1358,19 @@ mathevalarg(char *s, char **ss) + mnumber x; + int xmtok = mtok; + ++ /* ++ * At this entry point we don't allow an empty expression, ++ * whereas we do with matheval(). I'm not sure if this ++ * difference is deliberate, but it does mean that e.g. ++ * $array[$ind] where ind hasn't been set produces an error, ++ * which is probably safe. ++ * ++ * To avoid a more opaque error further in, bail out here. ++ */ ++ if (!*s || *s == Nularg) { ++ zerr("bad math expression: empty string"); ++ return (zlong)0; ++ } + x = mathevall(s, MPREC_ARG, ss); + if (mtok == COMMA) + (*ss)--; +diff --git a/Test/C01arith.ztst b/Test/C01arith.ztst +index 02d1519..33b03ef 100644 +--- a/Test/C01arith.ztst ++++ b/Test/C01arith.ztst +@@ -243,3 +243,7 @@ + >6000000 + >5000 + >255 ++ ++ print $((`:`)) ++0:Null string in arithmetic evaluation after command substitution ++>0 +-- +2.4.6 + + +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 + context + +Upstream-commit: c0a80171ee615b52a15a6fc8efe83c2bb53451d2 +Signed-off-by: Kamil Dudka +--- + Src/lex.c | 6 +++++- + Test/A01grammar.ztst | 6 ++++++ + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/Src/lex.c b/Src/lex.c +index bcceda6..f43b92b 100644 +--- a/Src/lex.c ++++ b/Src/lex.c +@@ -1541,7 +1541,7 @@ dquote_parse(char endchar, int sub) + { + int pct = 0, brct = 0, bct = 0, intick = 0, err = 0; + int c; +- int math = endchar == ')' || endchar == ']'; ++ int math = endchar == ')' || endchar == ']' || infor; + int zlemath = math && zlemetacs > zlemetall + addedx - inbufct; + + while (((c = hgetc()) != endchar || bct || +@@ -2004,7 +2004,9 @@ skipcomm(void) + { + char *new_tokstr, *new_bptr = bptr_raw; + int new_len, new_bsiz, new_lexstop, new_lex_add_raw; ++ int save_infor = infor; + ++ infor = 0; + cmdpush(CS_CMDSUBST); + SETPARBEGIN + add(Inpar); +@@ -2054,6 +2056,7 @@ skipcomm(void) + len_raw = new_len; + bptr_raw = new_bptr; + lex_add_raw = new_lex_add_raw; ++ dbparens = 0; /* restored by zcontext_restore_partial() */ + + if (!parse_event(OUTPAR) || tok != OUTPAR) + lexstop = 1; +@@ -2105,6 +2108,7 @@ skipcomm(void) + if (!lexstop) + SETPAREND + cmdpop(); ++ infor = save_infor; + + return lexstop; + } +diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst +index f04ddda..584ebd6 100644 +--- a/Test/A01grammar.ztst ++++ b/Test/A01grammar.ztst +@@ -169,6 +169,12 @@ + >1 + >2 + ++ for (( $(true); ; )); do break; done ++ for (( ; $(true); )); do break; done ++ for (( ; ; $(true) )); do break; done ++ for (( ; $((1)); )); do break; done ++0:regression test, nested cmdsubst in arithmetic `for' loop ++ + for keyvar valvar in key1 val1 key2 val2; do + print key=$keyvar val=$valvar + done +-- +2.4.6 + + +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 + expansion + +Upstream-commit: 3b32abafdb019cfb8f29908bc3d148e01518981d +Signed-off-by: Kamil Dudka +--- + Src/input.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/Src/input.c b/Src/input.c +index 1579762..5b782dc 100644 +--- a/Src/input.c ++++ b/Src/input.c +@@ -532,6 +532,12 @@ inpush(char *str, int flags, Alias inalias) + static void + inpoptop(void) + { ++ if (!lexstop) { ++ inbufflags &= ~INP_ALCONT; ++ while (inbufptr > inbuf) ++ inungetc(inbufptr[-1]); ++ } ++ + if (inbuf && (inbufflags & INP_FREE)) + free(inbuf); + +-- +2.4.6 + diff --git a/SOURCES/zsh-5.0.2-disable-alloca.patch b/SOURCES/zsh-5.0.2-disable-alloca.patch new file mode 100644 index 0000000..f369527 --- /dev/null +++ b/SOURCES/zsh-5.0.2-disable-alloca.patch @@ -0,0 +1,53 @@ +From d2f33b7005540aef5ce79479d598cdcc10d397f9 Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Thu, 24 Jul 2014 08:45:16 -0700 +Subject: [PATCH] 32853: redefine VARARR() to use heap rather than stack + allocation + +Upstream-commit: 2f0efe9f592255d0d83c0929423cc397bb1ebfa4 +Signed-off-by: Kamil Dudka +--- + Src/mem.c | 5 ++++- + Src/zsh_system.h | 5 +++++ + 2 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/Src/mem.c b/Src/mem.c +index 5275c6c..c4745a5 100644 +--- a/Src/mem.c ++++ b/Src/mem.c +@@ -856,7 +856,10 @@ zrealloc(void *ptr, size_t size) + ptr = NULL; + } else { + /* If ptr is NULL, then behave like malloc */ +- ptr = malloc(size); ++ if (!(ptr = (void *) malloc(size))) { ++ zerr("fatal error: out of memory"); ++ exit(1); ++ } + } + unqueue_signals(); + +diff --git a/Src/zsh_system.h b/Src/zsh_system.h +index f385330..427c25f 100644 +--- a/Src/zsh_system.h ++++ b/Src/zsh_system.h +@@ -286,11 +286,16 @@ struct timezone { + # include + #endif + ++#ifdef USE_STACK_ALLOCATION ++#warning compiling with USE_STACK_ALLOCATION + #ifdef HAVE_VARIABLE_LENGTH_ARRAYS + # define VARARR(X,Y,Z) X (Y)[Z] + #else + # define VARARR(X,Y,Z) X *(Y) = (X *) alloca(sizeof(X) * (Z)) + #endif ++#else ++# define VARARR(X,Y,Z) X *(Y) = (X *) zhalloc(sizeof(X) * (Z)) ++#endif + + /* we should handle unlimited sizes from pathconf(_PC_PATH_MAX) */ + /* but this is too much trouble */ +-- +2.1.0 + diff --git a/SOURCES/zsh-5.0.2-emul-man-page.patch b/SOURCES/zsh-5.0.2-emul-man-page.patch new file mode 100644 index 0000000..bc333a7 --- /dev/null +++ b/SOURCES/zsh-5.0.2-emul-man-page.patch @@ -0,0 +1,55 @@ +From d379782a50437c9a49d48adca163621f9f67aed1 Mon Sep 17 00:00:00 2001 +From: Jan Chaloupka +Date: Mon, 2 Jun 2014 17:06:32 +0200 +Subject: [PATCH] 32666: shell emulation doc addition + +Upstream-commit: d6698d89a6ff9e644ee608c1d08ff21911f9fb27 +Signed-off-by: Kamil Dudka +--- + Doc/Zsh/compat.yo | 2 +- + Doc/zsh.1 | 2 +- + Doc/zshall.1 | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/Doc/Zsh/compat.yo b/Doc/Zsh/compat.yo +index bf97fe2..f1be15f 100644 +--- a/Doc/Zsh/compat.yo ++++ b/Doc/Zsh/compat.yo +@@ -6,7 +6,7 @@ cindex(ksh compatibility) + Zsh tries to emulate bf(sh) or bf(ksh) when it is invoked as + tt(sh) or tt(ksh) respectively; more precisely, it looks at the first + letter of the name by which it was invoked, excluding any initial `tt(r)' +-(assumed to stand for `restricted'), and if that is `tt(s)' or `tt(k)' it ++(assumed to stand for `restricted'), and if that is `tt(b)', `tt(s)' or `tt(k)' it + will emulate bf(sh) or bf(ksh). Furthermore, if invoked as tt(su) (which + happens on certain systems when the shell is executed by the tt(su) + command), the shell will try to find an alternative name from the tt(SHELL) +diff --git a/Doc/zsh.1 b/Doc/zsh.1 +index 3ba42a6..8143d16 100644 +--- a/Doc/zsh.1 ++++ b/Doc/zsh.1 +@@ -255,7 +255,7 @@ can be stacked after the `\fB\-b\fP\&' and will take effect as normal\&. + Zsh tries to emulate \fBsh\fP or \fBksh\fP when it is invoked as + \fBsh\fP or \fBksh\fP respectively; more precisely, it looks at the first + letter of the name by which it was invoked, excluding any initial `\fBr\fP\&' +-(assumed to stand for `restricted\&'), and if that is `\fBs\fP' or `\fBk\fP' it ++(assumed to stand for `restricted\&'), and if that is `\fBb\fP', `\fBs\fP' or `\fBk\fP' it + will emulate \fBsh\fP or \fBksh\fP\&. Furthermore, if invoked as \fBsu\fP (which + happens on certain systems when the shell is executed by the \fBsu\fP + command), the shell will try to find an alternative name from the \fBSHELL\fP +diff --git a/Doc/zshall.1 b/Doc/zshall.1 +index 9642c5c..e23492a 100644 +--- a/Doc/zshall.1 ++++ b/Doc/zshall.1 +@@ -252,7 +252,7 @@ can be stacked after the `\fB\-b\fP' and will take effect as normal\&. + Zsh tries to emulate \fBsh\fP or \fBksh\fP when it is invoked as + \fBsh\fP or \fBksh\fP respectively; more precisely, it looks at the first + letter of the name by which it was invoked, excluding any initial `\fBr\fP' +-(assumed to stand for `restricted'), and if that is `\fBs\fP' or `\fBk\fP' it ++(assumed to stand for `restricted'), and if that is `\fBb\fP', `\fBs\fP' or `\fBk\fP' it + will emulate \fBsh\fP or \fBksh\fP\&. Furthermore, if invoked as \fBsu\fP (which + happens on certain systems when the shell is executed by the \fBsu\fP + command), the shell will try to find an alternative name from the \fBSHELL\fP +-- +2.1.0 + diff --git a/SOURCES/zsh-5.0.2-signal-safety.patch b/SOURCES/zsh-5.0.2-signal-safety.patch new file mode 100644 index 0000000..d9e2a72 --- /dev/null +++ b/SOURCES/zsh-5.0.2-signal-safety.patch @@ -0,0 +1,406 @@ +From a361a5ac293c9422f953c3d59e53f07e195740d3 Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Thu, 6 Nov 2014 10:50:20 -0800 +Subject: [PATCH 1/5] 33614 (based on RedHat BZ-978613): signal safety when + updating global state in execshfunc() + +Upstream-commit: 7abd611a2396bad9d93d18681a2c59cb1ea0e158 +Signed-off-by: Kamil Dudka +--- + Src/exec.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/Src/exec.c b/Src/exec.c +index 28da5c3..60ee4b8 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -4392,6 +4392,7 @@ execshfunc(Shfunc shf, LinkList args) + fputc('\n', xtrerr); + fflush(xtrerr); + } ++ queue_signals(); + ocs = cmdstack; + ocsp = cmdsp; + cmdstack = (unsigned char *) zalloc(CMDSTACKSZ); +@@ -4399,7 +4400,11 @@ 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; +@@ -4407,6 +4412,7 @@ execshfunc(Shfunc shf, LinkList args) + + if (!list_pipe) + deletefilelist(last_file_list, 0); ++ unqueue_signals(); + } + + /* Function to execute the special type of command that represents an * +-- +2.4.0 + + +From 236bb914d24e6588d12c3bf66bd06c6416832b8f Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Fri, 20 Feb 2015 18:45:36 -0800 +Subject: [PATCH 2/5] 34590: queue_signals() around more scopes that manipulate + global state + +Upstream-commit: a4ff8e69570cbdb8e7d5bf1d5cc4000ffe63e15e +Signed-off-by: Kamil Dudka +--- + Src/exec.c | 4 +++- + Src/text.c | 15 +++++++++++++++ + 2 files changed, 18 insertions(+), 1 deletion(-) + +diff --git a/Src/exec.c b/Src/exec.c +index 60ee4b8..83b9083 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -2280,6 +2280,7 @@ addvars(Estate state, Wordcode pc, int addflags) + void + setunderscore(char *str) + { ++ queue_signals(); + if (str && *str) { + int l = strlen(str) + 1, nl = (l + 31) & ~31; + +@@ -2297,6 +2298,7 @@ setunderscore(char *str) + *zunderscore = '\0'; + underscoreused = 1; + } ++ unqueue_signals(); + } + + /* These describe the type of expansions that need to be done on the words +@@ -5056,7 +5058,7 @@ execsave(void) + { + struct execstack *es; + +- es = (struct execstack *) malloc(sizeof(struct execstack)); ++ es = (struct execstack *) zalloc(sizeof(struct execstack)); + es->list_pipe_pid = list_pipe_pid; + es->nowait = nowait; + es->pline_level = pline_level; +diff --git a/Src/text.c b/Src/text.c +index f55553e..8f8eb34 100644 +--- a/Src/text.c ++++ b/Src/text.c +@@ -173,6 +173,8 @@ getpermtext(Eprog prog, Wordcode c, int start_indent) + { + struct estate s; + ++ queue_signals(); ++ + if (!c) + c = prog->prog; + +@@ -193,6 +195,9 @@ getpermtext(Eprog prog, Wordcode c, int start_indent) + *tptr = '\0'; + freeeprog(prog); /* mark as unused */ + untokenize(tbuf); ++ ++ unqueue_signals(); ++ + return tbuf; + } + +@@ -206,6 +211,8 @@ getjobtext(Eprog prog, Wordcode c) + + struct estate s; + ++ queue_signals(); ++ + if (!c) + c = prog->prog; + +@@ -224,6 +231,9 @@ getjobtext(Eprog prog, Wordcode c) + *tptr = '\0'; + freeeprog(prog); /* mark as unused */ + untokenize(jbuf); ++ ++ unqueue_signals(); ++ + return jbuf; + } + +@@ -879,6 +889,9 @@ getredirs(LinkList redirs) + ">", ">|", ">>", ">>|", "&>", "&>|", "&>>", "&>>|", "<>", "<", + "<<", "<<-", "<<<", "<&", ">&", NULL /* >&- */, "<", ">" + }; ++ ++ queue_signals(); ++ + taddchr(' '); + for (n = firstnode(redirs); n; incnode(n)) { + Redir f = (Redir) getdata(n); +@@ -966,4 +979,6 @@ getredirs(LinkList redirs) + } + } + tptr--; ++ ++ unqueue_signals(); + } +-- +2.4.0 + + +From 2e60901b1733929619cccce6cd66898520fd3015 Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Thu, 26 Sep 2013 21:27:27 -0700 +Subject: [PATCH 3/5] 31772: queue_signals() to prevent re-entry into + endparamscope(). + +Upstream-commit: ae92cadc75fbf7e8ec356cf09d3f73db9868424b +Signed-off-by: Kamil Dudka +--- + Src/params.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Src/params.c b/Src/params.c +index 8649178..d6711e4 100644 +--- a/Src/params.c ++++ b/Src/params.c +@@ -4667,10 +4667,12 @@ startparamscope(void) + mod_export void + endparamscope(void) + { ++ queue_signals(); + locallevel--; + /* This pops anything from a higher locallevel */ + saveandpophiststack(0, HFILE_USE_OPTIONS); + scanhashtable(paramtab, 0, 0, 0, scanendscope, 0); ++ unqueue_signals(); + } + + /**/ +-- +2.4.1 + + +From 39dea2e735ae277c9e1238e5d17f3fbd0a08bb6f Mon Sep 17 00:00:00 2001 +From: Bart Schaefer +Date: Thu, 17 Oct 2013 07:35:05 -0700 +Subject: [PATCH 4/5] 31832: make execrestore() more signal-safe. + +Upstream-commit: 978b5bcc8d21fce58369f810ef73bdbc434f33e7 +Signed-off-by: Kamil Dudka +--- + Src/exec.c | 52 ++++++++++++++++++++++++++++------------------------ + 1 file changed, 28 insertions(+), 24 deletions(-) + +diff --git a/Src/exec.c b/Src/exec.c +index 83b9083..2f94052 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -5087,30 +5087,34 @@ execsave(void) + void + execrestore(void) + { +- struct execstack *en; ++ struct execstack *en = exstack; + + DPUTS(!exstack, "BUG: execrestore() without execsave()"); +- list_pipe_pid = exstack->list_pipe_pid; +- nowait = exstack->nowait; +- pline_level = exstack->pline_level; +- list_pipe_child = exstack->list_pipe_child; +- list_pipe_job = exstack->list_pipe_job; +- strcpy(list_pipe_text, exstack->list_pipe_text); +- lastval = exstack->lastval; +- noeval = exstack->noeval; +- badcshglob = exstack->badcshglob; +- cmdoutpid = exstack->cmdoutpid; +- cmdoutval = exstack->cmdoutval; +- use_cmdoutval = exstack->use_cmdoutval; +- trap_return = exstack->trap_return; +- trap_state = exstack->trap_state; +- trapisfunc = exstack->trapisfunc; +- traplocallevel = exstack->traplocallevel; +- noerrs = exstack->noerrs; +- subsh_close = exstack->subsh_close; +- setunderscore(exstack->underscore); +- zsfree(exstack->underscore); +- en = exstack->next; +- free(exstack); +- exstack = en; ++ ++ queue_signals(); ++ exstack = exstack->next; ++ ++ list_pipe_pid = en->list_pipe_pid; ++ nowait = en->nowait; ++ pline_level = en->pline_level; ++ list_pipe_child = en->list_pipe_child; ++ list_pipe_job = en->list_pipe_job; ++ strcpy(list_pipe_text, en->list_pipe_text); ++ lastval = en->lastval; ++ noeval = en->noeval; ++ badcshglob = en->badcshglob; ++ cmdoutpid = en->cmdoutpid; ++ cmdoutval = en->cmdoutval; ++ use_cmdoutval = en->use_cmdoutval; ++ trap_return = en->trap_return; ++ trap_state = en->trap_state; ++ trapisfunc = en->trapisfunc; ++ traplocallevel = en->traplocallevel; ++ noerrs = en->noerrs; ++ subsh_close = en->subsh_close; ++ setunderscore(en->underscore); ++ zsfree(en->underscore); ++ free(en); ++ ++ unqueue_signals(); + } +-- +2.4.1 + + +From 15ac5a43bb483ed753655c7985fbdb056745303b Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Tue, 30 Sep 2014 20:34:58 -0700 +Subject: [PATCH 5/5] 33298: make lexrestore() more signal-safe + +Upstream-commit: 8727049674b1f39a8926c02dc74e9f19bbd70289 +Signed-off-by: Kamil Dudka +--- + Src/lex.c | 110 ++++++++++++++++++++++++++++++++------------------------------ + 1 file changed, 57 insertions(+), 53 deletions(-) + +diff --git a/Src/lex.c b/Src/lex.c +index ac87e5e..82bf848 100644 +--- a/Src/lex.c ++++ b/Src/lex.c +@@ -323,66 +323,70 @@ lexsave(void) + mod_export void + lexrestore(void) + { +- struct lexstack *ln; ++ struct lexstack *ln = lstack; + + DPUTS(!lstack, "BUG: lexrestore() without lexsave()"); +- incmdpos = lstack->incmdpos; +- incond = lstack->incond; +- incasepat = lstack->incasepat; +- dbparens = lstack->dbparens; +- isfirstln = lstack->isfirstln; +- isfirstch = lstack->isfirstch; +- histactive = lstack->histactive; +- histdone = lstack->histdone; +- lexflags = lstack->lexflags; +- stophist = lstack->stophist; +- chline = lstack->hline; +- hptr = lstack->hptr; ++ ++ queue_signals(); ++ lstack = lstack->next; ++ ++ if (!lstack) { ++ /* Back to top level: don't need special ZLE value */ ++ DPUTS(ln->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE"); ++ zle_chline = NULL; ++ } ++ ++ incmdpos = ln->incmdpos; ++ incond = ln->incond; ++ incasepat = ln->incasepat; ++ dbparens = ln->dbparens; ++ isfirstln = ln->isfirstln; ++ isfirstch = ln->isfirstch; ++ histactive = ln->histactive; ++ histdone = ln->histdone; ++ lexflags = ln->lexflags; ++ stophist = ln->stophist; ++ chline = ln->hline; ++ hptr = ln->hptr; + if (cmdstack) +- free(cmdstack); +- cmdstack = lstack->cstack; +- cmdsp = lstack->csp; +- tok = lstack->tok; +- isnewlin = lstack->isnewlin; +- tokstr = lstack->tokstr; +- zshlextext = lstack->zshlextext; +- bptr = lstack->bptr; +- bsiz = lstack->bsiz; +- len = lstack->len; +- chwords = lstack->chwords; +- chwordlen = lstack->chwordlen; +- chwordpos = lstack->chwordpos; +- hwgetword = lstack->hwgetword; +- lexstop = lstack->lexstop; +- hdocs = lstack->hdocs; +- hgetc = lstack->hgetc; +- hungetc = lstack->hungetc; +- hwaddc = lstack->hwaddc; +- hwbegin = lstack->hwbegin; +- hwend = lstack->hwend; +- addtoline = lstack->addtoline; ++ zfree(cmdstack, CMDSTACKSZ); ++ cmdstack = ln->cstack; ++ cmdsp = ln->csp; ++ tok = ln->tok; ++ isnewlin = ln->isnewlin; ++ tokstr = ln->tokstr; ++ zshlextext = ln->zshlextext; ++ bptr = ln->bptr; ++ bsiz = ln->bsiz; ++ len = ln->len; ++ chwords = ln->chwords; ++ chwordlen = ln->chwordlen; ++ chwordpos = ln->chwordpos; ++ hwgetword = ln->hwgetword; ++ lexstop = ln->lexstop; ++ hdocs = ln->hdocs; ++ hgetc = ln->hgetc; ++ hungetc = ln->hungetc; ++ hwaddc = ln->hwaddc; ++ hwbegin = ln->hwbegin; ++ hwend = ln->hwend; ++ addtoline = ln->addtoline; + if (ecbuf) + zfree(ecbuf, eclen); +- eclen = lstack->eclen; +- ecused = lstack->ecused; +- ecnpats = lstack->ecnpats; +- ecbuf = lstack->ecbuf; +- ecstrs = lstack->ecstrs; +- ecsoffs = lstack->ecsoffs; +- ecssub = lstack->ecssub; +- ecnfunc = lstack->ecnfunc; +- hlinesz = lstack->hlinesz; +- toklineno = lstack->toklineno; ++ eclen = ln->eclen; ++ ecused = ln->ecused; ++ ecnpats = ln->ecnpats; ++ ecbuf = ln->ecbuf; ++ ecstrs = ln->ecstrs; ++ ecsoffs = ln->ecsoffs; ++ ecssub = ln->ecssub; ++ ecnfunc = ln->ecnfunc; ++ hlinesz = ln->hlinesz; ++ toklineno = ln->toklineno; + errflag = 0; ++ free(ln); + +- ln = lstack->next; +- if (!ln) { +- /* Back to top level: don't need special ZLE value */ +- DPUTS(chline != zle_chline, "BUG: Ouch, wrong chline for ZLE"); +- zle_chline = NULL; +- } +- free(lstack); +- lstack = ln; ++ unqueue_signals(); + } + + /**/ +-- +2.4.1 + diff --git a/SOURCES/zshenv.rhs b/SOURCES/zshenv.rhs index 30630c0..a6614d3 100644 --- a/SOURCES/zshenv.rhs +++ b/SOURCES/zshenv.rhs @@ -1,9 +1,14 @@ +# /etc/zsh/zshenv: system-wide .zshenv file for zsh(1). # -# /etc/zshenv is sourced on all invocations of the -# shell, unless the -f option is set. It should -# contain commands to set the command search path, -# plus other important environment variables. -# .zshenv should not contain commands that produce +# This file is sourced on all invocations of the shell. +# If the -f flag is present or if the NO_RCS option is +# set within this file, all other initialization files +# are skipped. +# +# This file should contain commands to set the command +# search path, plus other important environment variables. +# This file should not contain commands that produce # output or assume the shell is attached to a tty. # +# Global Order: zshenv, zprofile, zshrc, zlogin diff --git a/SPECS/zsh.spec b/SPECS/zsh.spec index ed2baa5..1f95f82 100644 --- a/SPECS/zsh.spec +++ b/SPECS/zsh.spec @@ -3,7 +3,7 @@ Summary: Powerful interactive shell Name: zsh Version: 5.0.2 -Release: 7%{?dist}.2 +Release: 14%{?dist} License: MIT URL: http://zsh.sourceforge.net/ Group: System Environment/Shells @@ -24,19 +24,34 @@ Patch2: zsh-5.0.2-wait-for-exited.patch Patch4: zsh-4.3.6-8bit-prompts.patch Patch5: zsh-test-C02-dev_fd-mock.patch +# signal safety when updating global state (#1163823) +Patch6: zsh-5.0.2-signal-safety.patch + # fix NOEXEC option in execsimple() optimisation (#1146512) Patch7: zsh-5.0.2-noexec.patch # optimize matching of multiple * in wildcards (#1130418) Patch8: zsh-5.0.2-wildcard-opt.patch +# use heap rather than stack allocation for variable length arrays (#1130418) +Patch9: zsh-5.0.2-disable-alloca.patch + +# shell emulation doc addition (#1147545) +Patch10: zsh-5.0.2-emul-man-page.patch + # Tmp. Patch11: zsh-5.0.2.texi-itemx.patch Patch12: http://ausil.fedorapeople.org/aarch64/zsh/zsh-aarch64.patch +# suppress a warning about closing an already closed file descriptor (#1131191) +Patch13: zsh-5.0.2-close-fd.patch + # fix SIGSEGV of the syntax check in ksh emulation mode (#1222867) 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 + BuildRequires: coreutils sed ncurses-devel libcap-devel BuildRequires: texinfo texi2html gawk hostname Requires(post): /sbin/install-info grep @@ -72,13 +87,16 @@ This package contains the Zsh manual in html format. %patch2 -p1 %patch4 -p1 %patch5 -p1 - +%patch6 -p1 %patch7 -p1 %patch8 -p1 - +%patch9 -p1 +%patch10 -p1 %patch11 -p1 %patch12 -p1 +%patch13 -p1 %patch14 -p1 +%patch15 -p1 cp -p %SOURCE7 . @@ -195,12 +213,31 @@ fi %doc Doc/*.html %changelog -* Mon Oct 26 2015 Kamil Dudka - 5.0.2-7.el7_1.2 +* Fri Aug 14 2015 Kamil Dudka - 5.0.2-14 +- fix alias handling in command substitution (#1253555) + +* Thu Jul 30 2015 Kamil Dudka - 5.0.2-13 +- fix parser regression introduced by the fix for bug #1241023 + +* Wed Jul 08 2015 Kamil Dudka - 5.0.2-12 +- fix command substitutions to parse contents as they are read in (#1241023) + +* Fri May 22 2015 Kamil Dudka - 5.0.2-11 - fix SIGSEGV of the syntax check in ksh emulation mode (#1222867) + +* Mon May 18 2015 Kamil Dudka - 5.0.2-10 +- signal safety when updating global state (#1163823) + +* Tue May 05 2015 Kamil Dudka - 5.0.2-9 +- signal safety when updating global state in execshfunc() (#1163823) - make the wait built-in work for already exited processes (#1162198) +- replace an incorrect comment in /etc/zshenv (#1164312) - optimize matching of multiple * in wildcards (#1130418) +- use heap rather than stack allocation for variable length arrays (#1165118) +- shell emulation doc addition (#1147545) +- suppress a warning about closing an already closed file descriptor (#1131191) -* Thu Mar 19 2015 Kamil Dudka - 5.0.2-7.el7_1.1 +* Thu Mar 19 2015 Kamil Dudka - 5.0.2-8 - fix NOEXEC option in execsimple() optimisation (#1146512) * Tue Jan 28 2014 James Antill - 5.0.2-7