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) |
