ash: [EXPAND] Do not split quoted VSLENGTH and VSTRIM
authorDenys Vlasenko <vda.linux@googlemail.com>
Sat, 1 Oct 2016 18:55:02 +0000 (20:55 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sat, 1 Oct 2016 18:55:02 +0000 (20:55 +0200)
Upstream patch:

    Date: Wed, 8 Oct 2014 15:42:08 +0800
    [EXPAND] Do not split quoted VSLENGTH and VSTRIM

    Currently VSLENGTH and VSTRIM* are field-split even within quotes.
    This is obviously wrong.  This patch fixes that.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/ash.c
shell/ash_test/ash-vars/var_wordsplit_ifs2.right [new file with mode: 0644]
shell/ash_test/ash-vars/var_wordsplit_ifs2.tests [new file with mode: 0755]
shell/ash_test/ash-vars/var_wordsplit_ifs3.right [new file with mode: 0644]
shell/ash_test/ash-vars/var_wordsplit_ifs3.tests [new file with mode: 0755]
shell/hush_test/hush-vars/var_wordsplit_ifs2.right [new file with mode: 0644]
shell/hush_test/hush-vars/var_wordsplit_ifs2.tests [new file with mode: 0755]
shell/hush_test/hush-vars/var_wordsplit_ifs3.right [new file with mode: 0644]
shell/hush_test/hush-vars/var_wordsplit_ifs3.tests [new file with mode: 0755]

index 56dbcb7d13dde227934c71e0793331a50eef929d..d830e3962425073db48abfd49f1baea88969100d 100644 (file)
@@ -6753,7 +6753,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int
  * input string.
  */
 static char *
-evalvar(char *p, int flags, struct strlist *var_str_list)
+evalvar(char *p, int flag, struct strlist *var_str_list)
 {
        char varflags;
        char subtype;
@@ -6767,7 +6767,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
 
        varflags = (unsigned char) *p++;
        subtype = varflags & VSTYPE;
-       quoted = flags & EXP_QUOTED;
+       quoted = flag & EXP_QUOTED;
        var = p;
        easy = (!quoted || (*var == '@' && shellparam.nparam));
        nulonly = easy;
@@ -6775,7 +6775,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
        p = strchr(p, '=') + 1; //TODO: use var_end(p)?
 
  again:
-       varlen = varvalue(var, varflags, flags, var_str_list, &nulonly);
+       varlen = varvalue(var, varflags, flag, var_str_list, &nulonly);
        if (varflags & VSNUL)
                varlen--;
 
@@ -6789,36 +6789,27 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
                if (varlen < 0) {
                        argstr(
                                p,
-                               flags | EXP_TILDE | EXP_WORD,
+                               flag | EXP_TILDE | EXP_WORD,
                                var_str_list
                        );
                        goto end;
                }
-               if (easy)
-                       goto record;
-               goto end;
+               goto record;
        }
 
        if (subtype == VSASSIGN || subtype == VSQUESTION) {
-               if (varlen < 0) {
-                       if (subevalvar(p, var, /* strloc: */ 0,
-                                       subtype, startloc, varflags,
-                                       /* quotes: */ flags & ~QUOTES_ESC,
-                                       var_str_list)
-                       ) {
-                               varflags &= ~VSNUL;
-                               /*
-                                * Remove any recorded regions beyond
-                                * start of variable
-                                */
-                               removerecordregions(startloc);
-                               goto again;
-                       }
-                       goto end;
-               }
-               if (easy)
+               if (varlen >= 0)
                        goto record;
-               goto end;
+
+               subevalvar(p, var, 0, subtype, startloc, varflags,
+                          flag & ~QUOTES_ESC, var_str_list);
+               varflags &= ~VSNUL;
+               /*
+                * Remove any recorded regions beyond
+                * start of variable
+                */
+               removerecordregions(startloc);
+               goto again;
        }
 
        if (varlen < 0 && uflag)
@@ -6830,8 +6821,10 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
        }
 
        if (subtype == VSNORMAL) {
-               if (easy)
-                       goto record;
+ record:
+               if (!easy)
+                       goto end;
+               recordregion(startloc, expdest - (char *)stackblock(), nulonly);
                goto end;
        }
 
@@ -6860,7 +6853,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
                STPUTC('\0', expdest);
                patloc = expdest - (char *)stackblock();
                if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
-                               startloc, varflags, flags, var_str_list)) {
+                               startloc, varflags, flag, var_str_list)) {
                        int amount = expdest - (
                                (char *)stackblock() + patloc - 1
                        );
@@ -6868,8 +6861,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
                }
                /* Remove any recorded regions beyond start of variable */
                removerecordregions(startloc);
- record:
-               recordregion(startloc, expdest - (char *)stackblock(), nulonly);
+               goto record;
        }
 
  end:
diff --git a/shell/ash_test/ash-vars/var_wordsplit_ifs2.right b/shell/ash_test/ash-vars/var_wordsplit_ifs2.right
new file mode 100644 (file)
index 0000000..c234193
--- /dev/null
@@ -0,0 +1,3 @@
+Unquoted:<1>
+Unquoted:<3>
+Quoted:<123>
diff --git a/shell/ash_test/ash-vars/var_wordsplit_ifs2.tests b/shell/ash_test/ash-vars/var_wordsplit_ifs2.tests
new file mode 100755 (executable)
index 0000000..4752354
--- /dev/null
@@ -0,0 +1,13 @@
+# 123 chars long
+a="\
+01234567890123456789\
+01234567890123456789\
+01234567890123456789\
+01234567890123456789\
+01234567890123456789\
+0123456789\
+0123456789\
+012"
+
+IFS=2; for v in ${#a}; do echo Unquoted:"<$v>"; done
+IFS=2; for v in "${#a}"; do echo Quoted:"<$v>"; done
diff --git a/shell/ash_test/ash-vars/var_wordsplit_ifs3.right b/shell/ash_test/ash-vars/var_wordsplit_ifs3.right
new file mode 100644 (file)
index 0000000..5ab72e1
--- /dev/null
@@ -0,0 +1,12 @@
+Unquoted%:<q>
+Unquoted%:<w>
+Unquoted%:<e>
+Unquoted%:<r>
+Unquoted%:<t>
+Unquoted#:<w>
+Unquoted#:<e>
+Unquoted#:<r>
+Unquoted#:<t>
+Unquoted#:<y>
+Quoted%:<q w e r t >
+Quoted#:< w e r t y>
diff --git a/shell/ash_test/ash-vars/var_wordsplit_ifs3.tests b/shell/ash_test/ash-vars/var_wordsplit_ifs3.tests
new file mode 100755 (executable)
index 0000000..4aa6557
--- /dev/null
@@ -0,0 +1,5 @@
+a="q w e r t y"
+for v in ${a%y}; do echo Unquoted%:"<$v>"; done
+for v in ${a#q}; do echo Unquoted#:"<$v>"; done
+for v in "${a%y}"; do echo Quoted%:"<$v>"; done
+for v in "${a#q}"; do echo Quoted#:"<$v>"; done
diff --git a/shell/hush_test/hush-vars/var_wordsplit_ifs2.right b/shell/hush_test/hush-vars/var_wordsplit_ifs2.right
new file mode 100644 (file)
index 0000000..c234193
--- /dev/null
@@ -0,0 +1,3 @@
+Unquoted:<1>
+Unquoted:<3>
+Quoted:<123>
diff --git a/shell/hush_test/hush-vars/var_wordsplit_ifs2.tests b/shell/hush_test/hush-vars/var_wordsplit_ifs2.tests
new file mode 100755 (executable)
index 0000000..4752354
--- /dev/null
@@ -0,0 +1,13 @@
+# 123 chars long
+a="\
+01234567890123456789\
+01234567890123456789\
+01234567890123456789\
+01234567890123456789\
+01234567890123456789\
+0123456789\
+0123456789\
+012"
+
+IFS=2; for v in ${#a}; do echo Unquoted:"<$v>"; done
+IFS=2; for v in "${#a}"; do echo Quoted:"<$v>"; done
diff --git a/shell/hush_test/hush-vars/var_wordsplit_ifs3.right b/shell/hush_test/hush-vars/var_wordsplit_ifs3.right
new file mode 100644 (file)
index 0000000..5ab72e1
--- /dev/null
@@ -0,0 +1,12 @@
+Unquoted%:<q>
+Unquoted%:<w>
+Unquoted%:<e>
+Unquoted%:<r>
+Unquoted%:<t>
+Unquoted#:<w>
+Unquoted#:<e>
+Unquoted#:<r>
+Unquoted#:<t>
+Unquoted#:<y>
+Quoted%:<q w e r t >
+Quoted#:< w e r t y>
diff --git a/shell/hush_test/hush-vars/var_wordsplit_ifs3.tests b/shell/hush_test/hush-vars/var_wordsplit_ifs3.tests
new file mode 100755 (executable)
index 0000000..4aa6557
--- /dev/null
@@ -0,0 +1,5 @@
+a="q w e r t y"
+for v in ${a%y}; do echo Unquoted%:"<$v>"; done
+for v in ${a#q}; do echo Unquoted#:"<$v>"; done
+for v in "${a%y}"; do echo Quoted%:"<$v>"; done
+for v in "${a#q}"; do echo Quoted#:"<$v>"; done