]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
fixes for array subscripts and values containing 0x01 characters
authorChet Ramey <chet.ramey@case.edu>
Tue, 28 Sep 2021 19:13:02 +0000 (15:13 -0400)
committerChet Ramey <chet.ramey@case.edu>
Tue, 28 Sep 2021 19:13:02 +0000 (15:13 -0400)
CWRU/CWRU.chlog
MANIFEST
arrayfunc.c
tests/array.right
tests/array29.sub
tests/assoc.right
tests/assoc.tests
tests/assoc15.sub [new file with mode: 0644]

index ea62e6e9b65dcb99d667653ea8a901c6c8068181..6c3f7d9ccd702eca166561b13222a9c837e6661f 100644 (file)
@@ -2105,3 +2105,25 @@ redir.c
        - do_redirection_internal: if given [N]<&WORD- or [N]>&WORD- and WORD
          expands to null, make it identical to <&- or >&- and close file
          descriptor N (default 0). From a discussion back in 5/2021
+
+                                  9/27
+                                  ----
+arrayfunc.c
+       - expand_compound_array_assignment: since we run the string through
+         the parser to turn it into a list (so we can make sure all shell
+         metacharacters are properly quoted), we need to remove the CTLESC
+         the parser uses to quote CTLESC and CTLNUL in *unquoted* words.
+         The rest of the code assumes this has been done, and assumes that
+         any CTLESC characters passed to expansion are part of the original
+         word and should themselves be quoted, doubling the number of CTLESCs
+
+                                  9/28
+                                  ----
+arrayfunc.c
+       - expand_and_quote_kvpair_word,quote_compound_array_word,
+         expand_and_quote_assoc_word,quote_compound_array_list: if we are
+         single-quoting associative array subscripts and associative and
+         indexed array values, we need to quote CTLESC characters, because
+         that's how they come out of the parser and how the assignment
+         statement code expects to see them.
+         Fixes https://savannah.gnu.org/support/index.php?110538
index f3c456d8184f7239abab82f7e2ffaf799127294e..c51bb3b084d51eb3f554274af0a9bba95dfbebe7 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -952,6 +952,7 @@ tests/assoc11.sub   f
 tests/assoc12.sub      f
 tests/assoc13.sub      f
 tests/assoc14.sub      f
+tests/assoc15.sub      f
 tests/attr.tests       f
 tests/attr.right       f
 tests/attr1.sub                f
index a000ce0369946a813962a9639673c3cab4adcb56..46cf4c8feb71b9314864ba98725db7287116fa56 100644 (file)
@@ -530,8 +530,17 @@ expand_compound_array_assignment (var, value, flags)
      shell expansions including pathname generation and word splitting. */
   /* First we split the string on whitespace, using the shell parser
      (ksh93 seems to do this). */
+  /* XXX - this needs a rethink, maybe use split_at_delims */
   list = parse_string_to_word_list (val, 1, "array assign");
 
+  /* If the parser has quoted CTLESC and CTNLNUL with CTLESC in unquoted
+     words, we need to remove those here because the code below assumes
+     they are there because they exist in the original word. */
+  /* XXX - if we rethink parse_string_to_word_list above, change this. */
+  for (nlist = list; nlist; nlist = nlist->next)
+    if ((nlist->word->flags & W_QUOTED) == 0)
+      remove_quoted_escapes (nlist->word->word);
+
   /* Note that we defer expansion of the assignment statements for associative
      arrays here, so we don't have to scan the subscript and find the ending
      bracket twice. See the caller below. */
@@ -616,15 +625,10 @@ expand_and_quote_kvpair_word (w)
   char *r, *s, *t;
 
   t = w ? expand_subscript_string (w, 0) : 0;
-#if 0  /* TAG:bash-5.2 */
   s = (t && strchr (t, CTLESC)) ? quote_escapes (t) : t;
   r = sh_single_quote (s ? s : "");
   if (s != t)
     free (s);
-#else
-  r = sh_single_quote (t ? t : "");
-#endif
-
   free (t);
   return r;
 }
@@ -907,7 +911,10 @@ quote_compound_array_word (w, type)
 
   wlen = strlen (w);
   w[ind] = '\0';
-  sub = sh_single_quote (w+1);
+  t = (strchr (w+1, CTLESC)) ? quote_escapes (w+1) : w+1;
+  sub = sh_single_quote (t);
+  if (t != w+1)
+   free (t);
   w[ind] = RBRACK;
 
   nword = xmalloc (wlen * 4 + 5);      /* wlen*4 is max single quoted length */
@@ -920,14 +927,10 @@ quote_compound_array_word (w, type)
   if (w[ind] == '+')
     nword[i++] = w[ind++];
   nword[i++] = w[ind++];
-#if 0  /* TAG:bash-5.2 */
   t = (strchr (w+ind, CTLESC)) ? quote_escapes (w+ind) : w+ind;
   value = sh_single_quote (t);
   if (t != w+ind)
    free (t);
-#else
-  value = sh_single_quote (w + ind);
-#endif
   strcpy (nword + i, value);
 
   return nword;
@@ -956,8 +959,11 @@ expand_and_quote_assoc_word (w, type)
 
   w[ind] = '\0';
   t = expand_subscript_string (w+1, 0);
+  s = (t && strchr (t, CTLESC)) ? quote_escapes (t) : t;
+  key = sh_single_quote (s ? s : "");
+  if (s != t)
+    free (s);
   w[ind] = RBRACK;
-  key = sh_single_quote (t ? t : "");
   free (t);
 
   wlen = STRLEN (key);
@@ -972,14 +978,10 @@ expand_and_quote_assoc_word (w, type)
   nword[i++] = w[ind++];
 
   t = expand_subscript_string (w+ind, 0);
-#if 0  /* TAG:bash-5.2 */
   s = (t && strchr (t, CTLESC)) ? quote_escapes (t) : t;
   value = sh_single_quote (s ? s : "");
   if (s != t)
     free (s);
-#else
-  value = sh_single_quote (t ? t : "");
-#endif
   free (t);
   nword = xrealloc (nword, wlen + 5 + STRLEN (value));
   strcpy (nword + i, value);
@@ -1008,14 +1010,10 @@ quote_compound_array_list (list, type)
        continue;       /* should not happen, but just in case... */
       if ((l->word->flags & W_ASSIGNMENT) == 0)
        {
-#if 0  /* TAG:bash-5.2 */
          s = (strchr (l->word->word, CTLESC)) ? quote_escapes (l->word->word) : l->word->word;
          t = sh_single_quote (s);
          if (s != l->word->word)
            free (s);
-#else
-         t = sh_single_quote (l->word->word);
-#endif
        }
       else 
        t = quote_compound_array_word (l->word->word, type);
index 6964bbd2d40d737970046abf32e5c0ae19523ae8..8ad96aef2b395e01d131fd1fdbdb56909a0b385c 100644 (file)
@@ -760,8 +760,12 @@ declare -a bug3=([0]="" [1]="5" [2]="" [3]="1" [4]="")
 declare -a not_bug=([0]="no" [1]="nulls")
 declare -a workaround=([0]="")
 declare -a var=([0]=$'\001\001\001\001')
+declare -A v2=([$'\001']=$'ab\001c' )
 declare -a foo=([0]=$'\001\001\001\001')
-declare -a foo=([0]=$'\001\001')
-declare -a foo=([0]=$'\001\001')
-declare -A foo=([v]=$'\001\001' )
-declare -A foo=([v]=$'\001\001' )
+declare -A foo=([$'\001']=$'ab\001c' )
+declare -a foo=([0]=$'\001\001\001\001')
+declare -a foo=([0]=$'\001\001\001\001')
+declare -A foo=([v]=$'\001\001\001\001' )
+declare -A foo=([v]=$'\001\001\001\001' )
+declare -A foo=([$'\001']=$'ab\001c' )
+declare -A foo=([$'\001']=$'ab\001c' )
index 32db758e33bb21eb9551cb3106df3d95599e971e..f73c2d1c6795aefdf44a39c47323296181804abe 100644 (file)
 #   You should have received a copy of the GNU General Public License
 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
+# Issues with CTLESC characters in array subscripts and values. Bash-5.1 and
+# earlier didn't quote them correctly and therefore halved the number of
+# CTLESCs.
+
+declare -a var
 var=( $'\x01\x01\x01\x01' )
 declare -p var
+declare -A v2
+v2=( $'\x01' ab$'\x01'c )
+declare -p v2
 
 pv()
 {
@@ -22,6 +30,15 @@ pv()
 }
 pv
 
+unset -f pv
+pv()
+{
+        local -A foo
+        eval foo=\( "${v2[@]@k}" \)
+        declare -p foo
+}
+pv
+
 # these are wrong through bash-5.1; there is a fix tagged for bash-5.2
 # when I uncomment that fix, these results will reflect it
 
@@ -52,3 +69,18 @@ pv4()
        declare -p foo
 }
 pv4
+
+unset -f pv3 pv4
+pv3()
+{
+       local -A foo=( $'\x01' "${v2[@]}" )
+       declare -p foo
+}
+pv3
+
+pv4()
+{
+       local -A foo=( [$'\x01']="${v2[@]}" )
+       declare -p foo
+}
+pv4
index cd73041316eb0638dcfdaff49aab3419e2a5bc47..f2351a3d13546141b86f3e7ec3af3eda9d3f70d1 100644 (file)
@@ -329,3 +329,26 @@ argv[7] = <'foo'>
 argv[8] = <'bar'>
 declare -A clone=([hello]="world" ["key with spaces"]="value with spaces" [foo]="bar" [one]="1" )
 declare -A posparams=([hello]="world" ["key with spaces"]="value with spaces" [foo]="bar" [one]="1" )
+declare -A var=([$'\001']=$'\001\001\001\001' )
+declare -A v2=([$'\001']=$'\001\001\001\001' )
+argv[1] = <^A>
+argv[2] = <^A^A^A^A>
+declare -A foo=([$'\001']=$'\001\001\001\001' )
+declare -A var=([$'\001']=$'\001\001\001\001' )
+argv[1] = <^A>
+argv[2] = <^A^A^A^A>
+declare -A foo=([$'\001']=$'\001\001\001\001' )
+declare -A var=([$'\001']=$'\001\001\001\001' )
+argv[1] = <^A>
+argv[2] = <^A^A^A^A>
+declare -A foo=([$'\001']=$'\001\001\001\001' )
+declare -a var=([0]=$'\001\001\001\001')
+argv[1] = <$'\001\001\001\001'>
+declare -a foo=([0]=$'\001\001\001\001')
+declare -a var=([0]=$'\001\001\001\001')
+argv[1] = <$'\001\001\001\001'>
+declare -a foo=([0]=$'\001\001\001\001')
+declare -A var=([two]=$'ab\001cd' [one]=$'\001\001\001\001' )
+declare -A foo=([two]=$'ab\001cd' [one]=$'\001\001\001\001' )
+declare -A foo=([$'\001']=$'ab\001cd' )
+declare -A foo=([$'\001']=$'\001\001\001\001' )
index 6158f74d4659c841b557791f27b87f10d0c0a201..30e5201d05f73e93e20660fcfefa3f255501661a 100644 (file)
@@ -253,3 +253,6 @@ ${THIS_SH} ./assoc13.sub
 
 # tests of the @k transformation on associative arrays
 ${THIS_SH} ./assoc14.sub
+
+# tests with subscripts and values containing 0x01 (some indexed array tests too)
+${THIS_SH} ./assoc15.sub
diff --git a/tests/assoc15.sub b/tests/assoc15.sub
new file mode 100644 (file)
index 0000000..c47b153
--- /dev/null
@@ -0,0 +1,92 @@
+#   This program is free software: you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation, either version 3 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# associative arrays first
+
+v=$'\x01'
+
+declare -A var foo v2
+var=( $'\x01' $'\x01\x01\x01\x01' )
+declare -p var
+v2=( $v $v$v$v$v )
+declare -p v2
+
+recho "${var[@]@k}"
+eval foo=\( "${var[@]@k}" \)
+declare -p foo
+
+var=( \ 1 \ 1\ 1\ 1\ 1 )
+declare -p var
+
+recho "${var[@]@k}"
+eval foo=\( "${var[@]@k}" \)
+declare -p foo
+
+var=( [\ 1]=\ 1\ 1\ 1\ 1 )
+declare -p var
+
+recho "${var[@]@k}"
+eval foo=\( "${var[@]@k}" \)
+declare -p foo
+
+# now indexed arrays
+unset -v var foo
+
+declare -a var
+var=( [0]=\ 1\ 1\ 1\ 1 )
+declare -p var
+
+declare -a foo
+recho "${var[@]@Q}"
+eval foo=\( "${var[@]@Q}" \)
+declare -p foo
+
+var=( \ 1\ 1\ 1\ 1 )
+declare -p var
+
+unset foo
+
+declare -a foo
+recho "${var[@]@Q}"
+eval foo=\( "${var[@]@Q}" \)
+declare -p foo
+
+# similar to array29.sub
+unset -v var foo v2
+
+declare -A var
+var=( one $'\x01\x01\x01\x01' two ab$'\001'cd )
+declare -p var
+
+pv()
+{
+       local -A foo
+       eval foo=\( "${var[@]@k}" \)
+       declare -p foo
+}
+pv
+
+pv1()
+{
+       local -A foo=( $'\x01' "${var[two]}" )
+       declare -p foo
+}
+pv1
+
+pv2()
+{
+       local -A foo=( [$'\x01']="${var[one]}" )
+       declare -p foo
+}
+pv2