Subject: bin/36079: /bin/sh fails to execute EXIT trap handlers for some subshells
To: None <gnats-admin@netbsd.org, netbsd-bugs@netbsd.org>
From: M. Levinson <levinsm@users.sourceforge.net>
List: netbsd-bugs
Date: 03/24/2007 12:20:00
>Number:         36079
>Category:       bin
>Synopsis:       /bin/sh fails to execute EXIT trap handlers for some subshells
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Mar 24 12:20:00 +0000 2007
>Originator:     M. Levinson
>Release:        NetBSD 4.99.16 from 2007-03-23
>Organization:
>Environment:
     $NetBSD: eval.c,v 1.88 2006/10/16 00:36:19 christos Exp $
Architecture: i386
Machine: i386
>Description:
	If the final command to be run by a subshell is a shell function
	or built-in then /bin/sh executes trap handlers for the EXIT
	pseudo-signal before that subshell exits (as expected). But if the
	final command to be run by the subshell is an external program then
	an identical trap handler won't be executed; in this case the
	subshell doesn't fork before it execs the program, so of course
	after the exec the subshell never gets a chance to call the
	exitshell() function from src/bin/sh/trap.c. With the patch below
	the subshell will fork in this case, so when the subshell exits it
	will call exitshell() and any trap handler will be executed as
	expected.

>How-To-Repeat:
	This command echoes "exiting" as expected:
		sh -c "( trap 'echo exiting' EXIT; /usr/bin/true; : )"

	But this command does not:
		sh -c "( trap 'echo exiting' EXIT; /usr/bin/true )"
	
>Fix:
	
--- src/bin/sh/eval.c	2006-10-19 06:49:12.000000000 -0500
+++ src/bin/sh/eval.c	2007-03-23 13:46:16.000000000 -0400
@@ -814,7 +814,7 @@
 
 	/* Fork off a child process if necessary. */
 	if (cmd->ncmd.backgnd
-	 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
+	 || cmdentry.cmdtype == CMDNORMAL
 	 || ((flags & EV_BACKCMD) != 0
 	    && ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN)
 		 || cmdentry.u.bltin == dotcmd