From patchwork Sat Feb 24 00:33:44 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herbert Xu X-Patchwork-Id: 10240067 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id F1AE8602A0 for ; Sat, 24 Feb 2018 00:33:59 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DCFCD29A70 for ; Sat, 24 Feb 2018 00:33:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D124329A9E; Sat, 24 Feb 2018 00:33:59 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E0E8629A70 for ; Sat, 24 Feb 2018 00:33:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751674AbeBXAd6 (ORCPT ); Fri, 23 Feb 2018 19:33:58 -0500 Received: from orcrist.hmeau.com ([104.223.48.154]:58982 "EHLO deadmen.hmeau.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751547AbeBXAd5 (ORCPT ); Fri, 23 Feb 2018 19:33:57 -0500 Received: from gondobar.mordor.me.apana.org.au ([192.168.128.4] helo=gondobar) by deadmen.hmeau.com with esmtp (Exim 4.84_2 #2 (Debian)) id 1epNme-0000c8-9Y; Sat, 24 Feb 2018 08:33:48 +0800 Received: from herbert by gondobar with local (Exim 4.84_2) (envelope-from ) id 1epNma-0000t9-U7; Sat, 24 Feb 2018 08:33:44 +0800 Date: Sat, 24 Feb 2018 08:33:44 +0800 From: Herbert Xu To: Harald van Dijk Cc: Denys Vlasenko , dash@vger.kernel.org Subject: Re: dash bug: double-quoted "\" breaks glob protection for next char Message-ID: <20180224003344.GA3354@gondor.apana.org.au> References: <5e1ee06d-d1ca-6442-51de-786e2739d4df@gigawatt.nl> <297b41c4-0e15-e0d8-f088-d68acfcc3c0f@gigawatt.nl> <5a9d8ab5-ec2d-8101-2853-ac3be6b0c4f6@gigawatt.nl> <9f37ae19-6f74-f527-aa49-dd04c3c010f6@gigawatt.nl> <73e4ad51-1c3b-3173-429f-401296244869@gigawatt.nl> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <73e4ad51-1c3b-3173-429f-401296244869@gigawatt.nl> User-Agent: Mutt/1.5.23 (2014-03-12) Sender: dash-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: dash@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP On Wed, Feb 21, 2018 at 11:47:58PM +0100, Harald van Dijk wrote: > On 2/21/18 2:50 PM, Denys Vlasenko wrote: > >I propose replacing this: > > Agreed, that looks better. Thanks! Good work guys. However, could you check to see if this patch works too? It passes all my tests so far. ---8<--- The commit "[EXPAND] Move parse-time quote flag detection to run-time" broke the following case: case \\zzzz in "\*") echo bad;; esac The reason is that the naked backslash gets attached to the newly added backslash added for the special character "*" in preglob, IOW you end up with "\\*" instead of just "\*" as it should be. The reason the naked backslash exists in the first place is because otherwise we cannot tell the difference between "\[" and "\\[" when it occurs in a quoted pattern context such as "${var#\[}" This patch restores the original behaviour for the buggy case while keeping the naked backslash for the quoted pattern case. Fixes: 7cfd8be0dc83 ("[EXPAND] Move parse-time quote flag...") Reported-by: Denys Vlasenko Suggested-by: Harald van Dijk Signed-off-by: Herbert Xu diff --git a/src/Makefile.am b/src/Makefile.am index 139355e..b5bff06 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,7 +60,7 @@ init.c: mkinit $(dash_CFILES) nodes.c nodes.h: mknodes nodetypes nodes.c.pat ./$^ -syntax.c syntax.h: mksyntax +syntax.c syntax.h: mksyntax parser.h ./$^ signames.c: mksignames diff --git a/src/expand.c b/src/expand.c index 2a50830..aeffe82 100644 --- a/src/expand.c +++ b/src/expand.c @@ -244,6 +244,7 @@ argstr(char *p, int flag) CTLVAR, CTLBACKQ, CTLENDARI, + CTLBACK, 0 }; const char *reject = spclchars; @@ -330,6 +331,7 @@ addquote: startloc++; } break; + case CTLBACK: case CTLESC: startloc++; length++; @@ -340,7 +342,7 @@ addquote: * backslash. */ if (((flag | inquotes) & (EXP_QPAT | EXP_QUOTED)) == - EXP_QPAT && *p != '\\') + EXP_QPAT && (*p != '\\' || c == CTLBACK)) break; goto addquote; @@ -373,6 +375,7 @@ exptilde(char *startp, char *p, int flag) while ((c = *++p) != '\0') { switch(c) { + case CTLBACK: case CTLESC: return (startp); case CTLQUOTEMARK: @@ -594,7 +597,7 @@ scanleft( *loc2 = c; if (match) return loc; - if (quotes && *loc == (char)CTLESC) + if (quotes && (*loc == (char)CTLESC || *loc == (char)CTLBACK)) loc++; loc++; loc2++; @@ -821,7 +824,8 @@ end: if (subtype != VSNORMAL) { /* skip to end of alternative */ int nesting = 1; for (;;) { - if ((c = (signed char)*p++) == CTLESC) + if ((c = (signed char)*p++) == CTLESC || + c == CTLBACK) p++; else if (c == CTLBACKQ) { if (varlen >= 0) @@ -1052,7 +1056,7 @@ ifsbreakup(char *string, int maxargs, struct arglist *arglist) q = p; c = *p++; - if (c == (char)CTLESC) + if (c == (char)CTLESC || c == (char)CTLBACK) c = *p++; isifs = strchr(ifs, c); @@ -1684,7 +1688,7 @@ _rmescapes(char *str, int flag) notescaped = globbing; continue; } - if (*p == (char)CTLESC) { + if (*p == (char)CTLESC || *p == (char)CTLBACK) { p++; if (notescaped) *q++ = '\\'; diff --git a/src/jobs.c b/src/jobs.c index 4f02e38..a3aef20 100644 --- a/src/jobs.c +++ b/src/jobs.c @@ -1386,6 +1386,7 @@ cmdputs(const char *s) while ((c = *p++) != 0) { str = 0; switch (c) { + case CTLBACK: case CTLESC: c = *p++; break; diff --git a/src/mystring.c b/src/mystring.c index 0106bd2..2573d1f 100644 --- a/src/mystring.c +++ b/src/mystring.c @@ -62,7 +62,7 @@ const char spcstr[] = " "; const char snlfmt[] = "%s\n"; const char dolatstr[] = { CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0' }; -const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 }; +const char qchars[] = { CTLESC, CTLQUOTEMARK, CTLBACK, 0 }; const char illnum[] = "Illegal number: %s"; const char homestr[] = "HOME"; diff --git a/src/parser.c b/src/parser.c index 382658e..22fc84a 100644 --- a/src/parser.c +++ b/src/parser.c @@ -930,7 +930,7 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs) case CBACK: c = pgetc2(); if (c == PEOF) { - USTPUTC(CTLESC, out); + USTPUTC(CTLBACK, out); USTPUTC('\\', out); pungetc(); } else if (c == '\n') { @@ -944,6 +944,7 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs) eofmark != NULL ) ) { + USTPUTC(CTLBACK, out); USTPUTC('\\', out); } USTPUTC(CTLESC, out); diff --git a/src/parser.h b/src/parser.h index 2875cce..54c02eb 100644 --- a/src/parser.h +++ b/src/parser.h @@ -45,7 +45,8 @@ #define CTLARI -122 /* arithmetic expression */ #define CTLENDARI -121 #define CTLQUOTEMARK -120 -#define CTL_LAST -120 /* last 'special' character */ +#define CTLBACK -119 +#define CTL_LAST -119 /* last 'special' character */ /* variable substitution byte (follows CTLVAR) */ #define VSTYPE 0x0f /* type of variable substitution */ diff --git a/src/show.c b/src/show.c index 4a049e9..ed840aa 100644 --- a/src/show.c +++ b/src/show.c @@ -166,6 +166,7 @@ sharg(union node *arg, FILE *fp) bqlist = arg->narg.backquote; for (p = arg->narg.text ; *p ; p++) { switch ((signed char)*p) { + case CTLBACK: case CTLESC: putc(*++p, fp); break; @@ -311,6 +312,7 @@ trstring(char *s) case '\r': c = 'r'; goto backslash; case '"': c = '"'; goto backslash; case '\\': c = '\\'; goto backslash; + case CTLBACK: case CTLESC: c = 'e'; goto backslash; case CTLVAR: c = 'v'; goto backslash; case CTLBACKQ: c = 'q'; goto backslash;