diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2021-09-07 01:54:23 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2021-09-07 02:01:03 +0200 |
commit | f415e21a7dce1d4f4b760fddfaba85c551681e11 (patch) | |
tree | 1c126cfd0ff6193b151db4fddaf79fac3d822dfd | |
parent | 41beb53787ec798a27f336c4758cb5ebd8f0c75a (diff) | |
download | busybox-w32-f415e21a7dce1d4f4b760fddfaba85c551681e11.tar.gz busybox-w32-f415e21a7dce1d4f4b760fddfaba85c551681e11.tar.bz2 busybox-w32-f415e21a7dce1d4f4b760fddfaba85c551681e11.zip |
ash: eval: Do not cache value of eflag in evaltree
Upsteam commit:
Date: Mon, 17 May 2021 15:19:23 +0800
eval: Do not cache value of eflag in evaltree
Patrick BrĂ¼nn <P.Bruenn@beckhoff.com> wrote:
> Since we are migrating to Debian bullseye, we discovered a new behavior
> with our scripts, which look like this:
>>cleanup() {
>> set +e
>> rmdir ""
>>}
>>set -eu
>>trap 'cleanup' EXIT INT TERM
>>echo 'Hello world!'
>
> With old dash v0.5.10.2 this script would return 0 as we expected it.
> But since commit 62cf6955f8abe875752d7163f6f3adbc7e49ebae it returns
> the last exit code of our cleanup function.
...
Thanks for the report. This is actually a fairly old bug with
set -e that's just been exposed by the exit status change. What's
really happening is that cleanup itself is triggering a set -e
exit incorrectly because evaltree cached the value of eflag prior
to the function call.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | shell/ash.c | 15 | ||||
-rw-r--r-- | shell/ash_test/ash-misc/exitcode_trap7.right | 2 | ||||
-rwxr-xr-x | shell/ash_test/ash-misc/exitcode_trap7.tests | 7 |
3 files changed, 16 insertions, 8 deletions
diff --git a/shell/ash.c b/shell/ash.c index 2d2c09ba5..c65f09782 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -9336,8 +9336,7 @@ evaltree(union node *n, int flags) | |||
9336 | case NCMD: | 9336 | case NCMD: |
9337 | evalfn = evalcommand; | 9337 | evalfn = evalcommand; |
9338 | checkexit: | 9338 | checkexit: |
9339 | if (!(flags & EV_TESTED)) | 9339 | checkexit = ~flags & EV_TESTED; |
9340 | checkexit = ~0; | ||
9341 | goto calleval; | 9340 | goto calleval; |
9342 | case NFOR: | 9341 | case NFOR: |
9343 | evalfn = evalfor; | 9342 | evalfn = evalfor; |
@@ -9359,7 +9358,6 @@ evaltree(union node *n, int flags) | |||
9359 | case NAND: | 9358 | case NAND: |
9360 | case NOR: | 9359 | case NOR: |
9361 | case NSEMI: { | 9360 | case NSEMI: { |
9362 | |||
9363 | #if NAND + 1 != NOR | 9361 | #if NAND + 1 != NOR |
9364 | #error NAND + 1 != NOR | 9362 | #error NAND + 1 != NOR |
9365 | #endif | 9363 | #endif |
@@ -9387,8 +9385,7 @@ evaltree(union node *n, int flags) | |||
9387 | if (!status) { | 9385 | if (!status) { |
9388 | n = n->nif.ifpart; | 9386 | n = n->nif.ifpart; |
9389 | goto evaln; | 9387 | goto evaln; |
9390 | } | 9388 | } else if (n->nif.elsepart) { |
9391 | if (n->nif.elsepart) { | ||
9392 | n = n->nif.elsepart; | 9389 | n = n->nif.elsepart; |
9393 | goto evaln; | 9390 | goto evaln; |
9394 | } | 9391 | } |
@@ -9410,7 +9407,7 @@ evaltree(union node *n, int flags) | |||
9410 | */ | 9407 | */ |
9411 | dotrap(); | 9408 | dotrap(); |
9412 | 9409 | ||
9413 | if (checkexit & status) { | 9410 | if (checkexit && status) { |
9414 | if (trap[NTRAP_ERR] && !in_trap_ERR) { | 9411 | if (trap[NTRAP_ERR] && !in_trap_ERR) { |
9415 | int err; | 9412 | int err; |
9416 | struct jmploc *volatile savehandler = exception_handler; | 9413 | struct jmploc *volatile savehandler = exception_handler; |
@@ -9434,10 +9431,12 @@ evaltree(union node *n, int flags) | |||
9434 | exitstatus = savestatus; | 9431 | exitstatus = savestatus; |
9435 | } | 9432 | } |
9436 | if (eflag) | 9433 | if (eflag) |
9437 | raise_exception(EXEND); | 9434 | goto exexit; |
9438 | } | 9435 | } |
9439 | if (flags & EV_EXIT) | 9436 | if (flags & EV_EXIT) { |
9437 | exexit: | ||
9440 | raise_exception(EXEND); | 9438 | raise_exception(EXEND); |
9439 | } | ||
9441 | 9440 | ||
9442 | popstackmark(&smark); | 9441 | popstackmark(&smark); |
9443 | TRACE(("leaving evaltree (no interrupts)\n")); | 9442 | TRACE(("leaving evaltree (no interrupts)\n")); |
diff --git a/shell/ash_test/ash-misc/exitcode_trap7.right b/shell/ash_test/ash-misc/exitcode_trap7.right new file mode 100644 index 000000000..07d66e9d9 --- /dev/null +++ b/shell/ash_test/ash-misc/exitcode_trap7.right | |||
@@ -0,0 +1,2 @@ | |||
1 | Start | ||
2 | Ok:0 | ||
diff --git a/shell/ash_test/ash-misc/exitcode_trap7.tests b/shell/ash_test/ash-misc/exitcode_trap7.tests new file mode 100755 index 000000000..9772a7b8c --- /dev/null +++ b/shell/ash_test/ash-misc/exitcode_trap7.tests | |||
@@ -0,0 +1,7 @@ | |||
1 | $THIS_SH -c ' | ||
2 | cleanup() { set +e; false; } | ||
3 | set -eu | ||
4 | trap cleanup EXIT | ||
5 | echo Start | ||
6 | ' | ||
7 | echo Ok:$? | ||