* Call stack issues when running trap handler @ 2017-04-21 20:32 ` Sebastian Reuße 2017-04-21 22:19 ` Bart Schaefer ` (2 more replies) 0 siblings, 3 replies; 10+ messages in thread From: Sebastian Reuße @ 2017-04-21 20:32 UTC (permalink / raw) To: zsh-workers I’ve noticed that under certain conditions, shell functions called from inside an exit trap handler appear to never return. E.g., running the following code will only yield «a» as output, indicating that callee «echoa» never returns control to the caller «handler». #+begin_src shell trap handler EXIT handler() { echoa echo b } echoa() { echo a } exit0() { exit } main() { exit0 } main #+end_src When directly calling «exit0» or «exit» instead of «main», this issue does not arise. I was able to reproduce this both in Zsh 5.3.1 as well as today’s HEAD. Kind regards, SR ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Call stack issues when running trap handler 2017-04-21 20:32 ` Call stack issues when running trap handler Sebastian Reuße @ 2017-04-21 22:19 ` Bart Schaefer 2017-04-24 9:00 ` Peter Stephenson 2017-04-26 19:27 ` Peter Stephenson 2 siblings, 0 replies; 10+ messages in thread From: Bart Schaefer @ 2017-04-21 22:19 UTC (permalink / raw) To: zsh-workers On Apr 21, 10:32pm, Sebastian Reusse wrote: } } I've noticed that under certain conditions, shell functions called from } inside an exit trap handler appear to never return. Whatever this is dates back a long time. In zsh-3, the sample script doesn't appear to call the exit trap at all via "main" or "exit0" though it does if "exit" is called directly. In zsh-4 the behavior is the same as in current zsh-5. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Call stack issues when running trap handler 2017-04-21 20:32 ` Call stack issues when running trap handler Sebastian Reuße 2017-04-21 22:19 ` Bart Schaefer @ 2017-04-24 9:00 ` Peter Stephenson 2017-04-24 16:16 ` Bart Schaefer 2017-04-26 19:27 ` Peter Stephenson 2 siblings, 1 reply; 10+ messages in thread From: Peter Stephenson @ 2017-04-24 9:00 UTC (permalink / raw) To: zsh-workers On Fri, 21 Apr 2017 22:32:46 +0200 Sebastian Reuße <seb@wirrsal.net> wrote: > I’ve noticed that under certain conditions, shell functions called from > inside an exit trap handler appear to never return. E.g., running the > following code will only yield «a» as output, indicating that callee > «echoa» never returns control to the caller «handler». This is working OK for me, in my normal configuration or starting from scratch, so there appears to be some other ingredient to add. pws ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Call stack issues when running trap handler 2017-04-24 9:00 ` Peter Stephenson @ 2017-04-24 16:16 ` Bart Schaefer 2017-04-24 17:17 ` Peter Stephenson 0 siblings, 1 reply; 10+ messages in thread From: Bart Schaefer @ 2017-04-24 16:16 UTC (permalink / raw) To: Peter Stephenson; +Cc: zsh-workers On Mon, Apr 24, 2017 at 2:00 AM, Peter Stephenson <p.stephenson@samsung.com> wrote: > On Fri, 21 Apr 2017 22:32:46 +0200 > > This is working OK for me, in my normal configuration or starting > from scratch, so there appears to be some other ingredient to add. I am able to reproduce Sebastian's symptom exactly when starting any version from current back to 4.3.17. So if there's an ingredient, it's yours to make it work correctly. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Call stack issues when running trap handler 2017-04-24 16:16 ` Bart Schaefer @ 2017-04-24 17:17 ` Peter Stephenson 2017-04-24 17:39 ` Bart Schaefer 0 siblings, 1 reply; 10+ messages in thread From: Peter Stephenson @ 2017-04-24 17:17 UTC (permalink / raw) To: zsh-workers On Mon, 24 Apr 2017 09:16:55 -0700 Bart Schaefer <schaefer@brasslantern.com> wrote: > On Mon, Apr 24, 2017 at 2:00 AM, Peter Stephenson > <p.stephenson@samsung.com> wrote: > > On Fri, 21 Apr 2017 22:32:46 +0200 > > > > This is working OK for me, in my normal configuration or starting > > from scratch, so there appears to be some other ingredient to add. > > I am able to reproduce Sebastian's symptom exactly when starting any > version from current back to 4.3.17. > > So if there's an ingredient, it's yours to make it work correctly. I'm aware others can reproduce it; my only point is I can't so won't be looking at it. pws ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Call stack issues when running trap handler 2017-04-24 17:17 ` Peter Stephenson @ 2017-04-24 17:39 ` Bart Schaefer 0 siblings, 0 replies; 10+ messages in thread From: Bart Schaefer @ 2017-04-24 17:39 UTC (permalink / raw) To: Peter Stephenson; +Cc: zsh-workers On Mon, Apr 24, 2017 at 10:17 AM, Peter Stephenson <p.stephenson@samsung.com> wrote: > > I'm aware others can reproduce it; my only point is I can't so won't be > looking at it. OK. Perhaps I should know this from previous exchanges, but could you describe the environment in which it works? E.g. it fails for me on all of MacOS 10.9.5 and Ubuntu 12.04.5 and on an embarrassingly old CentOS virtual machine, all built from latest git and started from scratch with "zsh -f". ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Call stack issues when running trap handler 2017-04-21 20:32 ` Call stack issues when running trap handler Sebastian Reuße 2017-04-21 22:19 ` Bart Schaefer 2017-04-24 9:00 ` Peter Stephenson @ 2017-04-26 19:27 ` Peter Stephenson 2017-04-26 19:52 ` Peter Stephenson 2 siblings, 1 reply; 10+ messages in thread From: Peter Stephenson @ 2017-04-26 19:27 UTC (permalink / raw) To: zsh-workers On Fri, 21 Apr 2017 22:32:46 +0200 Sebastian Reuße <seb@wirrsal.net> wrote: > I’ve noticed that under certain conditions, shell functions called from > inside an exit trap handler appear to never return. E.g., running the > following code will only yield «a» as output, indicating that callee > «echoa» never returns control to the caller «handler». I've just re-read this and compared with the evidence and obviously I've misinterpreted it. When you said "never return", you meant it exited from that point (so never printed "b" but did leave the shell nonetheless). I interpreted this as saying it got stuck in that function, but that obviously isn't what you mean. This I can fix. If anyone knows whether I need to distinguish in any of the following between EXIT traps for functions and the shell as a whole, feel free to tell me. I'm assuming it's going to be too arcane to worry about. pws diff --git a/Src/builtin.c b/Src/builtin.c index b2e552d..ff07b04 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -5509,8 +5509,11 @@ 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* in an EXIT trap... give this all up as + * a bad job. */ - if (stopmsg || (zexit(0,2), !stopmsg)) { + if ((stopmsg || (zexit(0,2), !stopmsg)) && !in_exit_trap) { retflag = 1; breaks = loops; exit_pending = (num << 1) | 1; diff --git a/Src/exec.c b/Src/exec.c index 978a32d..e0fc544 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 68a7ae3..cad40f4 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); } ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Call stack issues when running trap handler 2017-04-26 19:27 ` Peter Stephenson @ 2017-04-26 19:52 ` Peter Stephenson 2017-04-26 21:15 ` Bart Schaefer 2017-05-11 7:58 ` Sebastian Reuße 0 siblings, 2 replies; 10+ messages in thread From: Peter Stephenson @ 2017-04-26 19:52 UTC (permalink / raw) To: zsh-workers On Wed, 26 Apr 2017 20:27:29 +0100 Peter Stephenson <p.w.stephenson@ntlworld.com> wrote: > This I can fix. I think I like this better. shell_exiting looks like a good way of ensuring we don't tie ourselves in knots with exits, independent of in_exit_trap which we still need for the original fix. The interaction is that when we commit to exiting shell_exiting goes to -1; then we won't set exit_pending in zexit(); that means we don't hit the case that caused us to exit early. Or something. pws diff --git a/Src/builtin.c b/Src/builtin.c index b2e552d..063644e 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 978a32d..e0fc544 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 68a7ae3..cad40f4 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 7bc0b48..7594012 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 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Call stack issues when running trap handler 2017-04-26 19:52 ` Peter Stephenson @ 2017-04-26 21:15 ` Bart Schaefer 2017-05-11 7:58 ` Sebastian Reuße 1 sibling, 0 replies; 10+ messages in thread From: Bart Schaefer @ 2017-04-26 21:15 UTC (permalink / raw) To: zsh-workers On Apr 26, 8:52pm, Peter Stephenson wrote: } } I think I like this better. I like it better, too, tho mostly because it means I can stop looking at it. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Call stack issues when running trap handler 2017-04-26 19:52 ` Peter Stephenson 2017-04-26 21:15 ` Bart Schaefer @ 2017-05-11 7:58 ` Sebastian Reuße 1 sibling, 0 replies; 10+ messages in thread From: Sebastian Reuße @ 2017-05-11 7:58 UTC (permalink / raw) To: zsh-workers > Peter Stephenson <p.w.stephenson@ntlworld.com> wrote: >> This I can fix. Only got to follow up on this now. Working fine for me on HEAD. Thank you kindly! Best regards, -- Insane cobra split the wood Trader of the lowland breed Call a jittney, drive away In the slipstream we will stay ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2017-05-11 8:30 UTC | newest] Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- [not found] <CGME20170421203315epcas2p2bcf3453e9998002d444d4fa02a87b58e@epcas2p2.samsung.com> 2017-04-21 20:32 ` Call stack issues when running trap handler Sebastian Reuße 2017-04-21 22:19 ` Bart Schaefer 2017-04-24 9:00 ` Peter Stephenson 2017-04-24 16:16 ` Bart Schaefer 2017-04-24 17:17 ` Peter Stephenson 2017-04-24 17:39 ` Bart Schaefer 2017-04-26 19:27 ` Peter Stephenson 2017-04-26 19:52 ` Peter Stephenson 2017-04-26 21:15 ` Bart Schaefer 2017-05-11 7:58 ` Sebastian Reuße
Code repositories for project(s) associated with this public inbox https://git.vuxu.org/mirror/zsh/ This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).