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