Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-redhat-linux-gnu' -DCONF_VENDOR='redhat' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I. -I./include -I./lib -D_GNU_SOURCE -DRECYCLES_PIDS -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic uname output: Linux localhost 3.1.6-1.fc16.x86_64 #1 SMP Wed Dec 21 22:41:17 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux Machine Type: x86_64-redhat-linux-gnu
Bash Version: 4.2 Patch Level: 20 Release Status: release Description: When a SIGCHLD is received in job control mode and a handler for the signal is installed, bash calls the trap handler within the signal handler itself. This is unsafe because the trap handler function run_sigchld_trap() uses the glibc malloc functions quite extensively (within the function itself and also the function it calls, i.e. parse_and_execute() ). This results in a deadlock and sometimes even a segmentation fault due to memory corruption. Repeat-By: $ cat > foo.sh #!/bin/sh check_stop_child_trap() { echo "child died!" } do_something() { while true; do true & done } trap check_stop_child_trap SIGCHLD do_something & do_something ^d $ bash $ . foo.sh ------------------ The above may either hang or result in a segmentation fault. Fix: The patch below fixes this by deferring execution of the trap handler by adding it to pending_sigs. diff -pruN bash-4.1/jobs.c bash-4.1.patched/jobs.c --- bash-4.1/jobs.c 2009-11-30 03:42:05.000000000 +0530 +++ bash-4.1.patched/jobs.c 2012-03-06 16:44:15.706595703 +0530 @@ -3037,6 +3037,7 @@ waitchld (wpid, block) PROCESS *child; pid_t pid; int call_set_current, last_stopped_job, job, children_exited, waitpid_flags; + int called_from_sighand = sigchld; static int wcontinued = WCONTINUED; /* run-time fix for glibc problem */ call_set_current = children_exited = 0; @@ -3161,7 +3162,17 @@ waitchld (wpid, block) longjmp (wait_intr_buf, 1); } - run_sigchld_trap (children_exited); + /* Queue up the trap handler if we're called directly from within the + signal handler. */ + if (called_from_sighand) + { + int i = children_exited; + interrupt_immediately = 0; + while (i--) + trap_handler (SIGCHLD); + } + else + run_sigchld_trap (children_exited); } /* We have successfully recorded the useful information about this process