Signal handler may hang in futex_wait on SMP

2010-02-25 Thread werner
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.0 +
@@ -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 +
@@ -35,6 +35,11 @@
 #  include "ansi_stdlib.h"
 #endif /* HAVE_STDLIB_H */
 
+/* Determine which kind of system this is.  */
+#include 
+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, 

Re: Possible Bug in BASH

2010-02-25 Thread Matthew Strax-Haber

On Jun 20, 2009, at 3:47 PM, Bob Proulx wrote:

> Matthew Strax-Haber wrote:
>> I think I may have found a bug in BASH 3.2.17(1)-release on a mac.
> 
> I am not sure it is a bug but it does seem ood.
Perhaps it is not a bug, but if it is not then the documentation is 
inconsistent with the behavior.

> 
>> Below is a simple demonstration of the unexpected behavior:
>> 
>> SHELL 1:
>> mattsh$ alias c=clear
>> mattsh$ c () { echo foo; }
>> mattsh$ clear
>> foo
> 
> Here c is the first word.  So it is replaced by the alias.  (I didn't
> know this behavior before.  This is actually really surprising
> behavior to me since I didn't expect a function definition to be a
> simple command.)
> 
>> SHELL 2:
>> mattsh$ alias c=clear
>> mattsh$ function c () { echo foo; }
>> mattsh$ clear
>> [blanks screen]
> 
> Here function is the first word.
> 
> Useful in this context is 'type -a c' and type -a clear' to view the
> list of possible definitions of c and clear.
> 
>> The documentation for 'function' states:
>> function: function NAME { COMMANDS ; } or NAME () { COMMANDS ; }
>>Create a simple command invoked by NAME which runs COMMANDS.
>>Arguments on the command line along with NAME are passed to the
>>function as $0 .. $n.
>> 
>> According to this, "function NAME { COMMANDS ; }" and "NAME () { COMMANDS 
>> ; }" should be equivalent.
> 
> Yes.  But the documentation for alias says:
> 
>Aliases allow a string to be substituted for a word when it is
>used as the first word of a simple command.
> 
> And the definition of reserved words says:
> 
>Reserved words are words that have a special meaning to the
>shell.  The following words are recognized as reserved when
>unquoted and either the first word of a simple command (see
>SHELL GRAMMAR below) or the third word of a case or for
>command:
> 
>! case do done elif else esac fi for function if in select then
>until while { } time [[ ]]
> 
> Therefore function is a reserved word when it is used as the first
> word of a simple command.  Meaning to me that the name c can't be the
> first word in that case because function is the first word.  Meaning
> that c isn't replaced by the alias in that case.  It is only replaced
> when it is the first word.
I understand what is happening and why, but from my understanding either the 
implementation should be changed or the documentation made more precise.

> Using aliases in this way seems really warped to me.  I would avoid it
> for the clarity of code.  Aliases are really an old paradigm from csh
> days.  Functions in more modern shells completely replace the need for
> aliases.
Agreed.

> Bob
-- 
~ Matthew Strax-Haber
Northeastern University





Re: Possible Bug in BASH

2010-02-25 Thread Andreas Schwab
Matthew Strax-Haber  writes:

> Perhaps it is not a bug, but if it is not then the documentation is 
> inconsistent with the behavior.

There is no inconsistency.  In the first example you define a function
with the name `clear', in the second example you define a function with
the name `c'.  Surely they behave differently.  Alias substitution is a
pure textual substution that changes the text to be parsed.

Andreas.

-- 
Andreas Schwab, sch...@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."




Re: Possible Bug in BASH

2010-02-25 Thread Chet Ramey
On 2/25/10 2:05 AM, Matthew Strax-Haber wrote:

>>> Below is a simple demonstration of the unexpected behavior:
>>>
>>> SHELL 1:
>>> mattsh$ alias c=clear
>>> mattsh$ c () { echo foo; }
>>> mattsh$ clear
>>> foo
>>
>> Here c is the first word.  So it is replaced by the alias.  (I didn't
>> know this behavior before.  This is actually really surprising
>> behavior to me since I didn't expect a function definition to be a
>> simple command.)

When `c' is parsed and delimited as a token, it is in a position to be the
first word of a simple command.  The shell does not look ahead or apply
any grammar rules before performing alias substitution, so `c' is a valid
candidate for replacement.  Since there is an alias defined for `c', the
text is replaced.

This is as Posix specifies and how Posix shells behave.

Chet
-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/