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>
This commit is contained in:
Denys Vlasenko 2021-09-07 01:54:23 +02:00
parent 41beb53787
commit f415e21a7d
3 changed files with 16 additions and 8 deletions

View File

@ -9336,8 +9336,7 @@ evaltree(union node *n, int flags)
case NCMD:
evalfn = evalcommand;
checkexit:
if (!(flags & EV_TESTED))
checkexit = ~0;
checkexit = ~flags & EV_TESTED;
goto calleval;
case NFOR:
evalfn = evalfor;
@ -9359,7 +9358,6 @@ evaltree(union node *n, int flags)
case NAND:
case NOR:
case NSEMI: {
#if NAND + 1 != NOR
#error NAND + 1 != NOR
#endif
@ -9387,8 +9385,7 @@ evaltree(union node *n, int flags)
if (!status) {
n = n->nif.ifpart;
goto evaln;
}
if (n->nif.elsepart) {
} else if (n->nif.elsepart) {
n = n->nif.elsepart;
goto evaln;
}
@ -9410,7 +9407,7 @@ evaltree(union node *n, int flags)
*/
dotrap();
if (checkexit & status) {
if (checkexit && status) {
if (trap[NTRAP_ERR] && !in_trap_ERR) {
int err;
struct jmploc *volatile savehandler = exception_handler;
@ -9434,10 +9431,12 @@ evaltree(union node *n, int flags)
exitstatus = savestatus;
}
if (eflag)
raise_exception(EXEND);
goto exexit;
}
if (flags & EV_EXIT)
if (flags & EV_EXIT) {
exexit:
raise_exception(EXEND);
}
popstackmark(&smark);
TRACE(("leaving evaltree (no interrupts)\n"));

View File

@ -0,0 +1,2 @@
Start
Ok:0

View File

@ -0,0 +1,7 @@
$THIS_SH -c '
cleanup() { set +e; false; }
set -eu
trap cleanup EXIT
echo Start
'
echo Ok:$?