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) &quotef;
  	(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