b130412
			     BASH PATCH REPORT
b130412
			     =================
b130412
b130412
Bash-Release: 3.2
b130412
Patch-ID: bash32-014
b130412
b130412
Bug-Reported-by: Brett Stahlman <brettstahlman@comcast.net>
b130412
Bug-Reference-ID: <000701c72d29$a227e0e0$5ec7cf47@computerroom>
b130412
Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2006-12/msg00065.html
b130412
b130412
Bug-Description:
b130412
b130412
Bash mishandles word splitting under certain circumstances when IFS is
b130412
null (IFS=).  Constructs affected include ${param/pat/sub} and others
b130412
when expanding arrays (array[@]).
b130412
b130412
Patch:
b130412
b130412
*** ../bash-3.2-patched/array.c	Wed Jun  1 16:39:22 2005
b130412
--- array.c	Mon Jan 15 22:58:00 2007
b130412
***************
b130412
*** 121,125 ****
b130412
  }
b130412
  
b130412
- #ifdef INCLUDE_UNUSED
b130412
  /*
b130412
   * Make and return a new array composed of the elements in array A from
b130412
--- 121,124 ----
b130412
***************
b130412
*** 142,146 ****
b130412
  		n = array_create_element (element_index(p), element_value(p));
b130412
  		ADD_BEFORE(a->head, n);
b130412
! 		mi = element_index(ae);
b130412
  	}
b130412
  	a->num_elements = i;
b130412
--- 141,145 ----
b130412
  		n = array_create_element (element_index(p), element_value(p));
b130412
  		ADD_BEFORE(a->head, n);
b130412
! 		mi = element_index(n);
b130412
  	}
b130412
  	a->num_elements = i;
b130412
***************
b130412
*** 148,152 ****
b130412
  	return a;
b130412
  }
b130412
- #endif
b130412
  
b130412
  /*
b130412
--- 147,150 ----
b130412
***************
b130412
*** 301,304 ****
b130412
--- 299,319 ----
b130412
  }
b130412
  
b130412
+ ARRAY	*
b130412
+ array_quote_escapes(array)
b130412
+ ARRAY	*array;
b130412
+ {
b130412
+ 	ARRAY_ELEMENT	*a;
b130412
+ 	char	*t;
b130412
+ 
b130412
+ 	if (array == 0 || array_head(array) == 0 || array_empty(array))
b130412
+ 		return (ARRAY *)NULL;
b130412
+ 	for (a = element_forw(array->head); a != array->head; a = element_forw(a)) {
b130412
+ 		t = quote_escapes (a->value);
b130412
+ 		FREE(a->value);
b130412
+ 		a->value = t;
b130412
+ 	}
b130412
+ 	return array;
b130412
+ }
b130412
+ 
b130412
  /*
b130412
   * Return a string whose elements are the members of array A beginning at
b130412
***************
b130412
*** 312,318 ****
b130412
  int	starsub, quoted;
b130412
  {
b130412
  	ARRAY_ELEMENT	*h, *p;
b130412
  	arrayind_t	i;
b130412
! 	char		*ifs, sep[2];
b130412
  
b130412
  	p = a ? array_head (a) : 0;
b130412
--- 327,334 ----
b130412
  int	starsub, quoted;
b130412
  {
b130412
+ 	ARRAY		*a2;
b130412
  	ARRAY_ELEMENT	*h, *p;
b130412
  	arrayind_t	i;
b130412
! 	char		*ifs, sep[2], *t;
b130412
  
b130412
  	p = a ? array_head (a) : 0;
b130412
***************
b130412
*** 337,340 ****
b130412
--- 353,363 ----
b130412
  		;
b130412
  
b130412
+ 	a2 = array_slice(a, h, p);
b130412
+ 
b130412
+ 	if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
b130412
+ 		array_quote(a2);
b130412
+ 	else
b130412
+ 		array_quote_escapes(a2);
b130412
+ 
b130412
  	if (starsub && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) {
b130412
  		ifs = getifs();
b130412
***************
b130412
*** 344,348 ****
b130412
  	sep[1] = '\0';
b130412
  
b130412
! 	return (array_to_string_internal (h, p, sep, quoted));
b130412
  }
b130412
  
b130412
--- 367,374 ----
b130412
  	sep[1] = '\0';
b130412
  
b130412
! 	t = array_to_string (a2, sep, 0);
b130412
! 	array_dispose(a2);
b130412
! 
b130412
! 	return t;
b130412
  }
b130412
  
b130412
***************
b130412
*** 368,372 ****
b130412
  
b130412
  	if (mflags & MATCH_QUOTED)
b130412
! 		array_quote (a2);
b130412
  	if (mflags & MATCH_STARSUB) {
b130412
  		ifs = getifs();
b130412
--- 394,400 ----
b130412
  
b130412
  	if (mflags & MATCH_QUOTED)
b130412
! 		array_quote(a2);
b130412
! 	else
b130412
! 		array_quote_escapes(a2);
b130412
  	if (mflags & MATCH_STARSUB) {
b130412
  		ifs = getifs();
b130412
*** ../bash-3.2-patched/array.h	Sun Jun  1 15:50:30 2003
b130412
--- array.h	Mon Jan 15 22:35:35 2007
b130412
***************
b130412
*** 56,59 ****
b130412
--- 56,60 ----
b130412
  extern int	array_shift_element __P((ARRAY *, char *));
b130412
  extern ARRAY	*array_quote __P((ARRAY *));
b130412
+ extern ARRAY	*array_quote_escapes __P((ARRAY *));
b130412
  
b130412
  extern char	*array_subrange __P((ARRAY *, arrayind_t, arrayind_t, int, int));
b130412
*** ../bash-3.2-patched/subst.c	Fri Mar  2 16:20:50 2007
b130412
--- subst.c	Tue Mar  6 11:40:55 2007
b130412
***************
b130412
*** 1888,1892 ****
b130412
--- 1889,1899 ----
b130412
  #endif
b130412
  
b130412
+   /* XXX -- why call quote_list if ifs == 0?  we can get away without doing
b130412
+      it now that quote_escapes quotes spaces */
b130412
+ #if 0
b130412
    tlist = ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || (ifs && *ifs == 0))
b130412
+ #else
b130412
+   tlist = (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES))
b130412
+ #endif
b130412
  		? quote_list (list)
b130412
  		: list_quote_escapes (list);
b130412
***************
b130412
*** 2922,2926 ****
b130412
  /* Quote escape characters in string s, but no other characters.  This is
b130412
     used to protect CTLESC and CTLNUL in variable values from the rest of
b130412
!    the word expansion process after the variable is expanded. */
b130412
  char *
b130412
  quote_escapes (string)
b130412
--- 2935,2944 ----
b130412
  /* Quote escape characters in string s, but no other characters.  This is
b130412
     used to protect CTLESC and CTLNUL in variable values from the rest of
b130412
!    the word expansion process after the variable is expanded.  If IFS is
b130412
!    null, we quote spaces as well, just in case we split on spaces later
b130412
!    (in the case of unquoted $@, we will eventually attempt to split the
b130412
!    entire word on spaces).  Corresponding code exists in dequote_escapes.
b130412
!    Even if we don't end up splitting on spaces, quoting spaces is not a
b130412
!    problem. */
b130412
  char *
b130412
  quote_escapes (string)
b130412
***************
b130412
*** 2930,2933 ****
b130412
--- 2948,2952 ----
b130412
    size_t slen;
b130412
    char *result, *send;
b130412
+   int quote_spaces;
b130412
    DECLARE_MBSTATE; 
b130412
  
b130412
***************
b130412
*** 2935,2938 ****
b130412
--- 2954,2958 ----
b130412
    send = string + slen;
b130412
  
b130412
+   quote_spaces = (ifs_value && *ifs_value == 0);
b130412
    t = result = (char *)xmalloc ((slen * 2) + 1);
b130412
    s = string;
b130412
***************
b130412
*** 2940,2944 ****
b130412
    while (*s)
b130412
      {
b130412
!       if (*s == CTLESC || *s == CTLNUL)
b130412
  	*t++ = CTLESC;
b130412
        COPY_CHAR_P (t, s, send);
b130412
--- 2960,2964 ----
b130412
    while (*s)
b130412
      {
b130412
!       if (*s == CTLESC || *s == CTLNUL || (quote_spaces && *s == ' '))
b130412
  	*t++ = CTLESC;
b130412
        COPY_CHAR_P (t, s, send);
b130412
***************
b130412
*** 2982,2985 ****
b130412
--- 3002,3006 ----
b130412
    size_t slen;
b130412
    char *result, *send;
b130412
+   int quote_spaces;
b130412
    DECLARE_MBSTATE;
b130412
  
b130412
***************
b130412
*** 2996,3002 ****
b130412
      return (strcpy (result, s));
b130412
  
b130412
    while (*s)
b130412
      {
b130412
!       if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL))
b130412
  	{
b130412
  	  s++;
b130412
--- 3017,3024 ----
b130412
      return (strcpy (result, s));
b130412
  
b130412
+   quote_spaces = (ifs_value && *ifs_value == 0);
b130412
    while (*s)
b130412
      {
b130412
!       if (*s == CTLESC && (s[1] == CTLESC || s[1] == CTLNUL || (quote_spaces && s[1] == ' ')))
b130412
  	{
b130412
  	  s++;
b130412
***************
b130412
*** 4462,4466 ****
b130412
        RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE);
b130412
  
b130412
!       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) || c == CTLESC || c == CTLNUL)
b130412
  	istring[istring_index++] = CTLESC;
b130412
  
b130412
--- 4498,4510 ----
b130412
        RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE);
b130412
  
b130412
!       /* This is essentially quote_string inline */
b130412
!       if ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) /* || c == CTLESC || c == CTLNUL */)
b130412
! 	istring[istring_index++] = CTLESC;
b130412
!       /* Escape CTLESC and CTLNUL in the output to protect those characters
b130412
! 	 from the rest of the word expansions (word splitting and globbing.)
b130412
! 	 This is essentially quote_escapes inline. */
b130412
!       else if (c == CTLESC)
b130412
! 	istring[istring_index++] = CTLESC;
b130412
!       else if (c == CTLNUL || (c == ' ' && (ifs_value && *ifs_value == 0)))
b130412
  	istring[istring_index++] = CTLESC;
b130412
  
b130412
***************
b130412
*** 5552,5555 ****
b130412
--- 5610,5616 ----
b130412
  	 rely on array_subrange to understand how to deal with them). */
b130412
        tt = array_subrange (array_cell (v), e1, e2, starsub, quoted);
b130412
+ #if 0
b130412
+       /* array_subrange now calls array_quote_escapes as appropriate, so the
b130412
+ 	 caller no longer needs to. */
b130412
        if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
b130412
  	{
b130412
***************
b130412
*** 5558,5561 ****
b130412
--- 5619,5623 ----
b130412
  	}
b130412
        else
b130412
+ #endif
b130412
  	temp = tt;
b130412
        break;
b130412
***************
b130412
*** 5808,5811 ****
b130412
--- 5870,5876 ----
b130412
      case VT_ARRAYVAR:
b130412
        temp = array_patsub (array_cell (v), p, rep, mflags);
b130412
+ #if 0
b130412
+       /* Don't need to do this anymore; array_patsub calls array_quote_escapes
b130412
+ 	 as appropriate before adding the space separators. */
b130412
        if (temp && (mflags & MATCH_QUOTED) == 0)
b130412
  	{
b130412
***************
b130412
*** 5814,5817 ****
b130412
--- 5879,5883 ----
b130412
  	  temp = tt;
b130412
  	}
b130412
+ #endif
b130412
        break;
b130412
  #endif
b130412
*** ../bash-3.2/patchlevel.h	Thu Apr 13 08:31:04 2006
b130412
--- patchlevel.h	Mon Oct 16 14:22:54 2006
b130412
***************
b130412
*** 26,30 ****
b130412
     looks for to find the patch level (for the sccs version string). */
b130412
  
b130412
! #define PATCHLEVEL 13
b130412
  
b130412
  #endif /* _PATCHLEVEL_H_ */
b130412
--- 26,30 ----
b130412
     looks for to find the patch level (for the sccs version string). */
b130412
  
b130412
! #define PATCHLEVEL 14
b130412
  
b130412
  #endif /* _PATCHLEVEL_H_ */