BASH PATCH REPORT ================= Bash-Release: 4.2 Patch-ID: bash42-003 Bug-Reported-by: Clark J. Wang Bug-Reference-ID: Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2011-02/msg00136.html Bug-Description: When using the pattern replacement and pattern removal word expansions, bash miscalculates the possible match length in the presence of an unescaped left bracket without a closing right bracket, resulting in a failure to match the pattern. Patch (apply with `patch -p0'): *** ../bash-4.2-patched/lib/glob/gmisc.c 2011-02-05 16:11:17.000000000 -0500 --- ./lib/glob/gmisc.c 2011-02-18 23:53:42.000000000 -0500 *************** *** 78,83 **** size_t wmax; { ! wchar_t wc, *wbrack; ! int matlen, t, in_cclass, in_collsym, in_equiv; if (*wpat == 0) --- 78,83 ---- size_t wmax; { ! wchar_t wc; ! int matlen, bracklen, t, in_cclass, in_collsym, in_equiv; if (*wpat == 0) *************** *** 119,123 **** case L'[': /* scan for ending `]', skipping over embedded [:...:] */ ! wbrack = wpat; wc = *wpat++; do --- 119,123 ---- case L'[': /* scan for ending `]', skipping over embedded [:...:] */ ! bracklen = 1; wc = *wpat++; do *************** *** 125,140 **** if (wc == 0) { ! matlen += wpat - wbrack - 1; /* incremented below */ ! break; } else if (wc == L'\\') { ! wc = *wpat++; ! if (*wpat == 0) ! break; } else if (wc == L'[' && *wpat == L':') /* character class */ { wpat++; in_cclass = 1; } --- 125,148 ---- if (wc == 0) { ! wpat--; /* back up to NUL */ ! matlen += bracklen; ! goto bad_bracket; } else if (wc == L'\\') { ! /* *wpat == backslash-escaped character */ ! bracklen++; ! /* If the backslash or backslash-escape ends the string, ! bail. The ++wpat skips over the backslash escape */ ! if (*wpat == 0 || *++wpat == 0) ! { ! matlen += bracklen; ! goto bad_bracket; ! } } else if (wc == L'[' && *wpat == L':') /* character class */ { wpat++; + bracklen++; in_cclass = 1; } *************** *** 142,145 **** --- 150,154 ---- { wpat++; + bracklen++; in_cclass = 0; } *************** *** 147,152 **** { wpat++; if (*wpat == L']') /* right bracket can appear as collating symbol */ ! wpat++; in_collsym = 1; } --- 156,165 ---- { wpat++; + bracklen++; if (*wpat == L']') /* right bracket can appear as collating symbol */ ! { ! wpat++; ! bracklen++; ! } in_collsym = 1; } *************** *** 154,157 **** --- 167,171 ---- { wpat++; + bracklen++; in_collsym = 0; } *************** *** 159,164 **** { wpat++; if (*wpat == L']') /* right bracket can appear as equivalence class */ ! wpat++; in_equiv = 1; } --- 173,182 ---- { wpat++; + bracklen++; if (*wpat == L']') /* right bracket can appear as equivalence class */ ! { ! wpat++; ! bracklen++; ! } in_equiv = 1; } *************** *** 166,174 **** --- 184,196 ---- { wpat++; + bracklen++; in_equiv = 0; } + else + bracklen++; } while ((wc = *wpat++) != L']'); matlen++; /* bracket expression can only match one char */ + bad_bracket: break; } *************** *** 214,219 **** size_t max; { ! char c, *brack; ! int matlen, t, in_cclass, in_collsym, in_equiv; if (*pat == 0) --- 236,241 ---- size_t max; { ! char c; ! int matlen, bracklen, t, in_cclass, in_collsym, in_equiv; if (*pat == 0) *************** *** 255,259 **** case '[': /* scan for ending `]', skipping over embedded [:...:] */ ! brack = pat; c = *pat++; do --- 277,281 ---- case '[': /* scan for ending `]', skipping over embedded [:...:] */ ! bracklen = 1; c = *pat++; do *************** *** 261,276 **** if (c == 0) { ! matlen += pat - brack - 1; /* incremented below */ ! break; } else if (c == '\\') { ! c = *pat++; ! if (*pat == 0) ! break; } else if (c == '[' && *pat == ':') /* character class */ { pat++; in_cclass = 1; } --- 283,306 ---- if (c == 0) { ! pat--; /* back up to NUL */ ! matlen += bracklen; ! goto bad_bracket; } else if (c == '\\') { ! /* *pat == backslash-escaped character */ ! bracklen++; ! /* If the backslash or backslash-escape ends the string, ! bail. The ++pat skips over the backslash escape */ ! if (*pat == 0 || *++pat == 0) ! { ! matlen += bracklen; ! goto bad_bracket; ! } } else if (c == '[' && *pat == ':') /* character class */ { pat++; + bracklen++; in_cclass = 1; } *************** *** 278,281 **** --- 308,312 ---- { pat++; + bracklen++; in_cclass = 0; } *************** *** 283,288 **** { pat++; if (*pat == ']') /* right bracket can appear as collating symbol */ ! pat++; in_collsym = 1; } --- 314,323 ---- { pat++; + bracklen++; if (*pat == ']') /* right bracket can appear as collating symbol */ ! { ! pat++; ! bracklen++; ! } in_collsym = 1; } *************** *** 290,293 **** --- 325,329 ---- { pat++; + bracklen++; in_collsym = 0; } *************** *** 295,300 **** { pat++; if (*pat == ']') /* right bracket can appear as equivalence class */ ! pat++; in_equiv = 1; } --- 331,340 ---- { pat++; + bracklen++; if (*pat == ']') /* right bracket can appear as equivalence class */ ! { ! pat++; ! bracklen++; ! } in_equiv = 1; } *************** *** 302,310 **** --- 342,354 ---- { pat++; + bracklen++; in_equiv = 0; } + else + bracklen++; } while ((c = *pat++) != ']'); matlen++; /* bracket expression can only match one char */ + bad_bracket: break; } *** ../bash-4.2-patched/patchlevel.h Sat Jun 12 20:14:48 2010 --- ./patchlevel.h Thu Feb 24 21:41:34 2011 *************** *** 26,30 **** looks for to find the patch level (for the sccs version string). */ ! #define PATCHLEVEL 2 #endif /* _PATCHLEVEL_H_ */ --- 26,30 ---- looks for to find the patch level (for the sccs version string). */ ! #define PATCHLEVEL 3 #endif /* _PATCHLEVEL_H_ */