bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Signal handler may hang in futex_wait on SMP


From: werner
Subject: Signal handler may hang in futex_wait on SMP
Date: Thu, 25 Feb 2010 13:38:34 +0100

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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]