bin/57554: [PATCH] sh(1) incorrect handling of quoted parameter
expansion
Mark Valentine
mark at valentine.me.uk
Mon Oct 6 12:20:15 PDT 2003
The following reply was made to PR bin/57554; it has been noted by GNATS.
From: Mark Valentine <mark at valentine.me.uk>
To: FreeBSD-gnats-submit at freebsd.org
Cc:
Subject: Re: bin/57554: [PATCH] sh(1) incorrect handling of quoted parameter expansion
Date: Mon, 6 Oct 2003 20:15:38 +0000
The NetBSD revisions I mentioned do seem to fix this. Here's a patch
which works for FreeBSD 4.8-STABLE; I just started a buildworld on my
system (which is running an older 4.8-STABLE from June), and I'll do
another installworld/buildworld cycle after that and follow up if any
problems arise.
The patch also applies OK to -CURRENT, but it'll take me a bit longer
to get around to testing that.
Index: mksyntax.c
===================================================================
RCS file: /usr/cvs/src/bin/sh/mksyntax.c,v
retrieving revision 1.14.2.3
diff -u -r1.14.2.3 mksyntax.c
--- mksyntax.c 19 Jul 2002 04:38:51 -0000 1.14.2.3
+++ mksyntax.c 6 Oct 2003 18:21:50 -0000
@@ -70,7 +70,6 @@
{ "CBACK", "a backslash character" },
{ "CSQUOTE", "single quote" },
{ "CDQUOTE", "double quote" },
- { "CENDQUOTE", "a terminating quote" },
{ "CBQUOTE", "backwards single quote" },
{ "CVAR", "a dollar sign" },
{ "CENDVAR", "a '}' character" },
@@ -220,7 +219,7 @@
fputs("\n/* syntax table used when in double quotes */\n", cfile);
add("\n", "CNL");
add("\\", "CBACK");
- add("\"", "CENDQUOTE");
+ add("\"", "CDQUOTE");
add("`", "CBQUOTE");
add("$", "CVAR");
add("}", "CENDVAR");
@@ -230,7 +229,7 @@
init();
fputs("\n/* syntax table used when in single quotes */\n", cfile);
add("\n", "CNL");
- add("'", "CENDQUOTE");
+ add("'", "CSQUOTE");
/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
add("!*?[=~:/-", "CCTL");
print("sqsyntax");
Index: parser.c
===================================================================
RCS file: /usr/cvs/src/bin/sh/parser.c,v
retrieving revision 1.29.2.10
diff -u -r1.29.2.10 parser.c
--- parser.c 22 Jul 2003 13:11:26 -0000 1.29.2.10
+++ parser.c 6 Oct 2003 18:39:24 -0000
@@ -73,6 +73,8 @@
/* values returned by readtoken */
#include "token.h"
+#define OPENBRACE '{'
+#define CLOSEBRACE '}'
struct heredoc {
@@ -885,6 +887,28 @@
#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
#define PARSEARITH() {goto parsearith; parsearith_return:;}
+/*
+ * Keep track of nested doublequotes in dblquote and doublequotep.
+ * We use dblquote for the first 32 levels, and we expand to a malloc'ed
+ * region for levels above that. Usually we never need to malloc.
+ * This code assumes that an int is 32 bits. We don't use uint32_t,
+ * because the rest of the code does not.
+ */
+#define ISDBLQUOTE() ((varnest < 32) ? (dblquote & (1 << varnest)) : \
+ (dblquotep[(varnest / 32) - 1] & (1 << (varnest % 32))))
+
+#define SETDBLQUOTE() \
+ if (varnest < 32) \
+ dblquote |= (1 << varnest); \
+ else \
+ dblquotep[(varnest / 32) - 1] |= (1 << (varnest % 32))
+
+#define CLRDBLQUOTE() \
+ if (varnest < 32) \
+ dblquote &= ~(1 << varnest); \
+ else \
+ dblquotep[(varnest / 32) - 1] &= ~(1 << (varnest % 32))
+
STATIC int
readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
{
@@ -894,6 +918,8 @@
char line[EOFMARKLEN + 1];
struct nodelist *bqlist;
int quotef;
+ int *dblquotep = NULL;
+ size_t maxnest = 32;
int dblquote;
int varnest; /* levels of variables expansion */
int arinest; /* levels of arithmetic expansion */
@@ -903,6 +929,8 @@
int synentry;
#if __GNUC__
/* Avoid longjmp clobbering */
+ (void) &maxnest;
+ (void) &dblquotep;
(void) &out;
(void) "ef;
(void) &dblquote;
@@ -917,11 +945,12 @@
startlinno = plinno;
dblquote = 0;
- if (syntax == DQSYNTAX)
- dblquote = 1;
+ varnest = 0;
+ if (syntax == DQSYNTAX) {
+ SETDBLQUOTE();
+ }
quotef = 0;
bqlist = NULL;
- varnest = 0;
arinest = 0;
parenlevel = 0;
@@ -959,7 +988,7 @@
USTPUTC(c, out);
break;
case CCTL:
- if (eofmark == NULL || dblquote)
+ if (eofmark == NULL || ISDBLQUOTE())
USTPUTC(CTLESC, out);
USTPUTC(c, out);
break;
@@ -974,7 +1003,7 @@
else
setprompt(0);
} else {
- if (dblquote && c != '\\' &&
+ if (ISDBLQUOTE() && c != '\\' &&
c != '`' && c != '$' &&
(c != '"' || eofmark != NULL))
USTPUTC('\\', out);
@@ -987,27 +1016,36 @@
}
break;
case CSQUOTE:
- if (eofmark == NULL)
- USTPUTC(CTLQUOTEMARK, out);
- syntax = SQSYNTAX;
- break;
+ if (syntax != SQSYNTAX) {
+ if (eofmark == NULL)
+ USTPUTC(CTLQUOTEMARK, out);
+ syntax = SQSYNTAX;
+ break;
+ }
+ /* FALLTHROUGH */
case CDQUOTE:
- if (eofmark == NULL)
- USTPUTC(CTLQUOTEMARK, out);
- syntax = DQSYNTAX;
- dblquote = 1;
- break;
- case CENDQUOTE:
if (eofmark != NULL && arinest == 0 &&
varnest == 0) {
USTPUTC(c, out);
} else {
if (arinest) {
- syntax = ARISYNTAX;
- dblquote = 0;
+ if (c != '"' || ISDBLQUOTE()) {
+ syntax = ARISYNTAX;
+ CLRDBLQUOTE();
+ } else {
+ syntax = DQSYNTAX;
+ SETDBLQUOTE();
+ USTPUTC(CTLQUOTEMARK, out);
+ }
} else if (eofmark == NULL) {
- syntax = BASESYNTAX;
- dblquote = 0;
+ if (c != '"' || ISDBLQUOTE()) {
+ syntax = BASESYNTAX;
+ CLRDBLQUOTE();
+ } else {
+ syntax = DQSYNTAX;
+ SETDBLQUOTE();
+ USTPUTC(CTLQUOTEMARK, out);
+ }
}
quotef++;
}
@@ -1015,8 +1053,8 @@
case CVAR: /* '$' */
PARSESUB(); /* parse substitution */
break;
- case CENDVAR: /* '}' */
- if (varnest > 0) {
+ case CENDVAR: /* CLOSEBRACE */
+ if (varnest > 0 && !ISDBLQUOTE()) {
varnest--;
USTPUTC(CTLENDVAR, out);
} else {
@@ -1037,9 +1075,9 @@
USTPUTC(CTLENDARI, out);
syntax = prevsyntax;
if (syntax == DQSYNTAX)
- dblquote = 1;
+ SETDBLQUOTE();
else
- dblquote = 0;
+ CLRDBLQUOTE();
} else
USTPUTC(')', out);
} else {
@@ -1092,6 +1130,8 @@
backquotelist = bqlist;
grabstackblock(len);
wordtext = out;
+ if (dblquotep != NULL)
+ ckfree(dblquotep);
return lasttoken = TWORD;
/* end of readtoken routine */
@@ -1202,7 +1242,7 @@
int bracketed_name = 0; /* used to handle ${[0-9]*} variables */
c = pgetc();
- if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
+ if (c != '(' && c != OPENBRACE && !is_name(c) && !is_special(c)) {
USTPUTC('$', out);
pungetc();
} else if (c == '(') { /* $(command) or $((arith)) */
@@ -1217,11 +1257,11 @@
typeloc = out - stackblock();
USTPUTC(VSNORMAL, out);
subtype = VSNORMAL;
- if (c == '{') {
+ if (c == OPENBRACE) {
bracketed_name = 1;
c = pgetc();
if (c == '#') {
- if ((c = pgetc()) == '}')
+ if ((c = pgetc()) == CLOSEBRACE)
c = '#';
else
subtype = VSLENGTH;
@@ -1281,11 +1321,17 @@
} else {
pungetc();
}
- if (subtype != VSLENGTH && (dblquote || arinest))
+ if (subtype != VSLENGTH && (ISDBLQUOTE() || arinest))
flags |= VSQUOTE;
*(stackblock() + typeloc) = subtype | flags;
- if (subtype != VSNORMAL)
+ if (subtype != VSNORMAL) {
varnest++;
+ if (varnest >= maxnest) {
+ dblquotep = ckrealloc(dblquotep, maxnest / 8);
+ dblquotep[(maxnest / 32) - 1] = 0;
+ maxnest += 32;
+ }
+ }
}
goto parsesub_return;
}
@@ -1366,7 +1412,7 @@
continue;
}
if (c != '\\' && c != '`' && c != '$'
- && (!dblquote || c != '"'))
+ && (!ISDBLQUOTE() || c != '"'))
STPUTC('\\', out);
break;
@@ -1437,7 +1483,7 @@
}
parsebackquote = savepbq;
handler = savehandler;
- if (arinest || dblquote)
+ if (arinest || ISDBLQUOTE())
USTPUTC(CTLBACKQ | CTLQUOTE, out);
else
USTPUTC(CTLBACKQ, out);
@@ -1456,7 +1502,7 @@
prevsyntax = syntax;
syntax = ARISYNTAX;
USTPUTC(CTLARI, out);
- if (dblquote)
+ if (ISDBLQUOTE())
USTPUTC('"',out);
else
USTPUTC(' ',out);
--
"Tigers will do ANYTHING for a tuna fish sandwich."
"We're kind of stupid that way." *munch* *munch*
-- <http://www.calvinandhobbes.com>
More information about the freebsd-bugs
mailing list