#1134345 mksh: over-eager set -e in eval in conditional

Package:
mksh
Source:
mksh
Description:
MirBSD Korn Shell
Submitter:
brian m. carlson
Date:
2026-04-19 01:35:01 UTC
Severity:
normal
#1134345#5
Date:
2026-04-18 22:09:40 UTC
From:
To:
Git is starting to optionally run its testsuite under `set -e` and so
I've been testing various shells in that configuration.  I noticed that
mksh and lksh appear to mishandle `set -e` in some circumstances.

For instance, with the script below, mksh prints `not ok 1`, whereas
dash, bash, zsh, and posh print `ok 1`.

POSIX[0] states the following about `set -e`:

    When this option is on, when any command fails (for any of the
    reasons listed in 2.8.1 Consequences of Shell Errors or by returning
    an exit status greater than zero), the shell immediately shall exit,
    as if by executing the exit special built-in utility with no
    arguments, with the following exceptions:

    [...]

    The -e setting shall be ignored when executing the compound list
    following the while, until, if, or elif reserved word, a pipeline
    beginning with the ! reserved word, or any command of an AND-OR list
    other than the last.

It appears mksh is mishandling this case because the `check_command`
function is exiting unsuccessfully (due to the `test` not matching) even
though the command if being run under an `if` in `test_run`, which
should disable existing on `set -e`.

It would be nice if this could be fixed, since I often recommend mksh as
a portable shell that people can use to run the Git testsuite (which
requires POSIX conformance as well as `local`; roughly a subset of
Debian `/bin/sh` requirements).

Output:
----
% dash test.sh
ok 1
1..2
% bash test.sh
ok 1
1..2
% zsh test.sh
ok 1
1..2
% posh test.sh
ok 1
1..2
% mksh test.sh
not ok 1
1..2
% lksh test.sh
not ok 1
1..2
----

Script test.sh:
----
#!/bin/sh

set -e

TESTNUM=1

test_run_ () {
    eval "$1"
}

test_run () {
    local body="$1"
    if test_run_ "$body"
    then
        echo "ok $TESTNUM"
    else
        echo "not ok $TESTNUM"
    fi
    TESTNUM=$((TESTNUM + 1))
}

test_done () {
    echo "1..$TESTNUM"
}

check_command () {
    test "$1" = barbaz
    case "$1" in
        foobar)
            ;;
        barbaz)
            ;;
    esac
}

test_run '
    check_command foobar
'

test_done
----

[0] https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_26

#1134345#10
Date:
2026-04-19 00:55:19 UTC
From:
To:
retitle 1134345 mksh: over-eager set -e in eval in conditional
thanks

Seems to be the “eval” that’s throwing this off. This is because
internally, “eval” is a bit disconnected from the rest of the
parsing. I can see whether I can fix this, but I *think* it will
require some amount of passing more things down the callstack…

I have a reduced testcase:

set -e
if eval 'false; true'; then echo 1; else echo 0; fi

Something like…

if { false; true; }; then echo 1; else echo 0; fi

… doesn’t differ between mksh and GNU bash, only the eval case.

Given how widespread the shells with this issue are, I suggest
rewording the test harness slightly to work around this, for
the next seven years or so.

test_run_() {
	eval "test_run__() {
		$1
	}"
	test_run__ "$@"
}

That is, define a temporary function with eval,
then run that function outside of eval.

I’d be glad if you could convey this to affected users.
Meanwhile thanks for discovering this.

bye,
//mirabilos

#1134345#17
Date:
2026-04-19 01:25:24 UTC
From:
To:
The good news is that the `set -e` functionality only handles bash 5 at
the moment (because bash 3 on macOS is buggy) and the testsuite
otherwise continues to use `&&` between all statements for error
checking.  If the `set -e` functionality is not enabled (which it is not
by default), then the testsuite passes just fine with mksh and lksh, so
I can continue to recommend those as good shell options.  We just won't
enable that functionality by default on mksh or lksh except on a patched
version; it's no big deal.

In other words, my local development version of Git is the only
environment affected by this and no other users have reported the
problem.

If you come out with a patch for this at some point, I'm happy to test
it, since we had a few test failures with mksh and `set -e` mode, but my
guess is that they're all a variant of this case.