commit bash-20160603 snapshot

This commit is contained in:
Chet Ramey
2016-06-07 16:46:16 -04:00
parent 80df5e5041
commit 80c3b1d4bd
17 changed files with 834 additions and 782 deletions
+109
View File
@@ -11153,3 +11153,112 @@ builtins/declare.def
removed from a readonly nameref variable that has a value, even if it
doesn't reference an existing variable. This distinction is for ksh93
compatibility. Pointed out by Grisha Levit <grishalevit@gmail.com>
5/31
----
builtins/declare.def
- declare_internal: if the call to bind_variable_value fails for some
reason, make sure to restore the nameref attribute to flags_on and
flags_off before calling NEXT_VARIABLE
subst.c
- make_internal_declare: handle += append op
- shell_expand_word_list: when transforming assignment statement arguments
to `declare', make sure to handle += append op to avoid passing invalid
identifiers to declare. Report by Grisha Levit <grishalevit@gmail.com>
6/1
---
builtins/declare.def
- declare_internal: if a nameref assignment fails, only call delete_var to
delete the variable if we created it in declare_internal in the first
place
general.c
- check_selfref: new function, checks a NAME against a VALUE for nameref
self-reference
general.h
- check_selfref: extern declaration
builtins/declare.def
- declare_internal: call check_selfref to determine whether a given NAME
and VALUE constitute an invalid nameref variable self-reference
variables.c
- bind_variable_internal: call check_selfref to determine whether a given
NAME and VALUE constitute an invalid nameref variable self-reference
6/2
---
parse.y
- clear_shell_input_line: new function, clears contents of shell_input_line
and sets index to 0, but doesn't free it
externs.h
- clear_shell_input_line: extern declaration
builtins/evalstring.c
- parse_and_execute: call clear_shell_input_line after setting input to
string to be executed. Fixes problem with command substitution and
multi-line aliases reported by Grisha Levit <grishalevit@gmail.com>
eval.c
- parse_command: only execute PROMPT_COMMAND if the shell is not
currently expanding an alias; use the same tests as parse.y:SHOULD_PROMPT
and parse.y:prompt_again() use to decide whether or not to print a
prompt. Fixes problems with PROMPT_COMMAND and multi-line aliases
reported by Grisha Levit <grishalevit@gmail.com>
builtins/set.def
- unset_builtin: changes to fix three problems reported by Grisha
Levit <grishalevit@gmail.com>:
o if -n is supplied, we should not try to unset a function if
a variable isn't found
o unsetting namerefs whose values are array references does
not work
o unset -n n[0], where n is a nameref, would unset the referenced
variable instead of `n'
redir.c
- redir_varvalue: handle case where nameref var points to subscripted
array reference. Reported by Grisha Levit <grishalevit@gmail.com>
variables.c
- bind_variable_value: make sure to call check_selfref only if aflags
includes ASS_NAMEREF and not ASS_FORCE. Reported by Grisha Levit
<grishalevit@gmail.com>
general.c
- valid_nameref_value: now understands a FLAGS value of 2 to mean that
the name will be used to create a variable, so only legal_identifier
matters
arrayfunc.c
- find_or_make_array_variable: call valid_nameref_value with FLAGS value
of 2 to indicate we will be creating a variable. Fixes mapfile issue
reported by Grisha Levit <grishalevit@gmail.com>
6/5
---
builtins/declare.def
- declare_internal: only pass ASS_FORCE as part of assignment flags to
assignments concerning arrays
- declare_internal: when at the global scope, if we resolve a nameref
and commit to using the new name, go back to to the beginning of the
loop and use the new name in the checks and variable references.
Make sure we construct the new name as a straight substitution of
the nameref value into the old name, including array subscripts and
rebuilding the correct values for `offset' and `value', since they
are relative to the original value of name.
Fixes several issues with checking use of subscripted array variables
as nameref values
- declare_internal: when calling assign_array_element, make sure to pass
ASS_APPEND if aflags includes it, so things like
declare -a var; var[1]=1; declare var[1]+=4
append to the value appropriately and var[1] ends up being `14'
arrayfunc.c
- valid_array_reference: make sure the array reference is properly
terminated after the first subscript; return invalid if there is
anything following the closing `]'
+3 -1
View File
@@ -370,7 +370,7 @@ find_or_make_array_variable (name, flags)
}
if (var && nameref_p (var))
{
if (valid_nameref_value (nameref_cell (var), 1) == 0)
if (valid_nameref_value (nameref_cell (var), 2) == 0)
{
sh_invalidid (nameref_cell (var));
return ((SHELL_VAR *)NULL);
@@ -899,6 +899,8 @@ valid_array_reference (name, flags)
len = skipsubscript (t, 0, 0);
if (t[len] != ']' || len == 1)
return 0;
if (t[len+1] != '\0')
return 0;
for (r = 1; r < len; r++)
if (whitespace (t[r]) == 0)
return 1;
+67 -36
View File
@@ -286,8 +286,8 @@ declare_internal (list, local_var)
/* There are arguments left, so we are making variables. */
while (list) /* declare [-aAfFirx] name [name ...] */
{
char *value, *name;
int offset, aflags, wflags;
char *value, *name, *oldname;
int offset, aflags, wflags, created_var, namelen;
#if defined (ARRAY_VARS)
int making_array_special, compound_array_assign, simple_array_assign;
int var_exists, array_exists, creating_array, array_subscript_assignment;
@@ -297,6 +297,7 @@ declare_internal (list, local_var)
wflags = list->word->flags;
offset = assignment (name, 0);
aflags = 0;
created_var = 0;
if (local_var && variable_context && STREQ (name, "-"))
{
@@ -332,27 +333,10 @@ declare_internal (list, local_var)
assign_error++;
NEXT_VARIABLE ();
}
else if (valid_array_reference (value, 0))
{
t = array_variable_name (value, (int *)NULL, (int *)NULL);
if (t && STREQ (name, t))
{
if (variable_context == 0)
{
free (t);
builtin_error (_("%s: nameref variable self references not allowed"), name);
assign_error++;
NEXT_VARIABLE ();
}
else
builtin_warning (_("%s: circular name reference"), name);
}
free (t);
}
else
#endif
/* disallow self references at global scope, warn at function scope */
if (STREQ (name, value))
if (check_selfref (name, value, 0))
{
if (variable_context == 0)
{
@@ -364,7 +348,7 @@ declare_internal (list, local_var)
builtin_warning (_("%s: circular name reference"), name);
}
#if 1
if (value && *value && (aflags & ASS_APPEND) == 0 && valid_nameref_value (value, 0) == 0)
if (value && *value && (aflags & ASS_APPEND) == 0 && valid_nameref_value (value, 1) == 0)
{
builtin_error (_("`%s': invalid variable name for name reference"), value);
assign_error++;
@@ -374,13 +358,15 @@ declare_internal (list, local_var)
}
#if defined (ARRAY_VARS)
restart_new_var_name:
var_exists = array_exists = creating_array = 0;
compound_array_assign = simple_array_assign = 0;
array_subscript_assignment = 0;
subscript_start = (char *)NULL;
if (t = strchr (name, '[')) /* ] */
{
/* If offset != 0 we have already validated any array reference */
/* If offset != 0 we have already validated any array reference
because assignment() calls skipsubscript() */
if (offset == 0 && valid_array_reference (name, 0) == 0)
{
sh_invalidid (name);
@@ -417,6 +403,7 @@ declare_internal (list, local_var)
refvar = (SHELL_VAR *)NULL;
if (variable_context && mkglobal == 0 && ((flags_on & att_function) == 0))
{
/* check name for validity here? */
#if defined (ARRAY_VARS)
if (flags_on & att_assoc)
var = make_local_assoc_variable (name);
@@ -446,6 +433,7 @@ declare_internal (list, local_var)
/* otherwise we have a var at the right context */
}
else
/* XXX - check name for validity here with valid_nameref_value */
var = make_local_variable (name); /* sets att_invisible for new vars */
if (var == 0)
{
@@ -592,8 +580,50 @@ declare_internal (list, local_var)
var = mkglobal ? find_global_variable (nameref_cell (refvar)) : find_variable (nameref_cell (refvar));
if (refvar && var == 0)
{
free (name);
name = savestring (nameref_cell (refvar));
oldname = name; /* need to free this */
namelen = strlen (nameref_cell (refvar));
#if defined (ARRAY_VARS)
if (subscript_start)
{
*subscript_start = '['; /*]*/
namelen += strlen (subscript_start);
}
#endif
name = xmalloc (namelen + 2 + strlen (value) + 1);
strcpy (name, nameref_cell (refvar));
#if defined (ARRAY_VARS)
if (subscript_start)
strcpy (name + strlen (nameref_cell (refvar)), subscript_start);
#endif
/* We are committed to using the new name, so reset */
if (offset)
{
/* Rebuild assignment and restore offset and value */
if (aflags & ASS_APPEND)
name[namelen++] = '+';
name[namelen++] = '=';
if (value && *value)
strcpy (name + namelen, value);
else
name[namelen] = '\0';
offset = assignment (name, 0);
/* if offset was valid previously, but the substituting
of the nameref value results in an invalid assignment,
throw an invalid identifier error */
if (offset == 0)
{
free (oldname);
sh_invalidid (name);
assign_error++;
NEXT_VARIABLE ();
}
name[offset] = '\0';
value = name + namelen;
}
free (oldname);
goto restart_new_var_name;
/* NOTREACHED */
}
}
if (var == 0)
@@ -622,13 +652,9 @@ declare_internal (list, local_var)
}
else
#endif
if (offset)
/* We're just setting a temporary value here, so force assignment */
var = mkglobal ? bind_global_variable (name, (char *)NULL, ASS_FORCE) : bind_variable (name, (char *)NULL, ASS_FORCE);
else
{
var = mkglobal ? bind_global_variable (name, (char *)NULL, ASS_FORCE) : bind_variable (name, (char *)NULL, ASS_FORCE);
if (var && no_invisible_vars == 0)
if (var && offset == 0 && no_invisible_vars == 0)
VSETATTR (var, att_invisible);
}
if (var == 0)
@@ -636,6 +662,7 @@ declare_internal (list, local_var)
/* Has to appear in brackets */
NEXT_VARIABLE ();
}
created_var = 1;
}
/* Can't take an existing array variable and make it a nameref */
else if ((array_p (var) || assoc_p (var)) && (flags_on & att_nameref))
@@ -775,14 +802,14 @@ declare_internal (list, local_var)
VUNSETATTR (var, flags_off);
#if defined (ARRAY_VARS)
aflags |= ASS_FORCE;
if (offset && compound_array_assign)
assign_array_var_from_string (var, value, aflags);
assign_array_var_from_string (var, value, aflags|ASS_FORCE);
else if (simple_array_assign && subscript_start)
{
/* declare [-aA] name[N]=value */
*subscript_start = '['; /* ] */
var = assign_array_element (name, value, 0); /* XXX - not aflags */
/* XXX - problem here with appending */
var = assign_array_element (name, value, aflags&ASS_APPEND); /* XXX - not aflags */
*subscript_start = '\0';
if (var == 0) /* some kind of assignment error */
{
@@ -796,12 +823,13 @@ declare_internal (list, local_var)
{
/* let bind_{array,assoc}_variable take care of this. */
if (assoc_p (var))
bind_assoc_variable (var, name, savestring ("0"), value, aflags);
bind_assoc_variable (var, name, savestring ("0"), value, aflags|ASS_FORCE);
else
bind_array_variable (name, 0, value, aflags);
bind_array_variable (name, 0, value, aflags|ASS_FORCE);
}
else
#endif
/* XXX - no ASS_FORCE here */
/* bind_variable_value duplicates the essential internals of
bind_variable() */
if (offset)
@@ -811,11 +839,14 @@ declare_internal (list, local_var)
v = bind_variable_value (var, value, aflags);
if (v == 0 && (onref || nameref_p (var)))
{
if (valid_nameref_value (value, 0) == 0)
if (valid_nameref_value (value, 1) == 0)
sh_invalidid (value);
assign_error++;
/* XXX - unset this variable? or leave it as normal var? */
delete_var (var->name, mkglobal ? global_variables : shell_variables);
if (created_var)
delete_var (var->name, mkglobal ? global_variables : shell_variables);
flags_on |= onref; /* undo change from above */
flags_off |= offref;
NEXT_VARIABLE ();
}
}
+2 -1
View File
@@ -267,6 +267,7 @@ parse_and_execute (string, from_file, flags)
current_token = '\n'; /* reset_parser() ? */
with_input_from_string (string, from_file);
clear_shell_input_line ();
while (*(bash_input.location.string))
{
command = (COMMAND *)NULL;
@@ -497,7 +498,7 @@ parse_string (string, from_file, flags, endp)
sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &ps_sigmask);
#endif
/* itrace("parse_string: `%s'", string); */
/*itrace("parse_string: `%s'", string);*/
/* Reset the line number if the caller wants us to. If we don't reset the
line number, we have to subtract one, because we will add one just
before executing the next command (resetting the line number sets it to
+20 -5
View File
@@ -808,7 +808,7 @@ unset_builtin (list)
{
int unset_function, unset_variable, unset_array, opt, nameref, any_failed;
int global_unset_func, global_unset_var;
char *name;
char *name, *tname;
unset_function = unset_variable = unset_array = nameref = any_failed = 0;
global_unset_func = global_unset_var = 0;
@@ -859,7 +859,7 @@ unset_builtin (list)
#if defined (ARRAY_VARS)
unset_array = 0;
if (!unset_function && valid_array_reference (name, 0))
if (!unset_function && nameref == 0 && valid_array_reference (name, 0))
{
t = strchr (name, '[');
*t++ = '\0';
@@ -897,7 +897,7 @@ unset_builtin (list)
find a function after unsuccessfully searching for a variable,
note that we're acting on a function now as if -f were
supplied. The readonly check below takes care of it. */
if (var == 0 && unset_variable == 0 && unset_function == 0)
if (var == 0 && nameref == 0 && unset_variable == 0 && unset_function == 0)
{
if (var = find_function (name))
unset_function = 1;
@@ -932,7 +932,22 @@ unset_builtin (list)
if (var == 0 && nameref == 0 && unset_function == 0)
{
var = find_variable_last_nameref (name, 0);
tem = (var && nameref_p (var)) ? unbind_variable (nameref_cell (var)) : unbind_variable (name);
if (var && nameref_p (var))
{
#if defined (ARRAY_VARS)
if (valid_array_reference (nameref_cell (var), 0))
{
tname = savestring (nameref_cell (var));
if (var = array_variable_part (tname, &t, 0))
tem = unbind_array_element (var, t);
free (tname);
}
else
#endif
tem = unbind_variable (nameref_cell (var));
}
else
tem = unbind_variable (name);
}
else
tem = unset_function ? unbind_func (name) : (nameref ? unbind_nameref (name) : unbind_variable (name));
@@ -941,7 +956,7 @@ unset_builtin (list)
is specified, the name refers to a variable; if a variable by
that name does not exist, a function by that name, if any,
shall be unset.'' */
if (tem == -1 && unset_function == 0 && unset_variable == 0)
if (tem == -1 && nameref == 0 && unset_function == 0 && unset_variable == 0)
tem = unbind_func (name);
name = list->word->word; /* reset above for namerefs */
+4 -1
View File
@@ -244,7 +244,10 @@ parse_command ()
/* Allow the execution of a random command just before the printing
of each primary prompt. If the shell variable PROMPT_COMMAND
is set then the value of it is the command to execute. */
if (interactive && bash_input.type != st_string)
/* The tests are a combination of SHOULD_PROMPT() and prompt_again()
from parse.y, which are the conditions under which the prompt is
actually printed. */
if (interactive && bash_input.type != st_string && parser_expanding_alias() == 0)
{
command_to_execute = get_string_value ("PROMPT_COMMAND");
if (command_to_execute)
+2
View File
@@ -116,6 +116,8 @@ extern int parser_expanding_alias __P((void));
extern void parser_save_alias __P((void));
extern void parser_restore_alias __P((void));
extern void clear_shell_input_line __P((void));
extern char *decode_prompt_string __P((char *));
extern int get_current_prompt_level __P((void));
+33 -6
View File
@@ -228,21 +228,21 @@ legal_identifier (name)
}
/* Return 1 if NAME is a valid value that can be assigned to a nameref
variable. The FOR_ASSIGNMENT flag is currently unused, but it could
variable. FLAGS can be 2, in which case the name is going to be used
to create a variable. Other values are currently unused, but could
be used to allow values to be stored and indirectly referenced, but
not used in assignments. */
int
valid_nameref_value (name, for_assignment)
valid_nameref_value (name, flags)
char *name;
int for_assignment;
int flags;
{
intmax_t r;
if (name == 0 || *name == 0)
return 0;
/* valid identifier */
#if defined (ARRAY_VARS)
if (legal_identifier (name) || valid_array_reference (name, 0))
if (legal_identifier (name) || (flags != 2 && valid_array_reference (name, 0)))
#else
if (legal_identifier (name))
#endif
@@ -251,6 +251,33 @@ valid_nameref_value (name, for_assignment)
return 0;
}
int
check_selfref (name, value, flags)
const char *name;
const char *value;
int flags;
{
char *t;
if (STREQ (name, value))
return 1;
#if defined (ARRAY_VARS)
if (valid_array_reference (value, 0))
{
t = array_variable_name (value, (int *)NULL, (int *)NULL);
if (t && STREQ (name, t))
{
free (t);
return 1;
}
free (t);
}
#endif
return 0; /* not a self reference */
}
/* Make sure that WORD is a valid shell identifier, i.e.
does not contain a dollar sign, nor is quoted in any way. Nor
does it consist of all digits. If CHECK_WORD is non-zero,
+1
View File
@@ -290,6 +290,7 @@ extern int importable_function_name __P((char *, size_t));
extern int exportable_function_name __P((char *));
extern int check_identifier __P((WORD_DESC *, int));
extern int valid_nameref_value __P((char *, int));
extern int check_selfref __P((const char *, const char *, int));
extern int legal_alias_name __P((char *, int));
extern int assignment __P((const char *, int));
-2
View File
@@ -4687,8 +4687,6 @@ set_maxchild (nchild)
{
static int lmaxchild = -1;
itrace("set_maxchild (%d)", nchild);
if (lmaxchild < 0)
lmaxchild = getmaxchild ();
if (lmaxchild < 0)
+8 -2
View File
@@ -1961,6 +1961,13 @@ parser_restore_alias ()
#endif
}
void
clear_shell_input_line ()
{
if (shell_input_line)
shell_input_line[shell_input_line_index = 0] = '\0';
}
/* Return a line of text, taken from wherever yylex () reads input.
If there is no more input, then we return NULL. If REMOVE_QUOTED_NEWLINE
is non-zero, we remove unquoted \<newline> pairs. This is used by
@@ -4696,7 +4703,7 @@ read_token_word (character)
/* Non-zero means to ignore the value of the next character, and just
to add it no matter what. */
int pass_next_character;
int pass_next_character;
/* The current delimiting character. */
int cd;
@@ -4993,7 +5000,6 @@ read_token_word (character)
}
got_character:
if (character == CTLESC || character == CTLNUL)
{
RESIZE_MALLOCED_BUFFER (token, token_index, 2, token_buffer_size,
+546 -710
View File
File diff suppressed because it is too large Load Diff
+21 -2
View File
@@ -1381,10 +1381,29 @@ redir_varvalue (redir)
/* XXX - handle set -u here? */
#if defined (ARRAY_VARS)
if (vr = valid_array_reference (w, 0))
v = array_variable_part (w, &sub, &len);
{
v = array_variable_part (w, &sub, &len);
}
else
#endif
v = find_variable (w);
{
v = find_variable (w);
#if defined (ARRAY_VARS)
if (v == 0)
{
v = find_variable_last_nameref (w, 0);
if (v && nameref_p (v))
{
w = nameref_cell (v);
if (vr = valid_array_reference (w, 0))
v = array_variable_part (w, &sub, &len);
else
v = find_variable (w);
}
}
#endif
}
if (v == 0 || invisible_p (v))
return -1;
+8 -1
View File
@@ -10294,7 +10294,12 @@ make_internal_declare (word, option, cmd)
w = make_word (word);
t = assignment (w->word, 0);
w->word[t] = '\0';
if (w->word[t] == '=')
{
w->word[t] = '\0';
if (w->word[t - 1] == '+') /* cut off any append op */
w->word[t - 1] = '\0';
}
wl = make_word_list (w, (WORD_LIST *)NULL);
wl = make_word_list (make_word (option), wl);
@@ -10419,6 +10424,8 @@ shell_expand_word_list (tlist, eflags)
/* Now transform the word as ksh93 appears to do and go on */
t = assignment (tlist->word->word, 0);
tlist->word->word[t] = '\0';
if (tlist->word->word[t - 1] == '+')
tlist->word->word[t - 1] = '\0'; /* cut off append op */
tlist->word->flags &= ~(W_ASSIGNMENT|W_NOSPLIT|W_COMPASSIGN|W_ASSIGNARG|W_ASSIGNASSOC|W_ASSIGNARRAY);
}
#endif
+7 -4
View File
@@ -291,6 +291,7 @@ declare -n ref="var"
./nameref14.sub: line 32: typeset: var: not found
declare -n ref="var"
./nameref15.sub: line 1: local: warning: a: circular name reference
./nameref15.sub: line 1: warning: a: circular name reference
./nameref15.sub: line 1: `a[0]': not a valid identifier
declare -a a=([0]="0")
./nameref15.sub: line 1: local: warning: a: circular name reference
@@ -299,6 +300,7 @@ declare -a a=([0]="0")
declare -a a=([0]="X")
declare -a b=([0]="X")
./nameref15.sub: line 1: local: warning: a: circular name reference
./nameref15.sub: line 1: warning: a: circular name reference
./nameref15.sub: line 1: `a[0]': not a valid identifier
declare -a b=([0]="0")
./nameref15.sub: line 19: typeset: warning: ref: circular name reference
@@ -309,14 +311,15 @@ inside
outside X
./nameref15.sub: line 29: typeset: ref: nameref variable self references not allowed
./nameref15.sub: line 31: ref: nameref variable self references not allowed
./nameref15.sub: line 32: typeset: ref: not found
declare -- ref="4"
declare -n ref="re"
declare -n ref="re"
declare -- re="4"
4
declare -n foo="var[@]"
declare -n ref="var[@]"
./nameref15.sub: line 47: var[@]: bad array subscript
./nameref15.sub: line 48: var[@]: bad array subscript
declare -n bar="var[@]"
./nameref15.sub: line 52: var[@]: bad array subscript
./nameref15.sub: line 53: var[@]: bad array subscript
declare -n r1="y"
declare -n r2="x"
./nameref16.sub: line 12: typeset: x: not found
+2 -1
View File
@@ -31,10 +31,11 @@ typeset -n ref=ref
typeset -n ref=re ref+=f
typeset -p ref
ref=4
typeset -p ref
typeset -p ref re
export ref
printenv ref
printenv re
unset ref ; unset -n ref
unset foo; unset -n foo
+1 -10
View File
@@ -2719,15 +2719,6 @@ bind_variable_internal (name, value, table, hflags, aflags)
else if (entry && nameref_p (entry))
{
newval = nameref_cell (entry);
#if 0
/* This check can go away if we stop allowing all-digit values for
nameref variables. */
if (newval && *newval && valid_nameref_value (newval, 1) == 0)
{
sh_invalidid (newval);
return ((SHELL_VAR *)NULL);
}
#endif
#if defined (ARRAY_VARS)
/* declare -n foo=x[2] */
if (valid_array_reference (newval, 0))
@@ -2949,7 +2940,7 @@ bind_variable_value (var, value, aflags)
else
{
t = make_variable_value (var, value, aflags);
if (STREQ (name_cell (var), t))
if ((aflags & (ASS_NAMEREF|ASS_FORCE)) == ASS_NAMEREF && check_selfref (name_cell (var), t, 0))
{
if (variable_context)
internal_warning (_("%s: circular name reference"), name_cell (var));