[git commit] ash: [PARSER] Fix parsing of ${##1}

Denys Vlasenko vda.linux at googlemail.com
Wed Oct 26 13:56:53 UTC 2016


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

Upstream commit:

    Date: Thu, 4 Oct 2007 22:15:10 +0800
    [PARSER] Fix parsing of ${##1}

    Previously dash treated ${##1} as a length operation.  This patch fixes that.

    Test case:

        set -- a
        echo ${##1}OK

    Old result:

        1OK

    New result:

        OK

This was a real bug in ash (but not in hush).

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/ash.c                                      | 28 +++++++++++++++---------
 shell/ash_test/ash-vars/param_expand_len.right   |  3 +++
 shell/ash_test/ash-vars/param_expand_len.tests   |  7 ++++++
 shell/hush_test/hush-vars/param_expand_len.right |  3 +++
 shell/hush_test/hush-vars/param_expand_len.tests |  7 ++++++
 5 files changed, 38 insertions(+), 10 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index b404449..2cebfe2 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -11728,16 +11728,9 @@ parsesub: {
 		subtype = VSNORMAL;
 		if (c == '{') {
 			c = pgetc_eatbnl();
-			if (c == '#') {
-				c = pgetc_eatbnl();
-				if (c == '}')
-					c = '#'; /* ${#} - same as $# */
-				else
-					subtype = VSLENGTH; /* ${#VAR} */
-			} else {
-				subtype = 0;
-			}
+			subtype = 0;
 		}
+ varname:
 		if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
 			/* $[{[#]]NAME[}] */
 			do {
@@ -11752,8 +11745,23 @@ parsesub: {
 			} while (isdigit(c));
 		} else if (is_special(c)) {
 			/* $[{[#]]<specialchar>[}] */
-			USTPUTC(c, out);
+			int cc = c;
+
 			c = pgetc_eatbnl();
+			if (!subtype && cc == '#') {
+				subtype = VSLENGTH;
+				if (c == '_' || isalnum(c))
+					goto varname;
+				cc = c;
+				c = pgetc_eatbnl();
+				if (cc == '}' || c != '}') {
+					pungetc();
+					subtype = 0;
+					c = cc;
+					cc = '#';
+				}
+			}
+			USTPUTC(cc, out);
 		} else {
 			goto badsub;
 		}
diff --git a/shell/ash_test/ash-vars/param_expand_len.right b/shell/ash_test/ash-vars/param_expand_len.right
index 96e8cb5..48d01d2 100644
--- a/shell/ash_test/ash-vars/param_expand_len.right
+++ b/shell/ash_test/ash-vars/param_expand_len.right
@@ -7,3 +7,6 @@ Make sure len parsing doesnt break arg count
 Testing len op
 4 3 2 1 0 0
 0 3 0
+Nothing:
+Nothing:
+One:1
diff --git a/shell/ash_test/ash-vars/param_expand_len.tests b/shell/ash_test/ash-vars/param_expand_len.tests
index fe20a45..369c8d4 100755
--- a/shell/ash_test/ash-vars/param_expand_len.tests
+++ b/shell/ash_test/ash-vars/param_expand_len.tests
@@ -15,3 +15,10 @@ unset e
 f=abc
 g=
 echo ${#e} ${#f} ${#g}
+
+set -- a
+# This must be interpreted as: $# ("1"), then remove trailing "1".
+# IOW: empty result.
+echo Nothing:${##1}
+echo Nothing:${#%1}
+echo One:${##x}
diff --git a/shell/hush_test/hush-vars/param_expand_len.right b/shell/hush_test/hush-vars/param_expand_len.right
index 96e8cb5..48d01d2 100644
--- a/shell/hush_test/hush-vars/param_expand_len.right
+++ b/shell/hush_test/hush-vars/param_expand_len.right
@@ -7,3 +7,6 @@ Make sure len parsing doesnt break arg count
 Testing len op
 4 3 2 1 0 0
 0 3 0
+Nothing:
+Nothing:
+One:1
diff --git a/shell/hush_test/hush-vars/param_expand_len.tests b/shell/hush_test/hush-vars/param_expand_len.tests
index fe20a45..369c8d4 100755
--- a/shell/hush_test/hush-vars/param_expand_len.tests
+++ b/shell/hush_test/hush-vars/param_expand_len.tests
@@ -15,3 +15,10 @@ unset e
 f=abc
 g=
 echo ${#e} ${#f} ${#g}
+
+set -- a
+# This must be interpreted as: $# ("1"), then remove trailing "1".
+# IOW: empty result.
+echo Nothing:${##1}
+echo Nothing:${#%1}
+echo One:${##x}


More information about the busybox-cvs mailing list