[gnu.bash.bug] Extremely obnoxious bash bug

ray@GIBBS.PHYSICS.PURDUE.EDU (Ray Moody) (07/26/89)

    Bash can hang your terminal...

    If a SIGINT occurs inside fork we will eventually call readline
(not right away as the signal is temporarly blocked).  We might be in
readline when the child changes the terminals process group.

    The child dies with the SIGINT signal.  Flush_child is called.
Flush_child calls kill to process the signal.  Rl_signal_handler is
called.  Rl_deprep_terminal is called.  Ioctl(TIOCSETN) is called.
Since the terminal no longer belongs to bash, a TTOU signal is posted
by the kernel. Rl_signal_handler gets called again.
Rl_deprep_terminal gets called again.  Ioctl(TIOCSETN) gets called
again.  A TTOU signal is posted again, but it is blocked.  Ioctl will
then wait for the terminal to be given back to bash, but this is never
going to happen.  You will have to log onto a different terminal and
kill off bash.

    Whew!

    You can reproduce this bug best when fork takes much time.  This
happens when bash is big and swapped out (use hostname completion on a
big /etc/hosts, and then let bash sit idle for a while and run some
huge programs).  You might also try overloading your swap disks.

								Ray
-------------------------------------------------------------------------------
RCS file: RCS/jobs.c,v
retrieving revision 1.2.1.1
diff -c -r1.2.1.1 jobs.c
*** /tmp/,RCSt1027287	Wed Jul 26 02:57:26 1989
--- jobs.c	Wed Jul 26 02:54:00 1989
***************
*** 612,617
  	  if (!pipeline_pgrp)	/* Then this is the first child. */
  	    pipeline_pgrp = getpid ();
      
  	  /* You must give the tty away before you set the process group,
  	     and you must do these things only in the child.  Otherwise,
  	     race conditions can occur. */

--- 612,624 -----
  	  if (!pipeline_pgrp)	/* Then this is the first child. */
  	    pipeline_pgrp = getpid ();
      
+ 	  /* Fixed by Ray Wed Jul 26 02:36:21 EST 1989
+ 	     We restore our sigmask before we change the terminal process
+ 	     group because we don't want to change it if we got a SIGINT
+ 	     while we were in fork. (If we change it, readline will be
+ 	     suprised, perhaps even after it has started reading!) */
+ 	  sigsetmask (oldmask);
+ 
  	  /* You must give the tty away before you set the process group,
  	     and you must do these things only in the child.  Otherwise,
  	     race conditions can occur. */
***************
*** 671,676
  	last_asynchronous_pid = pid;
  
        last_made_pid = pid;
      }
  
    sigsetmask (oldmask);

--- 678,685 -----
  	last_asynchronous_pid = pid;
  
        last_made_pid = pid;
+ 
+       sigsetmask (oldmask);
      }
  
    return (pid);
***************
*** 673,679
        last_made_pid = pid;
      }
  
-   sigsetmask (oldmask);
    return (pid);
  }
  

--- 682,687 -----
        sigsetmask (oldmask);
      }
  
    return (pid);
  }