Exit unexpectedly when errexit is enabled
ko1nksm opened this issue · 3 comments
Hello,
First off, thank you for your impressive project.
I was looking for various POSIX shell implementations and found your project. The goal of this project seems to be to formalize the POSIX shell standard, but I have determined that you are also developing an executable POSIX shell.
I was assuming that smoosh would actually work, but the following code terminated unexpectedly.
set -e
putsn() { echo "$@"; }
false && true
putsn "It should be executed" # Not executed by smoosh.
I'm developing ShellSpec, a unit testing framework that works with POSIX shells, and one of its goals is to support all POSIX shells. The goal is almost achieved, and it already works with almost all POSIX shells (even if there are some bugs). As part of this development, I am reporting a bug of the shell.
Due to the above bug, smoosh is not yet working with ShellSpec. If your project its (one of) goals is to develop an executable POSIX shell, I will gladly report back.
Regards,
Thanks for the bug report! (Quick tip: saying someone's software "doesn't actually work" when you've found a single bug isn't the nicest way to say hello.)
I suspect this is an issue with exit-code carryover; I'll take a look soon.
I took a look, it is. When run_command
returns with a Call
to step_eval
, the error code is still set to 1 and the error checking makes it fail. As far as I can tell, keeping the error code is the right thing to do:
$ tests/cmp/test.sh 'pe() { echo 0; }; false; pe'
smoosh: OUT [1] ERR [] EC [0]
bash-posix: OUT [1] ERR [] EC [0]
bash: OUT [1] ERR [] EC [0]
dash: OUT [1] ERR [] EC [0]
zsh-posix: OUT [1] ERR [] EC [0]
zsh: OUT [1] ERR [] EC [0]
osh: OUT [1] ERR [] EC [0]
mksh: OUT [1] ERR [] EC [0]
ksh: OUT [1] ERR [] EC [0]
yash-posix: OUT [1] ERR [] EC [0]
yash: OUT [1] ERR [] EC [0]
Making Call
a special case works and does not seem to break any of the working tests:
diff --git a/src/semantics.lem b/src/semantics.lem
index d838ca4..e8a221f 100644
--- a/src/semantics.lem
+++ b/src/semantics.lem
@@ -894,13 +894,18 @@ and step_eval s0 checked stmt =
not opts.force_simple_command &&
not (is_interactive s1)) (* per table in 2.8.1 *)
in
+ let is_call stms =
+ match stms with
+ | Call _ _ _ _ _ -> true
+ | _ -> false
+ end in
(* load exported variables, perform assignments *)
let env = Map.fromList assigns in
match run_command s1 opts checked prog args env with
| Right (s2, stmt', restore) ->
(XSSimple ("ran " ^ string_of_symbolic_string prog),
s2,
- if catching_errors && s2.sh.exit_code <> 0
+ if catching_errors && s2.sh.exit_code <> 0 && not (is_call stmt')
then Exit
else if restore
then pushredir stmt' saved_fds
But maybe there's a better way to fix this.
It's not just functions: the Wait
that gets generated from actual commands also causes early exit.
$ set -e
$ false && true; /usr/bin/true
[EXIT]
I think the right solution is to only do the exit code test when stmt'
is Done
(and maybe other terminating control... will need to test).