]> git.ipfire.org Git - thirdparty/bash.git/blobdiff - arrayfunc.c
fix nofork comsub overwriting currently executing command; free readline undo list...
[thirdparty/bash.git] / arrayfunc.c
index 28aee54b804479e5e4a1f14315d24a6e4b6b34a3..d56be4283d90286110085d4d87941344f055edb8 100644 (file)
@@ -1,6 +1,6 @@
 /* arrayfunc.c -- High-level array functions used by other parts of the shell. */
 
-/* Copyright (C) 2001-2023 Free Software Foundation, Inc.
+/* Copyright (C) 2001-2024 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -142,6 +142,26 @@ convert_var_to_assoc (SHELL_VAR *var)
   return var;
 }
 
+/* Copy the array (ARRAY *) or assoc (HASH_TABLE *) from variable V1 to V2,
+   and return V2. */
+SHELL_VAR *
+arrayvar_copyval (SHELL_VAR *v1, SHELL_VAR *v2)
+{
+  FREE (value_cell (v2));
+  VUNSETATTR (v2, (att_array | att_assoc));
+  if (array_p (v1))
+    {
+      var_setarray (v2, array_copy (array_cell (v1)));
+      VSETATTR (v2, att_array);
+    }
+  else if (assoc_p (v1))
+    {
+      var_setassoc (v2, assoc_copy (assoc_cell (v1)));
+      VSETATTR (v2, att_assoc);
+    }
+  return v2;
+}
+
 char *
 make_array_variable_value (SHELL_VAR *entry, arrayind_t ind, const char *key, const char *value, int flags)
 {
@@ -193,7 +213,10 @@ bind_assoc_var_internal (SHELL_VAR *entry, HASH_TABLE *hash, char *key, const ch
   newval = make_array_variable_value (entry, 0, key, value, flags);
 
   if (entry->assign_func)
-    (*entry->assign_func) (entry, newval, 0, key);
+    {
+      (*entry->assign_func) (entry, newval, 0, key);
+      FREE (key);
+    }
   else
     assoc_insert (hash, key, newval);
 
@@ -422,7 +445,8 @@ assign_array_element_internal (SHELL_VAR *entry, const char *name, char *vname,
    convert it to an indexed array.  If FLAGS&1 is non-zero, an existing
    variable is checked for the readonly or noassign attribute in preparation
    for assignment (e.g., by the `read' builtin).  If FLAGS&2 is non-zero, we
-   create an associative array. */
+   create an associative array. If FLAGS&4 is non-zero, we return noassign
+   variables instead of NULL because the caller wants to handle them. */
 SHELL_VAR *
 find_or_make_array_variable (const char *name, int flags)
 {
@@ -456,6 +480,8 @@ find_or_make_array_variable (const char *name, int flags)
     {
       if (readonly_p (var))
        err_readonly (name);
+      if ((flags & 4) && noassign_p (var))
+       return (var);
       return ((SHELL_VAR *)NULL);
     }
   else if ((flags & 2) && array_p (var))
@@ -483,10 +509,11 @@ assign_array_from_string (const char *name, char *value, int flags)
   vflags = 1;
   if (flags & ASS_MKASSOC)
     vflags |= 2;
+  vflags |= 4;         /* we want to handle noassign variables ourselves */
 
   var = find_or_make_array_variable (name, vflags);
-  if (var == 0)
-    return ((SHELL_VAR *)NULL);
+  if (var == 0 || noassign_p (var))
+    return (var);
 
   return (assign_array_var_from_string (var, value, flags));
 }
@@ -504,7 +531,19 @@ assign_array_var_from_word_list (SHELL_VAR *var, WORD_LIST *list, int flags)
   i = (flags & ASS_APPEND) ? array_max_index (a) + 1 : 0;
 
   for (l = list; l; l = l->next, i++)
-    bind_array_var_internal (var, i, 0, l->word->word, flags & ~ASS_APPEND);
+    {
+      if (a && i < 0)  /* overflow */
+       {
+         char *num;
+
+         num = itos (i);
+         report_error ("%s[%s]: %s", var->name, num, bash_badsub_errmsg);
+         free (num);
+         return (var);         /* XXX */
+       }
+
+      bind_array_var_internal (var, i, 0, l->word->word, flags & ~ASS_APPEND);
+    }
 
   VUNSETATTR (var, att_invisible);     /* no longer invisible */
 
@@ -516,7 +555,7 @@ expand_compound_array_assignment (SHELL_VAR *var, char *value, int flags)
 {
   WORD_LIST *list, *nlist;
   char *val;
-  int ni;
+  size_t ni;
 
   /* This condition is true when invoked from the declare builtin with a
      command like
@@ -654,14 +693,14 @@ expand_and_quote_kvpair_word (const char *w)
 
    If this is an associative array, we perform the assignments into NHASH and
    set NHASH to be the value of VAR after processing the assignments in NLIST */
-void
+int
 assign_compound_array_list (SHELL_VAR *var, WORD_LIST *nlist, int flags)
 {
   ARRAY *a;
   HASH_TABLE *h, *nhash;
   WORD_LIST *list;
   char *w, *val, *nval, *savecmd;
-  int len, iflags, free_val;
+  int len, iflags, free_val, any_failed;
   arrayind_t ind, last_ind;
   char *akey;
 
@@ -671,6 +710,8 @@ assign_compound_array_list (SHELL_VAR *var, WORD_LIST *nlist, int flags)
   akey = (char *)0;
   ind = 0;
 
+  any_failed = 0;
+
   /* Now that we are ready to assign values to the array, kill the existing
      value. */
   if ((flags & ASS_APPEND) == 0)
@@ -681,8 +722,6 @@ assign_compound_array_list (SHELL_VAR *var, WORD_LIST *nlist, int flags)
        nhash = assoc_create (h->nbuckets);
     }
 
-  last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0;
-
 #if ASSOC_KVPAIR_ASSIGNMENT
   if (assoc_p (var) && kvpair_assignment_p (nlist))
     {
@@ -694,10 +733,12 @@ assign_compound_array_list (SHELL_VAR *var, WORD_LIST *nlist, int flags)
          var_setassoc (var, nhash);
          assoc_dispose (h);
        }
-      return;
+      return 1;                /* XXX - check return value */
     }
 #endif
 
+  last_ind = (a && (flags & ASS_APPEND)) ? array_max_index (a) + 1 : 0;
+
   for (list = nlist; list; list = list->next)
     {
       /* Don't allow var+=(values) to make assignments in VALUES append to
@@ -716,10 +757,11 @@ assign_compound_array_list (SHELL_VAR *var, WORD_LIST *nlist, int flags)
          /* XXX - changes for `+=' */
          if (w[len] != ']' || (w[len+1] != '=' && (w[len+1] != '+' || w[len+2] != '=')))
            {
-             if (assoc_p (var))
+             if (assoc_p (var) || last_ind < 0)
                {
                  err_badarraysub (w);
-                 continue;
+                 any_failed++;
+                 break;
                }
              nval = make_variable_value (var, w, flags);
              if (var->assign_func)
@@ -734,14 +776,16 @@ assign_compound_array_list (SHELL_VAR *var, WORD_LIST *nlist, int flags)
          if (len == 1)
            {
              err_badarraysub (w);
-             continue;
+             any_failed++;
+             break;
            }
 
          if (ALL_ELEMENT_SUB (w[1]) && len == 2 && array_p (var))
            {
              set_exit_status (EXECUTION_FAILURE);
              report_error (_("%s: cannot assign to non-numeric index"), w);
-             continue;
+             any_failed++;
+             break;
            }
 
          if (array_p (var))
@@ -757,7 +801,8 @@ assign_compound_array_list (SHELL_VAR *var, WORD_LIST *nlist, int flags)
              if (ind < 0)
                {
                  err_badarraysub (w);
-                 continue;
+                 any_failed++;
+                 break;
                }
 
              last_ind = ind;
@@ -773,7 +818,8 @@ assign_compound_array_list (SHELL_VAR *var, WORD_LIST *nlist, int flags)
                {
                  err_badarraysub (w);
                  FREE (akey);
-                 continue;
+                 any_failed++;
+                 break;
                }
            }
 
@@ -790,7 +836,8 @@ assign_compound_array_list (SHELL_VAR *var, WORD_LIST *nlist, int flags)
        {
          set_exit_status (EXECUTION_FAILURE);
          report_error (_("%s: %s: must use subscript when assigning associative array"), var->name, w);
-         continue;
+         any_failed++;
+         break;
        }
       else             /* No [ind]=value, just a stray `=' */
        {
@@ -798,6 +845,16 @@ assign_compound_array_list (SHELL_VAR *var, WORD_LIST *nlist, int flags)
          val = w;
        }
 
+      if (array_p (var) && ind < 0)    /* overflow */
+       {
+         char *num;
+
+         num = itos (ind);
+         report_error ("%s[%s]: %s", var->name, num, bash_badsub_errmsg);
+         free (num);
+         return 0;
+       }
+
       free_val = 0;
       /* See above; we need to expand the value here */
       if (assoc_p (var))
@@ -831,6 +888,16 @@ assign_compound_array_list (SHELL_VAR *var, WORD_LIST *nlist, int flags)
       var_setassoc (var, nhash);
       assoc_dispose (h);
     }
+
+#if ARRAY_EXPORT
+  if (var && exported_p (var))
+    {
+      INVALIDATE_EXPORTSTR (var);
+      array_needs_making = 1;
+    }
+#endif
+
+  return (any_failed ? 0 : 1);
 }
 
 /* Perform a compound array assignment:  VAR->name=( VALUE ).  The
@@ -840,7 +907,7 @@ SHELL_VAR *
 assign_array_var_from_string (SHELL_VAR *var, char *value, int flags)
 {
   WORD_LIST *nlist;
-  int aflags;
+  int aflags, r;
 
   if (value == 0)
     return var;
@@ -850,7 +917,7 @@ assign_array_var_from_string (SHELL_VAR *var, char *value, int flags)
      expand_compound_array_assignment performs word expansions. Honors
      array_expand_once; allows @ and * as associative array keys. */
   aflags = flags | (array_expand_once ? ASS_NOEXPAND : 0) | ASS_ALLOWALLSUB;
-  assign_compound_array_list (var, nlist, aflags);
+  r = assign_compound_array_list (var, nlist, aflags);
 
   if (nlist)
     dispose_words (nlist);
@@ -858,7 +925,7 @@ assign_array_var_from_string (SHELL_VAR *var, char *value, int flags)
   if (var)
     VUNSETATTR (var, att_invisible);   /* no longer invisible */
 
-  return (var);
+  return (r == 0 ? (SHELL_VAR *)0 : var);
 }
 
 /* Quote globbing chars and characters in $IFS before the `=' in an assignment
@@ -945,6 +1012,7 @@ quote_compound_array_word (char *w, int type)
   if (t != w+ind)
    free (t);
   strcpy (nword + i, value);
+  free (value);
 
   return nword;
 }
@@ -988,7 +1056,6 @@ expand_and_quote_assoc_word (char *w, int type)
     nword[i++] = w[ind++];
   nword[i++] = w[ind++];
 
-
   t = expand_assignment_string_to_string (w+ind, 0);
   s = (t && strchr (t, CTLESC)) ? quote_escapes (t) : t;
   value = sh_single_quote (s ? s : "");
@@ -1226,7 +1293,7 @@ tokenize_array_reference (const char *name, int flags, char **subp)
   if (t)
     {
       *t = '\0';
-      r = legal_identifier (name);
+      r = valid_identifier (name);
       if (flags & VA_NOEXPAND) /* Don't waste a lookup if we don't need one */
        isassoc = (entry = find_variable (name)) && assoc_p (entry);      
       *t = '[';