On 1/24/13 12:10 PM, konsolebox wrote:
>     This doesn't help a lot.  How about building bash-4.2.42 with -g so
>     debugging symbols are preserved, then seeing where the crash is?
> 
> 
> I compiled 4.2.42 using gcc 4.6.3 (C[XX]FLAGS="-march=native -O2 -g"). It
> took longer before the crash occurred and this is the report I got:
> 
> malloc: ./read.def:696: assertion botched
> free: called with already freed block argument
> Aborting...catch.

OK, I was able to figure it out.  The problem is that the `read -t'
generates SIGALRM, which sometimes arrives and is handled while the SIGCHLD
trap is running (bash-4.2 runs the SIGCHLD trap immediately).  This
violates assumptions bash makes about the state of the unwind-protect
stack, and results in a double free because the free bash thinks it's
avoiding actually happens.

The real fix is coming in the next release of bash, with an extensive
reworking of how signal handlers and traps are run, but the attached
patch should be able to get you through the seg fault.

Chet

-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, ITS, CWRU    c...@case.edu    http://cnswww.cns.cwru.edu/~chet/
*** ../bash-4.2-patched/builtins/read.def	2012-10-31 21:22:51.000517000 -0400
--- builtins/read.def	2013-01-25 10:28:16.000038000 -0500
***************
*** 386,393 ****
  	  /* Tricky.  The top of the unwind-protect stack is the free of
  	     input_string.  We want to run all the rest and use input_string,
! 	     so we have to remove it from the stack. */
! 	  remove_unwind_protect ();
! 	  run_unwind_frame ("read_builtin");
  	  input_string[i] = '\0';	/* make sure it's terminated */
  	  retval = 128+SIGALRM;
  	  goto assign_vars;
--- 386,403 ----
  	  /* Tricky.  The top of the unwind-protect stack is the free of
  	     input_string.  We want to run all the rest and use input_string,
! 	     so we have to save input_string temporarily, run the unwind-
! 	     protects, then restore input_string so we can use it later. */
! 
  	  input_string[i] = '\0';	/* make sure it's terminated */
+ 	  if (i == 0)
+ 	    {
+ 	      t = (char *)xmalloc (1);
+ 	      t[0] = 0;
+ 	    }
+ 	  else
+ 	    t = savestring (input_string);
+ 
+ 	  run_unwind_frame ("read_builtin");
+ 	  input_string = t;
  	  retval = 128+SIGALRM;
  	  goto assign_vars;

Reply via email to