Roman Rakus 245501
			     BASH PATCH REPORT
Roman Rakus 245501
			     =================
Roman Rakus 245501
Roman Rakus 245501
Bash-Release: 4.0
Roman Rakus 245501
Patch-ID: bash40-007
Roman Rakus 245501
Roman Rakus 245501
Bug-Reported-by:	AnMaster <anmaster@tele2.se>
Roman Rakus 245501
Bug-Reference-ID:	<49A41C18.80807@tele2.se>
Roman Rakus 245501
Bug-Reference-URL:	http://lists.gnu.org/archive/html/bug-bash/2009-02/msg00188.html
Roman Rakus 245501
Roman Rakus 245501
Bug-Description:
Roman Rakus 245501
Roman Rakus 245501
Bash had a number of problems parsing associative array subscripts containing
Roman Rakus 245501
special characters.  The subscripts are supposed to be read as if they are
Roman Rakus 245501
enclosed between double quotes.
Roman Rakus 245501
Roman Rakus 245501
Patch:
Roman Rakus 245501
Roman Rakus 245501
*** ../bash-4.0/parse.y	2009-01-08 08:29:12.000000000 -0500
Roman Rakus 245501
--- parse.y	2009-02-25 17:25:56.000000000 -0500
Roman Rakus 245501
***************
Roman Rakus 245501
*** 2919,2922 ****
Roman Rakus 245501
--- 2919,2923 ----
Roman Rakus 245501
  #define P_COMMAND	0x08	/* parsing a command, so look for comments */
Roman Rakus 245501
  #define P_BACKQUOTE	0x10	/* parsing a backquoted command substitution */
Roman Rakus 245501
+ #define P_ARRAYSUB	0x20	/* parsing a [...] array subscript for assignment */
Roman Rakus 245501
  
Roman Rakus 245501
  /* Lexical state while parsing a grouping construct or $(...). */
Roman Rakus 245501
***************
Roman Rakus 245501
*** 3134,3137 ****
Roman Rakus 245501
--- 3134,3139 ----
Roman Rakus 245501
  	      FREE (nestret);
Roman Rakus 245501
  	    }
Roman Rakus 245501
+ 	  else if ((flags & P_ARRAYSUB) && (tflags & LEX_WASDOL) && (ch == '(' || ch == '{' || ch == '['))	/* ) } ] */
Roman Rakus 245501
+ 	    goto parse_dollar_word;
Roman Rakus 245501
  	}
Roman Rakus 245501
        /* Parse an old-style command substitution within double quotes as a
Roman Rakus 245501
***************
Roman Rakus 245501
*** 3150,3153 ****
Roman Rakus 245501
--- 3150,3154 ----
Roman Rakus 245501
  	/* check for $(), $[], or ${} inside quoted string. */
Roman Rakus 245501
  	{
Roman Rakus 245501
+ parse_dollar_word:
Roman Rakus 245501
  	  if (open == ch)	/* undo previous increment */
Roman Rakus 245501
  	    count--;
Roman Rakus 245501
***************
Roman Rakus 245501
*** 4277,4281 ****
Roman Rakus 245501
  		      (token_index == 0 && (parser_state&PST_COMPASSIGN))))
Roman Rakus 245501
          {
Roman Rakus 245501
! 	  ttok = parse_matched_pair (cd, '[', ']', &ttoklen, 0);
Roman Rakus 245501
  	  if (ttok == &matched_pair_error)
Roman Rakus 245501
  	    return -1;		/* Bail immediately. */
Roman Rakus 245501
--- 4277,4281 ----
Roman Rakus 245501
  		      (token_index == 0 && (parser_state&PST_COMPASSIGN))))
Roman Rakus 245501
          {
Roman Rakus 245501
! 	  ttok = parse_matched_pair (cd, '[', ']', &ttoklen, P_ARRAYSUB);
Roman Rakus 245501
  	  if (ttok == &matched_pair_error)
Roman Rakus 245501
  	    return -1;		/* Bail immediately. */
Roman Rakus 245501
*** ../bash-4.0/arrayfunc.c	2009-01-04 14:32:21.000000000 -0500
Roman Rakus 245501
--- arrayfunc.c	2009-02-25 07:58:54.000000000 -0500
Roman Rakus 245501
***************
Roman Rakus 245501
*** 605,666 ****
Roman Rakus 245501
  }
Roman Rakus 245501
  
Roman Rakus 245501
! /* This function assumes s[i] == '['; returns with s[ret] == ']' if
Roman Rakus 245501
!    an array subscript is correctly parsed. */
Roman Rakus 245501
! int
Roman Rakus 245501
! skipsubscript (s, i)
Roman Rakus 245501
!      const char *s;
Roman Rakus 245501
!      int i;
Roman Rakus 245501
! {
Roman Rakus 245501
!   int count, c;
Roman Rakus 245501
! #if defined (HANDLE_MULTIBYTE)
Roman Rakus 245501
!   mbstate_t state, state_bak;
Roman Rakus 245501
!   size_t slength, mblength;
Roman Rakus 245501
! #endif
Roman Rakus 245501
! 
Roman Rakus 245501
! #if defined (HANDLE_MULTIBYTE)
Roman Rakus 245501
!   memset (&state, '\0', sizeof (mbstate_t));
Roman Rakus 245501
!   slength = strlen (s + i);
Roman Rakus 245501
! #endif
Roman Rakus 245501
!   
Roman Rakus 245501
!   count = 1;
Roman Rakus 245501
!   while (count)
Roman Rakus 245501
!     {
Roman Rakus 245501
!       /* Advance one (possibly multibyte) character in S starting at I. */
Roman Rakus 245501
! #if defined (HANDLE_MULTIBYTE)
Roman Rakus 245501
!       if (MB_CUR_MAX > 1)
Roman Rakus 245501
! 	{
Roman Rakus 245501
! 	  state_bak = state;
Roman Rakus 245501
! 	  mblength = mbrlen (s + i, slength, &state);
Roman Rakus 245501
! 
Roman Rakus 245501
! 	  if (MB_INVALIDCH (mblength))
Roman Rakus 245501
! 	    {
Roman Rakus 245501
! 	      state = state_bak;
Roman Rakus 245501
! 	      i++;
Roman Rakus 245501
! 	      slength--;
Roman Rakus 245501
! 	    }
Roman Rakus 245501
! 	  else if (MB_NULLWCH (mblength))
Roman Rakus 245501
! 	    return i;
Roman Rakus 245501
! 	  else
Roman Rakus 245501
! 	    {
Roman Rakus 245501
! 	      i += mblength;
Roman Rakus 245501
! 	      slength -= mblength;
Roman Rakus 245501
! 	    }
Roman Rakus 245501
! 	}
Roman Rakus 245501
!       else
Roman Rakus 245501
! #endif
Roman Rakus 245501
!       ++i;
Roman Rakus 245501
! 
Roman Rakus 245501
!       c = s[i];
Roman Rakus 245501
! 
Roman Rakus 245501
!       if (c == 0)
Roman Rakus 245501
! 	break;
Roman Rakus 245501
!       else if (c == '[')
Roman Rakus 245501
! 	count++;
Roman Rakus 245501
!       else if (c == ']')
Roman Rakus 245501
! 	count--;
Roman Rakus 245501
!     }
Roman Rakus 245501
! 
Roman Rakus 245501
!   return i;
Roman Rakus 245501
! }
Roman Rakus 245501
  
Roman Rakus 245501
  /* This function is called with SUB pointing to just after the beginning
Roman Rakus 245501
--- 605,609 ----
Roman Rakus 245501
  }
Roman Rakus 245501
  
Roman Rakus 245501
! /* skipsubscript moved to subst.c to use private functions. 2009/02/24. */
Roman Rakus 245501
  
Roman Rakus 245501
  /* This function is called with SUB pointing to just after the beginning
Roman Rakus 245501
*** ../bash-4.0/subst.c	2009-01-28 14:34:12.000000000 -0500
Roman Rakus 245501
--- subst.c	2009-02-25 09:18:33.000000000 -0500
Roman Rakus 245501
***************
Roman Rakus 245501
*** 223,226 ****
Roman Rakus 245501
--- 223,227 ----
Roman Rakus 245501
  static char *extract_delimited_string __P((char *, int *, char *, char *, char *, int));
Roman Rakus 245501
  static char *extract_dollar_brace_string __P((char *, int *, int, int));
Roman Rakus 245501
+ static int skip_matched_pair __P((const char *, int, int, int, int));
Roman Rakus 245501
  
Roman Rakus 245501
  static char *pos_params __P((char *, int, int, int));
Roman Rakus 245501
***************
Roman Rakus 245501
*** 1375,1378 ****
Roman Rakus 245501
--- 1376,1480 ----
Roman Rakus 245501
  #define CQ_RETURN(x) do { no_longjmp_on_fatal_error = 0; return (x); } while (0)
Roman Rakus 245501
  
Roman Rakus 245501
+ /* This function assumes s[i] == open; returns with s[ret] == close; used to
Roman Rakus 245501
+    parse array subscripts.  FLAGS currently unused. */
Roman Rakus 245501
+ static int
Roman Rakus 245501
+ skip_matched_pair (string, start, open, close, flags)
Roman Rakus 245501
+      const char *string;
Roman Rakus 245501
+      int start, open, close, flags;
Roman Rakus 245501
+ {
Roman Rakus 245501
+   int i, pass_next, backq, si, c, count;
Roman Rakus 245501
+   size_t slen;
Roman Rakus 245501
+   char *temp, *ss;
Roman Rakus 245501
+   DECLARE_MBSTATE;
Roman Rakus 245501
+ 
Roman Rakus 245501
+   slen = strlen (string + start) + start;
Roman Rakus 245501
+   no_longjmp_on_fatal_error = 1;
Roman Rakus 245501
+ 
Roman Rakus 245501
+   i = start + 1;		/* skip over leading bracket */
Roman Rakus 245501
+   count = 1;
Roman Rakus 245501
+   pass_next = backq = 0;
Roman Rakus 245501
+   ss = (char *)string;
Roman Rakus 245501
+   while (c = string[i])
Roman Rakus 245501
+     {
Roman Rakus 245501
+       if (pass_next)
Roman Rakus 245501
+ 	{
Roman Rakus 245501
+ 	  pass_next = 0;
Roman Rakus 245501
+ 	  if (c == 0)
Roman Rakus 245501
+ 	    CQ_RETURN(i);
Roman Rakus 245501
+ 	  ADVANCE_CHAR (string, slen, i);
Roman Rakus 245501
+ 	  continue;
Roman Rakus 245501
+ 	}
Roman Rakus 245501
+       else if (c == '\\')
Roman Rakus 245501
+ 	{
Roman Rakus 245501
+ 	  pass_next = 1;
Roman Rakus 245501
+ 	  i++;
Roman Rakus 245501
+ 	  continue;
Roman Rakus 245501
+ 	}
Roman Rakus 245501
+       else if (backq)
Roman Rakus 245501
+ 	{
Roman Rakus 245501
+ 	  if (c == '`')
Roman Rakus 245501
+ 	    backq = 0;
Roman Rakus 245501
+ 	  ADVANCE_CHAR (string, slen, i);
Roman Rakus 245501
+ 	  continue;
Roman Rakus 245501
+ 	}
Roman Rakus 245501
+       else if (c == '`')
Roman Rakus 245501
+ 	{
Roman Rakus 245501
+ 	  backq = 1;
Roman Rakus 245501
+ 	  i++;
Roman Rakus 245501
+ 	  continue;
Roman Rakus 245501
+ 	}
Roman Rakus 245501
+       else if (c == open)
Roman Rakus 245501
+ 	{
Roman Rakus 245501
+ 	  count++;
Roman Rakus 245501
+ 	  i++;
Roman Rakus 245501
+ 	  continue;
Roman Rakus 245501
+ 	}
Roman Rakus 245501
+       else if (c == close)
Roman Rakus 245501
+ 	{
Roman Rakus 245501
+ 	  count--;
Roman Rakus 245501
+ 	  if (count == 0)
Roman Rakus 245501
+ 	    break;
Roman Rakus 245501
+ 	  i++;
Roman Rakus 245501
+ 	  continue;
Roman Rakus 245501
+ 	}
Roman Rakus 245501
+       else if (c == '\'' || c == '"')
Roman Rakus 245501
+ 	{
Roman Rakus 245501
+ 	  i = (c == '\'') ? skip_single_quoted (ss, slen, ++i)
Roman Rakus 245501
+ 			  : skip_double_quoted (ss, slen, ++i);
Roman Rakus 245501
+ 	  /* no increment, the skip functions increment past the closing quote. */
Roman Rakus 245501
+ 	}
Roman Rakus 245501
+       else if (c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
Roman Rakus 245501
+ 	{
Roman Rakus 245501
+ 	  si = i + 2;
Roman Rakus 245501
+ 	  if (string[si] == '\0')
Roman Rakus 245501
+ 	    CQ_RETURN(si);
Roman Rakus 245501
+ 
Roman Rakus 245501
+ 	  if (string[i+1] == LPAREN)
Roman Rakus 245501
+ 	    temp = extract_delimited_string (ss, &si, "$(", "(", ")", SX_NOALLOC|SX_COMMAND); /* ) */
Roman Rakus 245501
+ 	  else
Roman Rakus 245501
+ 	    temp = extract_dollar_brace_string (ss, &si, 0, SX_NOALLOC);
Roman Rakus 245501
+ 	  i = si;
Roman Rakus 245501
+ 	  if (string[i] == '\0')	/* don't increment i past EOS in loop */
Roman Rakus 245501
+ 	    break;
Roman Rakus 245501
+ 	  i++;
Roman Rakus 245501
+ 	  continue;
Roman Rakus 245501
+ 	}
Roman Rakus 245501
+       else
Roman Rakus 245501
+ 	ADVANCE_CHAR (string, slen, i);
Roman Rakus 245501
+     }
Roman Rakus 245501
+ 
Roman Rakus 245501
+   CQ_RETURN(i);
Roman Rakus 245501
+ }
Roman Rakus 245501
+ 
Roman Rakus 245501
+ #if defined (ARRAY_VARS)
Roman Rakus 245501
+ int
Roman Rakus 245501
+ skipsubscript (string, start)
Roman Rakus 245501
+      const char *string;
Roman Rakus 245501
+      int start;
Roman Rakus 245501
+ {
Roman Rakus 245501
+   return (skip_matched_pair (string, start, '[', ']', 0));
Roman Rakus 245501
+ }
Roman Rakus 245501
+ #endif
Roman Rakus 245501
+ 
Roman Rakus 245501
  /* Skip characters in STRING until we find a character in DELIMS, and return
Roman Rakus 245501
     the index of that character.  START is the index into string at which we
Roman Rakus 245501
*** ../bash-4.0/patchlevel.h	2009-01-04 14:32:40.000000000 -0500
Roman Rakus 245501
--- patchlevel.h	2009-02-22 16:11:31.000000000 -0500
Roman Rakus 245501
***************
Roman Rakus 245501
*** 26,30 ****
Roman Rakus 245501
     looks for to find the patch level (for the sccs version string). */
Roman Rakus 245501
  
Roman Rakus 245501
! #define PATCHLEVEL 6
Roman Rakus 245501
  
Roman Rakus 245501
  #endif /* _PATCHLEVEL_H_ */
Roman Rakus 245501
--- 26,30 ----
Roman Rakus 245501
     looks for to find the patch level (for the sccs version string). */
Roman Rakus 245501
  
Roman Rakus 245501
! #define PATCHLEVEL 7
Roman Rakus 245501
  
Roman Rakus 245501
  #endif /* _PATCHLEVEL_H_ */