fix for posix semantics for the := word expansion when assigning array elements

This commit is contained in:
Chet Ramey
2021-12-14 14:18:00 -05:00
parent 567c0bc2ed
commit 5f2dd5ff95
17 changed files with 165 additions and 23 deletions
+22
View File
@@ -2640,3 +2640,25 @@ variables.c
doc/Makefile.in
- changes to allow man pages that include others (.so FN) to be built
outside the source tree
12/13
-----
arrayfunc.c
- assign_array_element_internal: take an additional argument: char **NVALP.
If non-null, it gets the value eventually assigned to the array
element
- assign_array_element: take an additional NVALP argument; pass it to
assign_array_element_internal
arrayfunc.h
- assign_array_element: new extern function declaration
{subst,variables}.c,builtins/{common.c,declare.def}
- assign_array_element: change callers
subst.c
- parameter_brace_expand_rhs: for the ${param:=value}, use the value
returned by assign_array_element in NVALP as the return value, since
it's the value ultimately assigned to the variable after possible
modification (e.g., arithmetic evaluation). Reported by
oguzismailuysal@gmail.com after flawed fix applied 11/16
+1
View File
@@ -933,6 +933,7 @@ tests/array26.sub f
tests/array27.sub f
tests/array28.sub f
tests/array29.sub f
tests/array30.sub f
tests/array-at-star f
tests/array2.right f
tests/assoc.tests f
-2
View File
@@ -27,8 +27,6 @@
typedef intmax_t arrayind_t;
enum atype {array_indexed, array_assoc}; /* not used */
typedef struct array {
arrayind_t max_index;
arrayind_t num_elements;
+14 -4
View File
@@ -53,7 +53,7 @@ int assoc_expand_once = 0;
int array_expand_once = 0;
static SHELL_VAR *bind_array_var_internal PARAMS((SHELL_VAR *, arrayind_t, char *, char *, int));
static SHELL_VAR *assign_array_element_internal PARAMS((SHELL_VAR *, char *, char *, char *, int, char *, int));
static SHELL_VAR *assign_array_element_internal PARAMS((SHELL_VAR *, char *, char *, char *, int, char *, int, char **));
static void assign_assoc_from_kvlist PARAMS((SHELL_VAR *, WORD_LIST *, HASH_TABLE *, int));
@@ -322,9 +322,10 @@ bind_assoc_variable (entry, name, key, value, flags)
assign VALUE to that array element by calling bind_array_variable().
Flags are ASS_ assignment flags */
SHELL_VAR *
assign_array_element (name, value, flags)
assign_array_element (name, value, flags, nvalp)
char *name, *value;
int flags;
char **nvalp;
{
char *sub, *vname;
int sublen, isassoc;
@@ -352,14 +353,14 @@ assign_array_element (name, value, flags)
return ((SHELL_VAR *)NULL);
}
entry = assign_array_element_internal (entry, name, vname, sub, sublen, value, flags);
entry = assign_array_element_internal (entry, name, vname, sub, sublen, value, flags, nvalp);
free (vname);
return entry;
}
static SHELL_VAR *
assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
assign_array_element_internal (entry, name, vname, sub, sublen, value, flags, nvalp)
SHELL_VAR *entry;
char *name; /* only used for error messages */
char *vname;
@@ -367,9 +368,11 @@ assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
int sublen;
char *value;
int flags;
char **nvalp;
{
char *akey;
arrayind_t ind;
char *newval;
if (entry && assoc_p (entry))
{
@@ -386,6 +389,7 @@ assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
return ((SHELL_VAR *)NULL);
}
entry = bind_assoc_variable (entry, vname, akey, value, flags);
newval = entry ? assoc_reference (assoc_cell (entry), akey) : 0;
}
else
{
@@ -399,8 +403,14 @@ assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
return ((SHELL_VAR *)NULL);
}
entry = bind_array_variable (vname, ind, value, flags);
newval = entry ? array_reference (array_cell (entry), ind) : 0;
}
/* If the caller asks, return the (possibly modified) final value assigned.
This saves subseqent lookups. */
if (nvalp)
*nvalp = newval;
return (entry);
}
+1 -1
View File
@@ -56,7 +56,7 @@ extern char *make_array_variable_value PARAMS((SHELL_VAR *, arrayind_t, char *,
extern SHELL_VAR *bind_array_variable PARAMS((char *, arrayind_t, char *, int));
extern SHELL_VAR *bind_array_element PARAMS((SHELL_VAR *, arrayind_t, char *, int));
extern SHELL_VAR *assign_array_element PARAMS((char *, char *, int));
extern SHELL_VAR *assign_array_element PARAMS((char *, char *, int, char **));
extern SHELL_VAR *bind_assoc_variable PARAMS((SHELL_VAR *, char *, char *, char *, int));
+1 -1
View File
@@ -1004,7 +1004,7 @@ builtin_bind_variable (name, value, flags)
if (valid_array_reference (name, vflags) == 0)
v = bind_variable (name, value, flags);
else
v = assign_array_element (name, value, bindflags);
v = assign_array_element (name, value, bindflags, (char **)0);
#else /* !ARRAY_VARS */
v = bind_variable (name, value, flags);
#endif /* !ARRAY_VARS */
+1 -1
View File
@@ -949,7 +949,7 @@ restart_new_var_name:
local_aflags = aflags&ASS_APPEND;
local_aflags |= assoc_noexpand ? ASS_NOEXPAND : 0;
local_aflags |= ASS_ALLOWALLSUB; /* allow declare a[@]=at */
var = assign_array_element (name, value, local_aflags); /* XXX - not aflags */
var = assign_array_element (name, value, local_aflags, (char **)0); /* XXX - not aflags */
*subscript_start = '\0';
if (var == 0) /* some kind of assignment error */
{
+1 -1
View File
@@ -281,7 +281,7 @@ An \fIinteractive\fP shell is one started without non-option arguments
(unless \fB\-s\fP is specified)
and without the
.B \-c
option
option,
whose standard input and error are
both connected to terminals (as determined by
.IR isatty (3)),
+3 -2
View File
@@ -7091,8 +7091,9 @@ the same, but the effective user id is not reset.
@subsection What is an Interactive Shell?
An interactive shell
is one started without non-option arguments, unless @option{-s} is
specified, without specifying the @option{-c} option, and
is one started without non-option arguments
(unless @option{-s} is specified)
and without specifying the @option{-c} option,
whose input and error output are both
connected to terminals (as determined by @code{isatty(3)}),
or one started with the @option{-i} option.
+15 -7
View File
@@ -3308,7 +3308,7 @@ do_assignment_internal (word, expand)
ASSIGN_RETURN (0);
}
aflags |= ASS_ALLOWALLSUB; /* allow a[@]=value for existing associative arrays */
entry = assign_array_element (name, value, aflags);
entry = assign_array_element (name, value, aflags, (char **)0);
if (entry == 0)
ASSIGN_RETURN (0);
}
@@ -7227,8 +7227,8 @@ parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdoll
{
WORD_DESC *w;
WORD_LIST *l, *tl;
char *t, *t1, *temp, *vname;
int l_hasdollat, sindex;
char *t, *t1, *temp, *vname, *newval;
int l_hasdollat, sindex, arrayref;
SHELL_VAR *v;
/*itrace("parameter_brace_expand_rhs: %s:%s pflags = %d", name, value, pflags);*/
@@ -7374,9 +7374,13 @@ parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdoll
}
}
arrayref = 0;
#if defined (ARRAY_VARS)
if (valid_array_reference (vname, 0))
v = assign_array_element (vname, t1, 0);
{
v = assign_array_element (vname, t1, ASS_ALLOWALLSUB, &newval);
arrayref = 1;
}
else
#endif /* ARRAY_VARS */
v = bind_variable (vname, t1, 0);
@@ -7399,16 +7403,20 @@ parameter_brace_expand_rhs (name, value, op, quoted, pflags, qdollaratp, hasdoll
stupidly_hack_special_variables (vname);
if (vname != name)
free (vname);
/* "In all cases, the final value of parameter shall be substituted." */
if (shell_compatibility_level > 51)
{
FREE (t1);
#if defined (ARRAY_VARS)
t1 = arrayref ? newval : get_variable_value (v);
#else
t1 = value_cell (v);
#endif
}
if (vname != name)
free (vname);
/* From Posix group discussion Feb-March 2010. Issue 7 0000221 */
/* If we are double-quoted or if we are not going to be performing word
+12
View File
@@ -773,3 +773,15 @@ 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' )
foo
declare -a a=([42]="foo")
foo
declare -a a=([42]="foo")
7
declare -ai a=([42]="7")
42
declare -ai a=([42]="42")
FOO
declare -Au A=([Darwin]="FOO" )
FOO
declare -Au A=(["@"]="FOO" )
+1
View File
@@ -426,3 +426,4 @@ ${THIS_SH} ./array26.sub
${THIS_SH} ./array27.sub
${THIS_SH} ./array28.sub
${THIS_SH} ./array29.sub
${THIS_SH} ./array30.sub
+46
View File
@@ -0,0 +1,46 @@
# 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/>.
#
declare -a a
a=()
echo ${a[42]=foo}
declare -p a
a=()
echo ${a[$(echo 42)]=foo}
declare -p a
unset a
declare -ai a
a=()
echo ${a[42]=4+3}
declare -p a
a=()
echo ${a[$(echo 42)]=42}
declare -p a
unset a
declare -A A
declare -u A
A=()
echo ${A[$(echo Darwin)]=foo}
declare -p A
A=()
echo ${A[@]:=foo}
declare -p A
+8
View File
@@ -409,3 +409,11 @@ cdefg
abcdefg
abcde
abcdefg
foo
declare -- a="foo"
7
declare -i a="7"
42
declare -- a="42"
FOO
declare -u A="FOO"
+1
View File
@@ -423,3 +423,4 @@ ${THIS_SH} ./exp9.sub
${THIS_SH} ./exp10.sub
${THIS_SH} ./exp11.sub
${THIS_SH} ./exp12.sub
${THIS_SH} ./exp13.sub
+34
View File
@@ -0,0 +1,34 @@
# 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/>.
#
unset a
echo ${a:=foo}
declare -p a
unset a
declare -i a
echo ${a:=4+3}
declare -p a
unset a
echo ${a:=42}
declare -p a
unset a
declare -u A
A=
echo ${A:=foo}
declare -p A
+4 -4
View File
@@ -2495,7 +2495,7 @@ get_variable_value (var)
/* Return the string value of a variable. Return NULL if the variable
doesn't exist. Don't cons a new string. This is a potential memory
leak if the variable is found in the temporary environment, but doesn't
leak in practice. Since functions and variables have separate name
leak in practice. Since functions and variables have separate name
spaces, returns NULL if var_name is a shell function only. */
char *
get_string_value (var_name)
@@ -3111,7 +3111,7 @@ bind_variable_internal (name, value, table, hflags, aflags)
assign_array_element will eventually do it itself based on
newval and aflags. */
entry = assign_array_element (newval, value, aflags|ASS_NAMEREF);
entry = assign_array_element (newval, value, aflags|ASS_NAMEREF, (char **)0);
if (entry == 0)
return entry;
}
@@ -3268,7 +3268,7 @@ bind_variable (name, value, flags)
return (bind_variable_internal (nv->name, value, nvc->table, 0, flags));
#if defined (ARRAY_VARS)
else if (valid_array_reference (nameref_cell (nv), 0))
return (assign_array_element (nameref_cell (nv), value, flags));
return (assign_array_element (nameref_cell (nv), value, flags, (char **)0));
else
#endif
return (bind_variable_internal (nameref_cell (nv), value, nvc->table, 0, flags));
@@ -3433,7 +3433,7 @@ bind_int_variable (lhs, rhs, flags)
#if defined (ARRAY_VARS)
if (isarr)
v = assign_array_element (lhs, rhs, flags);
v = assign_array_element (lhs, rhs, flags, (char **)0);
else if (implicitarray)
v = bind_array_variable (lhs, 0, rhs, 0); /* XXX - check on flags */
else