#719358 bash: Bash incorrectly handles trap when already within a signal handler

Package:
bash
Source:
bash
Description:
GNU Bourne Again SHell
Submitter:
Ben Wong
Date:
2013-08-11 11:09:06 UTC
Severity:
normal
#719358#5
Date:
2013-08-11 11:07:26 UTC
From:
To:
Dear Bash Maintainer,

Bash seems to have a bug in which it cannot reset the signal handler
(using 'trap') when already within a signal handler. Here is a sample
script that demonstrates the problem:
----------------------------------------------------------------------

#
# ackbar.sh: a test of layered trap handling in Bourne-ish shells.
# In a working shell, this script should exit when ^C is hit twice.
#

trap maybeexit 2

maybeexit() {
    trap reallyexit 2
    echo
    echo -n "Cancelling task $x"
    sleep 1
    echo
    trap maybeexit 2
}

reallyexit() {
    echo
    echo "Okay, really exiting..."
    exit 0
}

echo "Hit ^C to cancel current task."
echo "Hit ^C twice to exit."
while :; do
    x=$((x+1))
    echo "Now churning on long running task no. $x"
    sleep 1000
done
---------------------------------------------------------------------- When run in Bash this script does not exit when ^C is hit twice. The first ^C is caught correctly, but the second merely kills the "sleep" in the "maybeexit" signal handler and continues execution. (Note: Using the "trap -p" command before the sleep, one can see that Bash actually thinks it has updated the signal handler, even though it does not honor it.) In contrast, when this script is run in other POSIX shells (I've tested dash, ksh, mksh, pdksh, and zsh), the script runs correctly. In those shells, hitting ^C twice calls the "reallyexit" signal handler which exits the program. I admit that there is much deep magic surrounding "correct" interrupt handling in different shells, but I'm not inexperienced, and I'd be very surprised if this is by design. If so, then there is a bug in the documentation, as I have pored over it repeatedly and there is no mention of traps being inoperable until the handler has finished.