From 0aaaa50b4551ab5912ccd95d66d633844eac6d85 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 2 Oct 2016 02:46:56 +0200 Subject: [PATCH] ash: expand: Fixed "$@" expansion when EXP_FULL is false Upstream commit: Date: Thu, 1 Jan 2015 07:53:10 +1100 expand: Fixed "$@" expansion when EXP_FULL is false The commit 3c06acdac0b1ba0e0acdda513a57ee6e31385dce ([EXPAND] Split unquoted $@/$* correctly when IFS is set but empty) broke the case where $@ is in quotes and EXP_FULL is false. In that case we should still emit IFS as field splitting is not performed. Reported-by: Juergen Daubert Signed-off-by: Herbert Xu Signed-off-by: Denys Vlasenko --- shell/ash.c | 28 +++++++++---------- .../ash-vars/var_wordsplit_ifs1.right | 16 +++++++++++ .../ash-vars/var_wordsplit_ifs1.tests | 21 ++++++++++++++ .../hush-vars/var_wordsplit_ifs1.right | 16 +++++++++++ .../hush-vars/var_wordsplit_ifs1.tests | 21 ++++++++++++++ 5 files changed, 87 insertions(+), 15 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index 731c4b2b0..4f6ba0c70 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -6615,7 +6615,10 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int int subtype = varflags & VSTYPE; int discard = subtype == VSPLUS || subtype == VSLENGTH; int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL; - int syntax = quoted ? DQSYNTAX : BASESYNTAX; + int syntax; + + sep = (flags & EXP_FULL) << CHAR_BIT; + syntax = quoted ? DQSYNTAX : BASESYNTAX; switch (*name) { case '$': @@ -6649,23 +6652,18 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int raise_error_syntax("bad substitution"); #endif break; - case '@': { + case '@': + if (quoted && sep) + goto param; + /* fall through */ + case '*': { char **ap; char sepc; - sep = 0; - if (quoted && (flags & EXP_FULL)) { - /* note: this is not meant as PEOF value */ - sep = 1 << CHAR_BIT; - goto param; - } - /* fall through */ - case '*': - sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' '; - if (!quoted) { + if (quoted) + sep = 0; + sep |= ifsset() ? ifsval()[0] : ' '; param: - sep |= (flags & EXP_FULL) << CHAR_BIT; - } sepc = sep; *quotedp = !sepc; ap = shellparam.p; @@ -6680,7 +6678,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int } } break; - } /* case '@' and '*' */ + } /* case '*' */ case '0': case '1': case '2': diff --git a/shell/ash_test/ash-vars/var_wordsplit_ifs1.right b/shell/ash_test/ash-vars/var_wordsplit_ifs1.right index efdafc70f..cf583d0aa 100644 --- a/shell/ash_test/ash-vars/var_wordsplit_ifs1.right +++ b/shell/ash_test/ash-vars/var_wordsplit_ifs1.right @@ -22,4 +22,20 @@ Testing: IFS="" "$*" Testing: IFS="" "$@" .abc. .d e. +Testing: !IFS v=$* +v='abc d e' +Testing: !IFS v=$@ +v='abc d e' +Testing: !IFS v="$*" +v='abc d e' +Testing: !IFS v="$@" +v='abc d e' +Testing: IFS="" v=$* +v='abcd e' +Testing: IFS="" v=$@ +v='abcd e' +Testing: IFS="" v="$*" +v='abcd e' +Testing: IFS="" v="$@" +v='abcd e' Finished diff --git a/shell/ash_test/ash-vars/var_wordsplit_ifs1.tests b/shell/ash_test/ash-vars/var_wordsplit_ifs1.tests index 532ab992e..a62afc6fd 100755 --- a/shell/ash_test/ash-vars/var_wordsplit_ifs1.tests +++ b/shell/ash_test/ash-vars/var_wordsplit_ifs1.tests @@ -18,4 +18,25 @@ IFS=""; for a in "$*"; do echo ".$a."; done echo 'Testing: IFS="" "$@"' IFS=""; for a in "$@"; do echo ".$a."; done +echo 'Testing: !IFS v=$*' +unset IFS; v=$*; echo "v='$v'" +echo 'Testing: !IFS v=$@' +unset IFS; v=$@; echo "v='$v'" +echo 'Testing: !IFS v="$*"' +unset IFS; v="$*"; echo "v='$v'" +echo 'Testing: !IFS v="$@"' +unset IFS; v="$@"; echo "v='$v'" + +echo 'Testing: IFS="" v=$*' +IFS=""; v=$*; echo "v='$v'" +echo 'Testing: IFS="" v=$@' +IFS=""; v=$@; echo "v='$v'" +echo 'Testing: IFS="" v="$*"' +IFS=""; v="$*"; echo "v='$v'" +echo 'Testing: IFS="" v="$@"' +IFS=""; v="$@"; echo "v='$v'" + +# Note: in IFS="" v=$@ and IFS="" v="$@" cases, bash produces "abc d e" +# We produce "abcd e" + echo Finished diff --git a/shell/hush_test/hush-vars/var_wordsplit_ifs1.right b/shell/hush_test/hush-vars/var_wordsplit_ifs1.right index efdafc70f..cf583d0aa 100644 --- a/shell/hush_test/hush-vars/var_wordsplit_ifs1.right +++ b/shell/hush_test/hush-vars/var_wordsplit_ifs1.right @@ -22,4 +22,20 @@ Testing: IFS="" "$*" Testing: IFS="" "$@" .abc. .d e. +Testing: !IFS v=$* +v='abc d e' +Testing: !IFS v=$@ +v='abc d e' +Testing: !IFS v="$*" +v='abc d e' +Testing: !IFS v="$@" +v='abc d e' +Testing: IFS="" v=$* +v='abcd e' +Testing: IFS="" v=$@ +v='abcd e' +Testing: IFS="" v="$*" +v='abcd e' +Testing: IFS="" v="$@" +v='abcd e' Finished diff --git a/shell/hush_test/hush-vars/var_wordsplit_ifs1.tests b/shell/hush_test/hush-vars/var_wordsplit_ifs1.tests index 532ab992e..a62afc6fd 100755 --- a/shell/hush_test/hush-vars/var_wordsplit_ifs1.tests +++ b/shell/hush_test/hush-vars/var_wordsplit_ifs1.tests @@ -18,4 +18,25 @@ IFS=""; for a in "$*"; do echo ".$a."; done echo 'Testing: IFS="" "$@"' IFS=""; for a in "$@"; do echo ".$a."; done +echo 'Testing: !IFS v=$*' +unset IFS; v=$*; echo "v='$v'" +echo 'Testing: !IFS v=$@' +unset IFS; v=$@; echo "v='$v'" +echo 'Testing: !IFS v="$*"' +unset IFS; v="$*"; echo "v='$v'" +echo 'Testing: !IFS v="$@"' +unset IFS; v="$@"; echo "v='$v'" + +echo 'Testing: IFS="" v=$*' +IFS=""; v=$*; echo "v='$v'" +echo 'Testing: IFS="" v=$@' +IFS=""; v=$@; echo "v='$v'" +echo 'Testing: IFS="" v="$*"' +IFS=""; v="$*"; echo "v='$v'" +echo 'Testing: IFS="" v="$@"' +IFS=""; v="$@"; echo "v='$v'" + +# Note: in IFS="" v=$@ and IFS="" v="$@" cases, bash produces "abc d e" +# We produce "abcd e" + echo Finished -- 2.25.1