From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 19115 invoked by alias); 16 Feb 2015 17:04:29 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: X-Seq: 34560 Received: (qmail 25127 invoked from network); 16 Feb 2015 17:04:26 -0000 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_HI, SPF_HELO_PASS autolearn=ham version=3.3.2 X-AuditID: cbfec7f5-b7fc86d0000066b7-ff-54e2228262cf Date: Mon, 16 Feb 2015 17:04:13 +0000 From: Peter Stephenson To: zsh-workers@zsh.org Subject: Re: PATCH: Crash bug on garbage input (previously reported to Debian) Message-id: <20150216170413.054623af@pwslap01u.europe.root.pri> In-reply-to: <20150216125749.7a26822c@pwslap01u.europe.root.pri> References: <150214102534.ZM4368@torch.brasslantern.com> <20150214214209.6d2f5e7e@ntlworld.com> <150215112622.ZM11584@torch.brasslantern.com> <20150216125749.7a26822c@pwslap01u.europe.root.pri> Organization: Samsung Cambridge Solution Centre X-Mailer: Claws Mail 3.7.9 (GTK+ 2.22.0; i386-redhat-linux-gnu) MIME-version: 1.0 Content-type: text/plain; charset=US-ASCII Content-transfer-encoding: 7bit X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrGLMWRmVeSWpSXmKPExsVy+t/xK7pNSo9CDJqnGVscbH7I5MDoserg B6YAxigum5TUnMyy1CJ9uwSujL1v97IXdGpWXLh9hqmBcb98FyMnh4SAicS8NWuYIGwxiQv3 1rN1MXJxCAksZZQ4vOIvE4SzhEni19nbjBDONkaJq91rGEFaWARUJTq+LgdrZxMwlJi6aTZY XERAXOLs2vMsILawgL/Ej6vd7CA2r4C9xKFt58FsTgEHiadb17KC2EICxxklfs7iBrH5BfQl rv79BHWSvcTMK2cYIXoFJX5Mvgc2k1lAS2LztiZWCFteYvOat8wQc9QlbtzdzT6BUWgWkpZZ SFpmIWlZwMi8ilE0tTS5oDgpPddIrzgxt7g0L10vOT93EyMkbL/uYFx6zOoQowAHoxIP74aw ByFCrIllxZW5hxglOJiVRHhDpB+FCPGmJFZWpRblxxeV5qQWH2Jk4uCUamBkPcd8qXPXY6NE Aemlz1lnSZipnxSucj14oD3xz57n7J0F4WvmRJoH6R1vytFOep+/jZV/0d31kWUSydolHxwm MGtVT9Q57FklYLfi1J8rvhE3qyoUr3hwGxhFFxS/7Gq99rvzj++SwyWCK66KOuX6B/Y8M71+ 7+KB+eX/r7VU+85auKdlxy0lluKMREMt5qLiRACTe3t8OQIAAA== On Mon, 16 Feb 2015 12:57:49 +0000 Peter Stephenson wrote: > % print $((echo foo > mathsubst> ); echo bar) > Attempt to inungetc() at start of input. > zsh: Garbled input at \n (binary file as commands?) > zsh: parse error near `)' > > ...we somehow need to > detect we're doing the tentative looking for math mode and if so add the > new line as a continuation of the old one --- that's allowed by the > input mechanism and I don't see why that wouldn't work here (largely > because I haven't tried it yet). So it "only" remains working out where > to detect this. > > This will need a test, too. The current continuation / push expansion behaviour doesn't quite do what we want since it assumes we've finished with previous input. Here's a simple fix for appending to the input buffer instead of replacing it for this case. It's logically general, however I didn't bother to optimise it since it's special to this particular very rare case. I've noted this in the code. Optimising it now would be premature --- it would just introduce lots of new and hard to test special cases. This version has the virtue of being virtually independent of anything else going on. I've add the "parse test from hell" where the first line looks like an arithmetic substitution but it actually turns out to be a case statement with unbalanced parentheses that needs the new parsing behaviour. The original error now gives something that looks a bit more rational: % ${($((()$[(s: braceparam mathsubst mathsubst> this ends up in the history)}}) zsh: parse error near `$[(s:' zsh: closing brace expected The newly added error is probably sensible for robustness, though, although it's also likely to be a sign that something else is broken. pws diff --git a/Src/input.c b/Src/input.c index 9520fdd..f919e57 100644 --- a/Src/input.c +++ b/Src/input.c @@ -330,8 +330,37 @@ inputline(void) } } isfirstch = 1; - /* Put this into the input channel. */ - inputsetline(ingetcline, INP_FREE); + if ((inbufflags & INP_APPEND) && inbuf) { + /* + * We need new input but need to be able to back up + * over the old input, so append this line. + * Pushing the line onto the stack doesn't have the right + * effect. + * + * This is quite a simple and inefficient fix, but currently + * we only need it when backing up over a multi-line $((... + * that turned out to be a command substitution rather than + * a math substitution, which is a very special case. + * So it's not worth rewriting. + */ + char *oinbuf = inbuf; + int newlen = strlen(ingetcline); + int oldlen = (int)(inbufptr - inbuf) + inbufleft; + if (inbufflags & INP_FREE) { + inbuf = realloc(inbuf, oldlen + newlen + 1); + inbufptr += inbuf - oinbuf; + strcpy(inbuf + oldlen, ingetcline); + } else { + /* Paranoia: don't think this is used */ + DPUTS(1, "Appending to unallocated input line."); + } + inbufleft += newlen; + inbufct += newlen; + inbufflags |= INP_FREE; + } else { + /* Put this into the input channel. */ + inputsetline(ingetcline, INP_FREE); + } return 0; } diff --git a/Src/lex.c b/Src/lex.c index 91628d4..0068485 100644 --- a/Src/lex.c +++ b/Src/lex.c @@ -483,9 +483,13 @@ cmd_or_math(int cs_type) { int oldlen = lexbuf.len; int c; + int oinflags = inbufflags; cmdpush(cs_type); + inbufflags |= INP_APPEND; c = dquote_parse(')', 0); + if (!(oinflags & INP_APPEND)) + inbufflags &= ~INP_APPEND; cmdpop(); *lexbuf.ptr = '\0'; if (!c) { diff --git a/Src/zsh.h b/Src/zsh.h index 94e9ffc..dd946d2 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -410,6 +410,7 @@ enum { #define INP_CONT (1<<3) /* continue onto previously stacked input */ #define INP_ALCONT (1<<4) /* stack is continued from alias expn. */ #define INP_LINENO (1<<5) /* update line number */ +#define INP_APPEND (1<<6) /* Append new lines to allow backup */ /* Flags for metafy */ #define META_REALLOC 0 diff --git a/Test/C01arith.ztst b/Test/C01arith.ztst index ea87af2..09c0822 100644 --- a/Test/C01arith.ztst +++ b/Test/C01arith.ztst @@ -318,3 +318,38 @@ # 0.75 is exactly representable, don't expect rounding error. >0 >0.75 + + # The following tests for a bug that only happens when + # backing up over input read a line at a time, so we'll + # read the input from stdin. + $ZTST_testdir/../Src/zsh -f <<<' + print $((echo first command + ); echo second command) + print third command + ' +0:Backing up a line of input when finding out it's not arithmetic +>first command second command +>third command + + $ZTST_testdir/../Src/zsh -f <<<' + print $((3 + + 4)) + print next line + ' +0:Not needing to back up a line when reading multiline arithmetic +>7 +>next line + + $ZTST_testdir/../Src/zsh -f <<<' + print $((case foo in + bar) + echo not this no, no + ;; + foo) + echo yes, this one + ;; + esac) + print after case in subshell) + ' +0:Non-arithmetic subst with command subsitution parse from hell +>yes, this one after case in subshell