Configuration Information [Automatically generated, do not change]: Machine: i586 OS: linux-gnu Compiler: gcc -I/usr/src/packages/BUILD/bash-4.1 -L/usr/src/packages/BUILD/bash-4.1/../readline-6.1 Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='i586' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='i586-suse-linux-gnu' -DCONF_VENDOR='suse' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I. -I./include -I./lib -O2 -march=i586 -mtune=i686 -fmessage-length=0 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector -funwind-tables -fasynchronous-unwind-tables -g -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DRECYCLES_PIDS -Wall -g -std=gnu89 -Wextra -Wno-unprototyped-calls -Wno-switch-enum -Wno-unused-variable -Wno-unused-parameter -ftree-loop-linear -pipe -fprofile-use uname output: Linux boole 2.6.27.19-3.2-pae #1 SMP 2009-02-25 15:40:44 +0100 i686 i686 i386 GNU/Linux Machine Type: i586-suse-linux-gnu
Bash Version: 4.1, 4.0, 3.2, 3.1, 3.0 Patch Level: all Release Status: release Description: Signal handler may hang in futex_wait() on fast multi processor systems. This seems to caused by using stdio within signal handlers in some cases where glibc uses malloc()/free() internal. Repeat-By: This is very hard to reproduce as it requires a fast multi processor system combined with a glibc version which triggers this race condition. See https://bugzilla.novell.com/show_bug.cgi?id=522351 Fix: For the malloc()/free() used by the bash (confgured with --without-gnu-malloc and --without-bash-malloc) I use the patch below but this does not work for the in glibc internal used malloc()/free() calls. A real solution could be the way done in tcsh or ksh where only flags will be set from the signal handlers whereas the real work is done within the main loop its self. --- parse.y +++ parse.y 2010-01-20 13:51:39.000000000 +0000 @@ -1434,10 +1434,11 @@ yy_readline_get () current_readline_prompt : ""); terminate_immediately = 0; - if (signal_is_ignored (SIGINT) == 0 && old_sigint) + if (signal_is_ignored (SIGINT) == 0) { interrupt_immediately--; - set_signal_handler (SIGINT, old_sigint); + if (old_sigint) + set_signal_handler (SIGINT, old_sigint); } #if 0 --- xmalloc.c +++ xmalloc.c 2010-02-24 08:32:51.452626384 +0000 @@ -35,6 +35,11 @@ # include "ansi_stdlib.h" #endif /* HAVE_STDLIB_H */ +/* Determine which kind of system this is. */ +#include <signal.h> +extern int interrupt_immediately; +extern int signal_is_trapped __P((int)); + #include "error.h" #include "bashintl.h" @@ -94,6 +99,34 @@ allocerr (func, bytes) #endif /* !HAVE_SBRK */ } +static void +block_signals (setp, osetp) + sigset_t *setp, *osetp; +{ +#ifdef HAVE_POSIX_SIGNALS + sigfillset (setp); + sigemptyset (osetp); + sigprocmask (SIG_BLOCK, setp, osetp); +#else +# if defined (HAVE_BSD_SIGNALS) + *osetp = sigsetmask (-1); +# endif +#endif +} + +static void +unblock_signals (setp, osetp) + sigset_t *setp, *osetp; +{ +#ifdef HAVE_POSIX_SIGNALS + sigprocmask (SIG_SETMASK, osetp, (sigset_t *)NULL); +#else +# if defined (HAVE_BSD_SIGNALS) + sigsetmask (*osetp); +# endif +#endif +} + /* Return a pointer to free()able block of memory large enough to hold BYTES number of bytes. If the memory cannot be allocated, print an error message and abort. */ @@ -102,15 +135,28 @@ xmalloc (bytes) size_t bytes; { PTR_T temp; + sigset_t set, oset; + int blocked_sigs; #if defined (DEBUG) if (bytes == 0) internal_warning("xmalloc: size argument is 0"); #endif + /* Block all signals in case we are executed from a signal handler. */ + blocked_sigs = 0; + if (interrupt_immediately || signal_is_trapped (SIGINT) || signal_is_trapped (SIGCHLD)) + { + block_signals (&set, &oset); + blocked_sigs = 1; + } + FINDBRK(); temp = malloc (bytes); + if (blocked_sigs) + unblock_signals (&set, &oset); + if (temp == 0) allocerr ("xmalloc", bytes); @@ -123,15 +169,28 @@ xrealloc (pointer, bytes) size_t bytes; { PTR_T temp; + sigset_t set, oset; + int blocked_sigs; #if defined (DEBUG) if (bytes == 0) internal_warning("xrealloc: size argument is 0"); #endif + /* Block all signals in case we are executed from a signal handler. */ + blocked_sigs = 0; + if (interrupt_immediately || signal_is_trapped (SIGINT) || signal_is_trapped (SIGCHLD)) + { + block_signals (&set, &oset); + blocked_sigs = 1; + } + FINDBRK(); temp = pointer ? realloc (pointer, bytes) : malloc (bytes); + if (blocked_sigs) + unblock_signals (&set, &oset); + if (temp == 0) allocerr ("xrealloc", bytes); @@ -145,7 +204,22 @@ xfree (string) PTR_T string; { if (string) - free (string); + { + sigset_t set, oset; + int blocked_sigs = 0; + + /* Block all signals in case we are executed from a signal handler. */ + if (interrupt_immediately || signal_is_trapped (SIGINT) || signal_is_trapped (SIGCHLD)) + { + block_signals (&set, &oset); + blocked_sigs = 1; + } + + free (string); + + if (blocked_sigs) + unblock_signals (&set, &oset); + } } #ifdef USING_BASH_MALLOC