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