Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Bug with trap?



On Mon, 3 May 2010 20:14:04 +0100
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx> wrote:
> On Mon, 3 May 2010 21:49:50 +0300
> "Nadav Har'El" <nyh@xxxxxxxxxxxxxxxxxxx> wrote:
> > On Fri, Apr 30, 2010, Omari Norman wrote about "Bug with trap?":
> > > It seems that the trap builtin with the EXIT argument does not work
> > > properly if you have a list inside curly braces and the output is piped
> > > to another command. For example:
> > >...
> > > { trap "echo exit trap running" EXIT} | cat
> > >...
> > > Thus the trap in the last example simply did not run. You can try this
> > > with another command in the trap (e.g. touch, or rm) and you will get
> > > the same result: the trap does not run.
> > > 
> > > This is zsh 4.3.6 on Debian 5.0. Is this a bug or am I missing
> > > something?
> > 
> > This is not a bug, but rather a result of the way that shells (not just zsh)
> > do pipes.
> 
> I was wondering along the lines you suggest, but the counterargument is
> that if you do:
> 
> zsh -fc '{ trap "echo exit trap running" EXIT; exit} | cat'
> 
> you get the expected message when the left-hand-side (explicitly) exits.
> It's not clear to me it should be different on an implicit exit.

I don't think it should, I think this is just a bug in a special case in
the code:  a left hand side run in the current shell causes a fork in an
place that's not part of the normal execution path.

bash (4.0.35) does what zsh does before this patch, only executes the
trap on an explicit exit.  It's in the standard that it's required in
that case ("A trap on EXIT shall be executed before the shell
terminates, except when the exit utility is invoked in that trap itself,
in which case the shell shall exit immediately"), but I'm not aware of
any statement limiting execution of traps to explicit exits, and that's
certainly not what happens in an ordinary script.

There are rules about when traps get implicitly unset---so you wouldn't
usually see this problem because any EXIT trap set in the parent shell
would no longer be set in the pipeline---but that's a different
matter that doesn't apply here because the trap is explicitly set
within the pipeline.

Separately, I think passing last1 down to execcmd() here is also correct
since we know the shell is going to exit after the command.  I'm not
sure why it was ever 0; unless I'm much mistaken the fact the shell is
about to exit is entirely sufficient grounds for using it (we test for
things like traps before exiting early).

Further discussion on the internal behaviour should go on zsh-workers.

Index: Src/exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.177
diff -p -u -r1.177 exec.c
--- Src/exec.c	24 Feb 2010 21:38:10 -0000	1.177
+++ Src/exec.c	4 May 2010 19:03:26 -0000
@@ -1631,7 +1631,9 @@ execpline2(Estate state, wordcode pcode,
 		entersubsh(((how & Z_ASYNC) ? ESUB_ASYNC : 0)
 			   | ESUB_PGRP | ESUB_KEEPTRAP);
 		close(synch[1]);
-		execcmd(state, input, pipes[1], how, 0);
+		execcmd(state, input, pipes[1], how, 1);
+		if (sigtrapped[SIGEXIT])
+		    dotrap(SIGEXIT);
 		_exit(lastval);
 	    }
 	} else {
Index: Test/C03traps.ztst
===================================================================
RCS file: /cvsroot/zsh/zsh/Test/C03traps.ztst,v
retrieving revision 1.17
diff -p -u -r1.17 C03traps.ztst
--- Test/C03traps.ztst	31 Aug 2008 19:50:49 -0000	1.17
+++ Test/C03traps.ztst	4 May 2010 19:03:26 -0000
@@ -350,6 +350,9 @@
 >trap
 >Working 0
 
+   { trap 'echo This subshell is exiting' EXIT; } | cat
+0: EXIT trap set in current shell at left of pipeline
+>This subshell is exiting
 
 %clean
 

-- 
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/



Messages sorted by: Reverse Date, Date, Thread, Author