			     BASH PATCH REPORT
			     =================

Bash-Release:	4.3
Patch-ID:	bash43-033

Bug-Reported-by:	mickael9@gmail.com, Jan Rome <jan.rome@gmail.com>
Bug-Reference-ID:	<20140907224046.382ED3610CC@mickael-laptop.localdomain>,
			<540D661D.50908@gmail.com>
Bug-Reference-URL:	http://lists.gnu.org/archive/html/bug-bash/2014-09/msg00029.html
			http://lists.gnu.org/archive/html/bug-bash/2014-09/msg00030.html

Bug-Description:

Bash does not clean up the terminal state in all cases where bash or
readline  modifies it and bash is subsequently terminated by a fatal signal.
This happens when the `read' builtin modifies the terminal settings, both
when readline is active and when it is not.  It occurs most often when a script
installs a trap that exits on a signal without re-sending the signal to itself.

Patch (apply with `patch -p0'):

*** ../bash-4.3-patched/shell.c	2014-01-14 08:04:32.000000000 -0500
--- shell.c	2014-12-22 10:27:50.000000000 -0500
***************
*** 74,77 ****
--- 74,78 ----
  
  #if defined (READLINE)
+ #  include <readline/readline.h>
  #  include "bashline.h"
  #endif
***************
*** 910,913 ****
--- 912,923 ----
    fflush (stderr);
  
+   /* Clean up the terminal if we are in a state where it's been modified. */
+ #if defined (READLINE)
+   if (RL_ISSTATE (RL_STATE_TERMPREPPED) && rl_deprep_term_function)
+     (*rl_deprep_term_function) ();
+ #endif
+   if (read_tty_modified ())
+     read_tty_cleanup ();
+ 
    /* Do trap[0] if defined.  Allow it to override the exit status
       passed to us. */
*** ../bash-4.3-patched/builtins/read.def	2014-10-01 12:57:38.000000000 -0400
--- builtins/read.def	2014-12-22 10:48:54.000000000 -0500
***************
*** 141,148 ****
  int sigalrm_seen;
  
! static int reading;
  static SigHandler *old_alrm;
  static unsigned char delim;
  
  /* In all cases, SIGALRM just sets a flag that we check periodically.  This
     avoids problems with the semi-tricky stuff we do with the xfree of
--- 141,150 ----
  int sigalrm_seen;
  
! static int reading, tty_modified;
  static SigHandler *old_alrm;
  static unsigned char delim;
  
+ static struct ttsave termsave;
+ 
  /* In all cases, SIGALRM just sets a flag that we check periodically.  This
     avoids problems with the semi-tricky stuff we do with the xfree of
***************
*** 189,193 ****
    SHELL_VAR *var;
    TTYSTRUCT ttattrs, ttset;
-   struct ttsave termsave;
  #if defined (ARRAY_VARS)
    WORD_LIST *alist;
--- 191,194 ----
***************
*** 222,226 ****
    USE_VAR(lastsig);
  
!   sigalrm_seen = reading = 0;
  
    i = 0;		/* Index into the string that we are reading. */
--- 223,227 ----
    USE_VAR(lastsig);
  
!   sigalrm_seen = reading = tty_modified = 0;
  
    i = 0;		/* Index into the string that we are reading. */
***************
*** 439,442 ****
--- 440,445 ----
  	  goto assign_vars;
  	}
+       if (interactive_shell == 0)
+ 	initialize_terminating_signals ();
        old_alrm = set_signal_handler (SIGALRM, sigalrm);
        add_unwind_protect (reset_alarm, (char *)NULL);
***************
*** 483,487 ****
--- 486,493 ----
  	  if (i < 0)
  	    sh_ttyerror (1);
+ 	  tty_modified = 1;
  	  add_unwind_protect ((Function *)ttyrestore, (char *)&termsave);
+ 	  if (interactive_shell == 0)
+ 	    initialize_terminating_signals ();
  	}
      }
***************
*** 498,502 ****
--- 504,511 ----
  	sh_ttyerror (1);
  
+       tty_modified = 1;
        add_unwind_protect ((Function *)ttyrestore, (char *)&termsave);
+       if (interactive_shell == 0)
+ 	initialize_terminating_signals ();
      }
  
***************
*** 589,592 ****
--- 598,603 ----
  	  else
  	    lastsig = 0;
+ 	  if (terminating_signal && tty_modified)
+ 	    ttyrestore (&termsave);	/* fix terminal before exiting */
  	  CHECK_TERMSIG;
  	  eof = 1;
***************
*** 979,982 ****
--- 990,1007 ----
  {
    ttsetattr (ttp->fd, ttp->attrs);
+   tty_modified = 0;
+ }
+ 
+ void
+ read_tty_cleanup ()
+ {
+   if (tty_modified)
+     ttyrestore (&termsave);
+ }
+ 
+ int
+ read_tty_modified ()
+ {
+   return (tty_modified);
  }
  
*** ../bash-4.3-patched/builtins/common.h	2014-10-01 12:57:47.000000000 -0400
--- builtins/common.h	2014-12-22 10:10:14.000000000 -0500
***************
*** 123,126 ****
--- 141,148 ----
  extern void getopts_reset __P((int));
  
+ /* Functions from read.def */
+ extern void read_tty_cleanup __P((void));
+ extern int read_tty_modified __P((void));
+ 
  /* Functions from set.def */
  extern int minus_o_option_value __P((char *));
*** ../bash-4.3-patched/bashline.c	2014-05-14 09:22:39.000000000 -0400
--- bashline.c	2014-09-08 11:28:56.000000000 -0400
***************
*** 203,206 ****
--- 203,207 ----
  extern int array_needs_making;
  extern int posixly_correct, no_symbolic_links;
+ extern int sigalrm_seen;
  extern char *current_prompt_string, *ps1_prompt;
  extern STRING_INT_ALIST word_token_alist[];
***************
*** 4209,4214 ****
    /* If we're going to longjmp to top_level, make sure we clean up readline.
       check_signals will call QUIT, which will eventually longjmp to top_level,
!      calling run_interrupt_trap along the way. */
!   if (interrupt_state)
      rl_cleanup_after_signal ();
    bashline_reset_event_hook ();
--- 4262,4268 ----
    /* If we're going to longjmp to top_level, make sure we clean up readline.
       check_signals will call QUIT, which will eventually longjmp to top_level,
!      calling run_interrupt_trap along the way.  The check for sigalrm_seen is
!      to clean up the read builtin's state. */
!   if (terminating_signal || interrupt_state || sigalrm_seen)
      rl_cleanup_after_signal ();
    bashline_reset_event_hook ();
*** ../bash-4.3-patched/sig.c	2014-01-10 15:06:06.000000000 -0500
--- sig.c	2014-09-08 11:26:33.000000000 -0400
***************
*** 533,538 ****
    /* Set the event hook so readline will call it after the signal handlers
       finish executing, so if this interrupted character input we can get
!      quick response. */
!   if (interactive_shell && interactive && no_line_editing == 0)
      bashline_set_event_hook ();
  #endif
--- 533,540 ----
    /* Set the event hook so readline will call it after the signal handlers
       finish executing, so if this interrupted character input we can get
!      quick response.  If readline is active or has modified the terminal we
!      need to set this no matter what the signal is, though the check for
!      RL_STATE_TERMPREPPED is possibly redundant. */
!   if (RL_ISSTATE (RL_STATE_SIGHANDLER) || RL_ISSTATE (RL_STATE_TERMPREPPED))
      bashline_set_event_hook ();
  #endif
*** ../bash-4.3/patchlevel.h	2012-12-29 10:47:57.000000000 -0500
--- patchlevel.h	2014-03-20 20:01:28.000000000 -0400
***************
*** 26,30 ****
     looks for to find the patch level (for the sccs version string). */
  
! #define PATCHLEVEL 32
  
  #endif /* _PATCHLEVEL_H_ */
--- 26,30 ----
     looks for to find the patch level (for the sccs version string). */
  
! #define PATCHLEVEL 33
  
  #endif /* _PATCHLEVEL_H_ */
