[git commit] ash: [PARSER] Report substition errors at expansion time

Denys Vlasenko vda.linux at googlemail.com
Tue Oct 25 23:55:56 UTC 2016


commit: https://git.busybox.net/busybox/commit/?id=88e15703acdbfb182440cf35fdb8972fc4931dd2
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

Upstreams commit:

    Date: Mon, 8 Oct 2007 21:32:25 +0800
    [PARSER] Report substition errors at expansion time

    On Wed, Apr 11, 2007 at 01:24:21PM -0700, Micah Cowan wrote:
    > This operation fails on Ubuntu:
    >
    >     $ /bin/sh -c 'if false; then d="${foo/bar}"; fi'
    >     /bin/sh: Syntax error: Bad substitution
    >
    > When used with other POSIX shells it succeeds. While semantically the
    > variable reference ${foo/bar} is not valid, this is not a syntax error
    > according to POSIX, and since the variable assignment expression is
    > never invoked (because it's within an "if false") it should not be seen
    > as an error.
    >
    > I ran into this because after restarting my system I could no longer log
    > in. It turns out that the problem was (a) I had edited .gnomerc to
    > source my .bashrc file so that my environment would be set properly, and
    > (b) I had added some new code to my .bashrc WITHIN A CHECK FOR BASH!
    > that used bash's ${var/match/sub} feature. Even though this code was
    > within a "case $BASH_VERSION; in *[0-9]*) ... esac (so dash would never
    > execute it since that variable is not set), it still caused dash to
    > throw up.
    >
    > FYI, some relevant details from POSIX:
    >
    > Section 2.3, Token Recognition:
    >
    > 5. If the current character is an unquoted '$' or '`', the shell shall
    > identify the start of any candidates for parameter expansion ( Parameter
    > Expansion), command substitution ( Command Substitution), or arithmetic
    > expansion ( Arithmetic Expansion) from their introductory unquoted
    > character sequences: '$' or "${", "$(" or '`', and "$((", respectively.
    > The shell shall read sufficient input to determine the end of the unit
    > to be expanded (as explained in the cited sections).
    >
    > Section 2.6.2, Parameter Expansion:
    >
    > The format for parameter expansion is as follows:
    >
    >     ${expression}
    >
    > where expression consists of all characters until the matching '}'. Any
    > '}' escaped by a backslash or within a quoted string, and characters in
    > embedded arithmetic expansions, command substitutions, and variable
    > expansions, shall not be examined in determining the matching '}'.
    > [...]
    >
    > The parameter name or symbol can be enclosed in braces, which are
    > optional except for positional parameters with more than one digit or
    > when parameter is followed by a character that could be interpreted as
    > part of the name. The matching closing brace shall be determined by
    > counting brace levels, skipping over enclosed quoted strings, and
    > command substitutions.
    > ---
    > In addition to bash I've checked Solaris /bin/sh and ksh and they don't
    > report an error.
    >
    > -----
    > Micah Cowan:
    >
    > The applicable portion of POSIX is in XCU 2.10.1:
    >
    > "The WORD tokens shall have the word expansion rules applied to them
    > immediately before the associated command is executed, not at the time
    > the command is parsed."
    >
    > This seems fairly clear to me.

    This patch moves the error detection to expansion time.

    Test case:

    	if false; then
    		echo ${a!7}
    	fi
    	echo OK

    Old result:

	dash: Syntax error: Bad substitution

    New result:

	OK

function                                             old     new   delta
evalvar                                              574     585     +11
readtoken1                                          2763    2750     -13

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/ash.c | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index dc26bc1..e30d7fe 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -6752,6 +6752,10 @@ evalvar(char *p, int flag, struct strlist *var_str_list)
 
 	varflags = (unsigned char) *p++;
 	subtype = varflags & VSTYPE;
+
+	if (!subtype)
+		raise_error_syntax("bad substitution");
+
 	quoted = flag & EXP_QUOTED;
 	var = p;
 	easy = (!quoted || (*var == '@' && shellparam.nparam));
@@ -11699,7 +11703,7 @@ parseredir: {
 parsesub: {
 	unsigned char subtype;
 	int typeloc;
-	int flags;
+	int flags = 0;
 
 	c = pgetc_eatbnl();
 	if (c > 255 /* PEOA or PEOF */
@@ -11759,15 +11763,13 @@ parsesub: {
 			USTPUTC(c, out);
 			c = pgetc_eatbnl();
 		} else {
- badsub:
-			raise_error_syntax("bad substitution");
+			goto badsub;
 		}
 		if (c != '}' && subtype == VSLENGTH) {
 			/* ${#VAR didn't end with } */
 			goto badsub;
 		}
 
-		STPUTC('=', out);
 		flags = 0;
 		if (subtype == 0) {
 			static const char types[] ALIGN1 = "}-+?=";
@@ -11784,7 +11786,7 @@ parsesub: {
 				if (!strchr(types, c)) {
 					subtype = VSSUBSTR;
 					pungetc();
-					break; /* "goto do_pungetc" is bigger (!) */
+					break; /* "goto badsub" is bigger (!) */
 				}
 #endif
 				flags = VSNUL;
@@ -11792,7 +11794,7 @@ parsesub: {
 			default: {
 				const char *p = strchr(types, c);
 				if (p == NULL)
-					goto badsub;
+					break;
 				subtype = p - types + VSNORMAL;
 				break;
 			}
@@ -11802,7 +11804,7 @@ parsesub: {
 				subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
 				c = pgetc_eatbnl();
 				if (c != cc)
-					goto do_pungetc;
+					goto badsub;
 				subtype++;
 				break;
 			}
@@ -11814,13 +11816,13 @@ parsesub: {
 				subtype = VSREPLACE;
 				c = pgetc_eatbnl();
 				if (c != '/')
-					goto do_pungetc;
+					goto badsub;
 				subtype++; /* VSREPLACEALL */
 				break;
 #endif
 			}
 		} else {
- do_pungetc:
+ badsub:
 			pungetc();
 		}
 		((unsigned char *)stackblock())[typeloc] = subtype | flags;
@@ -11830,6 +11832,7 @@ parsesub: {
 				dqvarnest++;
 			}
 		}
+		STPUTC('=', out);
 	}
 	goto parsesub_return;
 }


More information about the busybox-cvs mailing list