bin/74404: sh does not handle signals to subshells properly and/or $! is broken

Mike Silbersack silby at silby.com
Fri Nov 26 00:10:19 PST 2004


>Number:         74404
>Category:       bin
>Synopsis:       sh does not handle signals to subshells properly and/or $! is broken
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Fri Nov 26 08:10:18 GMT 2004
>Closed-Date:
>Last-Modified:
>Originator:     Mike Silbersack
>Release:        FreeBSD 6.0-CURRENT i386
>Organization:
>Environment:
System: FreeBSD patrocles.silby.com 6.0-CURRENT FreeBSD 6.0-CURRENT #2: Thu Nov 25 01:13:18 CST 2004 silby at patrocles.silby.com:/usr/obj/usr/src/sys/PATROCLES i386


	
Description:
	/bin/sh in the base system has an oddity in how it handles signals
to subshells.  If you run the supplied script (known as badsh.sh), you will
find that the subshell will not be terminated by the script, and the
"You didn't get me!" line will be printed.

Under bash, the subshell is killed as expected.

The reason for this issue appears to be due to a few things:

1.  sh spawns forks TWO copies of itself when creating the subshell.

2.  The first subshell's PID is returned by $!; this subshell then
forks again and creates the second subshell, which actually does
the sleep and echo.

3.  The first subshell does not pass on signals to the second subshell.
As a result, the kill signal is never delivered to the second subshell,
and it is not terminated.

This is frustrating behavior because aside from kill $! + 1 (which would be
a gross hack), the only way to kill the subshell would be to use ps | grep
something or other > kill.  So, the best fix would be for the 1st subshell
to simply pass on the kill signal to the second subshell before it dies.

This behavior happens on 6.0 and 4.10; I have not tested other OS versions.
Since bash handles it in what appears to be the correct fashion, this seems
to be a bug in sh.

How-To-Repeat:

This test program will help you see the issue:

#!/bin/sh
echo $$
    (
        sleep 10
	echo "You didn't get me!"
        exit 1
        )&
        echo $!
        kill $!
        exit 1

Immediately after running it, use ps and see how many /bin/sh processes are running.
Comment out the kill line and compare.

Fix:
	None at this time... using bash instead could be an alternative.


>Description:
>How-To-Repeat:
>Fix:
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list