On 10/01/2019 14:21, Martijn Dekker wrote:
Op 10-01-19 om 11:37 schreef Martijn Dekker:
In a dot script sourced with 'command .' (which is useful to avoid
exiting if the script doesn't exist), triggering a syntax error in an
'eval' in a subshell causes dash to hang at the end of the main script.
In fact, 'eval' doesn't appear related. I can also trigger the bug by
triggering an error in another special builtin:
command . /dev/stdin <<EOF
( set -o foobar ) && echo WOOPS
EOF
echo end
I do not see a hang myself, but I definitely see wrong behaviour: the
output I get is
$ command . /dev/stdin <<EOF
> ( set -o foobar ) && echo WOOPS
> EOF
src/dash: 1: set: Illegal option -o foobar
$ echo end
end
$ <Ctrl-D>
WOOPS
$
This was introduced by
commit 46d5a7fcea81b489819f753451c1ad2fe435f148
Author: Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx>
Date: Tue Mar 27 00:39:35 2018 +0800
eval: Restore input files in evalcommand
When evalcommand invokes a command that modifies parsefile and
then bails out without popping the file, we need to ensure the
input file is restored so that the shell can continue to execute.
What I think it going on here, although I do not understand it
completely yet, is:
evalcommand invokes a command that modifies parsefile: that's the dot
command. The evaluation of the dotted file involves creating a subshell,
and because of the invalid option, that subshell exits with EXERROR.
Because the subshell is invoked from within the command builtin, that
EXERROR is eaten, and the input file is restored. The subshell then
happily continues reading commands at the same time as the parent shell.
Although this particular example used to work before that specific
commit, I suspect the underlying problem had been there already and
other examples could expose it just as well.
Fundamentally, I think an important question to ask is whether
command . /dev/stdin <<EOF
set -o invalid
echo a
EOF
echo b
is supposed to abort the shell because of the invalid option, and if
not, whether it should print a and b, or only b. Personally, I think
there is nothing in POSIX to suggest that only b gets printed: either
the special property of special built-in utilities that they cause the
shell to exit on error apply, in which case nothing gets printed, or
they do not apply, in which both a and b get printed. Nonetheless,
printing b is the most popular result:
bash/yash/zsh print nothing.
dash/ksh/mksh/pdksh/posh print b.
bosh prints a and b.
My personal feeling is that "print nothing" is the correct result: the
command built-in should only cause the immediately invoked command to
not be treated as a special built-in utility, not anything indirectly
invoked by that.
Cheers,
Harald van Dijk