diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2020-02-22 19:38:40 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2020-02-24 19:20:51 +0100 |
commit | 1555895b4af44ce47fe2365aec82e8e67c685f08 (patch) | |
tree | bd821be779bc1d489ac966b0d83e4a5e026979dd /shell | |
parent | 823318822ccb0e0910abbd4e1f983637dfd9d3c0 (diff) | |
download | busybox-w32-1555895b4af44ce47fe2365aec82e8e67c685f08.tar.gz busybox-w32-1555895b4af44ce47fe2365aec82e8e67c685f08.tar.bz2 busybox-w32-1555895b4af44ce47fe2365aec82e8e67c685f08.zip |
ash: expand: Fix multiple issues with EXP_DISCARD in evalvar
Upstream commit:
Date: Wed, 12 Sep 2018 14:27:16 +0800
expand: Fix multiple issues with EXP_DISCARD in evalvar
The commit 3cd538634f71538370f5af239f342aec48b7470b broke parameter
expansion in multiple ways because the EXP_DISCARD flag wasn't set
or tested for various cases:
$ src/dash -c 'var=; echo ${var:+nonempty}'
nonempty
$ src/dash -u -c 'unset foo bar; echo ${foo+${bar}}'
dash: 1: bar: parameter not set
$ src/dash -c 'foo=bar; echo ${foo=BUG}; echo $foo'
barBUG
bar
$
This patch fixes them by introducing a new discard variable that
tracks whether the extra word should be discarded or not when it
is parsed.
Reported-by: Martijn Dekker <martijn@inlv.org>
Fixes: 3cd538634f71 ("expand: Do not reprocess data when...")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Reported-by: Martijn Dekker <martijn@inlv.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 28 |
1 files changed, 14 insertions, 14 deletions
diff --git a/shell/ash.c b/shell/ash.c index 425da6bb6..d0d99f60e 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -7454,6 +7454,7 @@ evalvar(char *p, int flag) | |||
7454 | int patloc; | 7454 | int patloc; |
7455 | int startloc; | 7455 | int startloc; |
7456 | ssize_t varlen; | 7456 | ssize_t varlen; |
7457 | int discard; | ||
7457 | int quoted; | 7458 | int quoted; |
7458 | 7459 | ||
7459 | varflags = (unsigned char) *p++; | 7460 | varflags = (unsigned char) *p++; |
@@ -7469,33 +7470,31 @@ evalvar(char *p, int flag) | |||
7469 | if (varflags & VSNUL) | 7470 | if (varflags & VSNUL) |
7470 | varlen--; | 7471 | varlen--; |
7471 | 7472 | ||
7473 | discard = varlen < 0 ? EXP_DISCARD : 0; | ||
7474 | |||
7472 | switch (subtype) { | 7475 | switch (subtype) { |
7473 | case VSPLUS: | 7476 | case VSPLUS: |
7474 | varlen = -1 - varlen; | 7477 | discard ^= EXP_DISCARD; |
7475 | /* fall through */ | 7478 | /* fall through */ |
7476 | case 0: | 7479 | case 0: |
7477 | case VSMINUS: | 7480 | case VSMINUS: |
7478 | p = argstr(p, flag | EXP_TILDE | EXP_WORD); | 7481 | p = argstr(p, flag | EXP_TILDE | EXP_WORD | (discard ^ EXP_DISCARD)); |
7479 | if (varlen < 0) | ||
7480 | return p; | ||
7481 | goto record; | 7482 | goto record; |
7482 | 7483 | ||
7483 | case VSASSIGN: | 7484 | case VSASSIGN: |
7484 | case VSQUESTION: | 7485 | case VSQUESTION: |
7485 | if (varlen >= 0) | ||
7486 | goto record; | ||
7487 | |||
7488 | p = subevalvar(p, var, 0, startloc, varflags, | 7486 | p = subevalvar(p, var, 0, startloc, varflags, |
7489 | flag & ~QUOTES_ESC); | 7487 | (flag & ~QUOTES_ESC) | (discard ^ EXP_DISCARD)); |
7490 | 7488 | ||
7491 | if (flag & EXP_DISCARD) | 7489 | if ((flag | ~discard) & EXP_DISCARD) |
7492 | return p; | 7490 | goto record; |
7493 | 7491 | ||
7494 | varflags &= ~VSNUL; | 7492 | varflags &= ~VSNUL; |
7493 | subtype = VSNORMAL; | ||
7495 | goto again; | 7494 | goto again; |
7496 | } | 7495 | } |
7497 | 7496 | ||
7498 | if (varlen < 0 && uflag) | 7497 | if ((discard & ~flag) && uflag) |
7499 | varunset(p, var, 0, 0); | 7498 | varunset(p, var, 0, 0); |
7500 | 7499 | ||
7501 | if (subtype == VSLENGTH) { | 7500 | if (subtype == VSLENGTH) { |
@@ -7503,7 +7502,7 @@ evalvar(char *p, int flag) | |||
7503 | if (flag & EXP_DISCARD) | 7502 | if (flag & EXP_DISCARD) |
7504 | return p; | 7503 | return p; |
7505 | cvtnum(varlen > 0 ? varlen : 0, flag); | 7504 | cvtnum(varlen > 0 ? varlen : 0, flag); |
7506 | goto record; | 7505 | goto really_record; |
7507 | } | 7506 | } |
7508 | 7507 | ||
7509 | if (subtype == VSNORMAL) | 7508 | if (subtype == VSNORMAL) |
@@ -7528,7 +7527,7 @@ evalvar(char *p, int flag) | |||
7528 | } | 7527 | } |
7529 | #endif | 7528 | #endif |
7530 | 7529 | ||
7531 | flag |= varlen < 0 ? EXP_DISCARD : 0; | 7530 | flag |= discard; |
7532 | if (!(flag & EXP_DISCARD)) { | 7531 | if (!(flag & EXP_DISCARD)) { |
7533 | /* | 7532 | /* |
7534 | * Terminate the string and start recording the pattern | 7533 | * Terminate the string and start recording the pattern |
@@ -7541,9 +7540,10 @@ evalvar(char *p, int flag) | |||
7541 | p = subevalvar(p, NULL, patloc, startloc, varflags, flag); | 7540 | p = subevalvar(p, NULL, patloc, startloc, varflags, flag); |
7542 | 7541 | ||
7543 | record: | 7542 | record: |
7544 | if (flag & EXP_DISCARD) | 7543 | if ((flag | discard) & EXP_DISCARD) |
7545 | return p; | 7544 | return p; |
7546 | 7545 | ||
7546 | really_record: | ||
7547 | if (quoted) { | 7547 | if (quoted) { |
7548 | quoted = *var == '@' && shellparam.nparam; | 7548 | quoted = *var == '@' && shellparam.nparam; |
7549 | if (!quoted) | 7549 | if (!quoted) |