diff options
author | Peter Stephenson <p.w.stephenson@ntlworld.com> | 2017-04-27 18:56:18 +0100 |
---|---|---|
committer | Peter Stephenson <p.w.stephenson@ntlworld.com> | 2017-04-27 18:56:18 +0100 |
commit | d7110d8f01cae8c8d51c7abd0255f533cd8b8623 (patch) | |
tree | 238931229fcf7831c7ff5f41212f9626167fbb63 | |
parent | 48b0daf3d4972987873f1be00cc73d73734daf05 (diff) | |
download | zsh-d7110d8f01cae8c8d51c7abd0255f533cd8b8623.tar.gz zsh-d7110d8f01cae8c8d51c7abd0255f533cd8b8623.tar.xz zsh-d7110d8f01cae8c8d51c7abd0255f533cd8b8623.zip |
41012: Fix premature exit from nested function in EXIT trap.
Also add check so we don't delay an exit if we were already in an EXIT trap for the main shell, as we should in that case leave immediately.
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | Src/builtin.c | 23 | ||||
-rw-r--r-- | Src/exec.c | 5 | ||||
-rw-r--r-- | Src/signals.c | 11 | ||||
-rw-r--r-- | Test/C03traps.ztst | 21 |
5 files changed, 60 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog index fb0d379e2..243957455 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2017-04-27 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 41012: Src/builtin.c, Src/exec.c, Src/signals.c, + Test/C03traps.ztst: Fix early exit from nested functions in EXIT + trap. Drive-by fix of testing for need to exit if exiting when + already in EXIT trap for main shell --- we should just leave + immediately. + 2017-04-27 Peter Stephenson <p.stephenson@samsung.com> * 41016: Test/A01grammar.ztst: test that quoted precommand diff --git a/Src/builtin.c b/Src/builtin.c index b2e552db7..063644efb 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -5500,7 +5500,7 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func) } /*FALLTHROUGH*/ case BIN_EXIT: - if (locallevel > forklevel) { + if (locallevel > forklevel && shell_exiting != -1) { /* * We don't exit directly from functions to allow tidying * up, in particular EXIT traps. We still need to perform @@ -5509,6 +5509,9 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func) * * If we are forked, we exit the shell at the function depth * at which we became a subshell, hence the comparison. + * + * If we are already exiting... give this all up as + * a bad job. */ if (stopmsg || (zexit(0,2), !stopmsg)) { retflag = 1; @@ -5555,6 +5558,14 @@ checkjobs(void) } } +/* + * -1 if the shell is already committed to exit. + * positive if zexit() was already called. + */ + +/**/ +int shell_exiting; + /* exit the shell. val is the return value of the shell. * * from_where is * 1 if zexit is called because of a signal @@ -5566,10 +5577,8 @@ checkjobs(void) mod_export void zexit(int val, int from_where) { - static int in_exit; - /* Don't do anything recursively: see below */ - if (in_exit == -1) + if (shell_exiting == -1) return; if (isset(MONITOR) && !stopmsg && from_where != 1) { @@ -5582,14 +5591,14 @@ zexit(int val, int from_where) } } /* Positive in_exit means we have been here before */ - if (from_where == 2 || (in_exit++ && from_where)) + if (from_where == 2 || (shell_exiting++ && from_where)) return; /* - * We're now committed to exiting. Set in_exit to -1 to + * We're now committed to exiting. Set shell_exiting to -1 to * indicate we shouldn't do any recursive processing. */ - in_exit = -1; + shell_exiting = -1; /* * We want to do all remaining processing regardless of preceding * errors, even user interrupts. diff --git a/Src/exec.c b/Src/exec.c index 978a32d20..e0fc54445 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -5688,8 +5688,11 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) * the only likely case where we need that second test is * when we have an "always" block. The endparamscope() has * already happened, hence the "+1" here. + * + * If we are in an exit trap, finish it first... we wouldn't set + * exit_pending if we were already in one. */ - if (exit_pending && exit_level >= locallevel+1) { + if (exit_pending && exit_level >= locallevel+1 && !in_exit_trap) { if (locallevel > forklevel) { /* Still functions to return: force them to do so. */ retflag = 1; diff --git a/Src/signals.c b/Src/signals.c index 68a7ae34d..cad40f4eb 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -55,6 +55,11 @@ mod_export Eprog siglists[VSIGCOUNT]; /**/ mod_export int nsigtrapped; +/* Running an exit trap? */ + +/**/ +int in_exit_trap; + /* * Flag that exit trap has been set in POSIX mode. * The setter's expectation is therefore that it is run @@ -1435,7 +1440,13 @@ dotrap(int sig) dont_queue_signals(); + if (sig == SIGEXIT) + ++in_exit_trap; + dotrapargs(sig, sigtrapped+sig, funcprog); + if (sig == SIGEXIT) + --in_exit_trap; + restore_queue_signals(q); } diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst index 7bc0b486d..759401225 100644 --- a/Test/C03traps.ztst +++ b/Test/C03traps.ztst @@ -756,6 +756,27 @@ F:Must be tested with a top-level script rather than source or function >'' >hello + $ZTST_testdir/../Src/zsh -f =(<<<" + trap handler EXIT + handler() { + echoa + echo b + } + echoa() { + echo a + } + exit0() { + exit + } + main() { + exit0 + } + main + ") +0:No early exit from nested function in EXIT trap. +>a +>b + %clean rm -f TRAPEXIT |