diff options
| author | Chet Ramey <chet.ramey@case.edu> | 2016-05-09 16:20:21 -0400 |
|---|---|---|
| committer | Chet Ramey <chet.ramey@case.edu> | 2016-05-09 16:20:21 -0400 |
| commit | 814e1ff513ceca5d535b92f6c8dd9af7554fe83e (patch) | |
| tree | c1ff6f6d11013802b4607c541f916da327f3a9c9 | |
| parent | f30e22304101dace5b225f728033af04f39cb39d (diff) | |
| download | bash-814e1ff513ceca5d535b92f6c8dd9af7554fe83e.tar.gz | |
commit bash-20160506 snapshot
| -rw-r--r-- | CWRU/CWRU.chlog | 143 | ||||
| -rw-r--r-- | MANIFEST | 3 | ||||
| -rw-r--r-- | arrayfunc.c | 16 | ||||
| -rw-r--r-- | builtins/declare.def | 48 | ||||
| -rw-r--r-- | builtins/mapfile.def | 2 | ||||
| -rw-r--r-- | builtins/set.def | 18 | ||||
| -rw-r--r-- | builtins/shopt.def | 64 | ||||
| -rw-r--r-- | execute_cmd.c | 51 | ||||
| -rw-r--r-- | flags.c | 16 | ||||
| -rw-r--r-- | general.c | 6 | ||||
| -rw-r--r-- | lib/readline/histexpand.c | 2 | ||||
| -rw-r--r-- | parse.y | 2 | ||||
| -rw-r--r-- | pcomplete.c | 2 | ||||
| -rw-r--r-- | shell.c | 10 | ||||
| -rw-r--r-- | subst.c | 20 | ||||
| -rwxr-xr-x | tests/RUN-ONE-TEST | 2 | ||||
| -rw-r--r-- | tests/nameref.right | 65 | ||||
| -rw-r--r-- | tests/nameref.tests | 3 | ||||
| -rw-r--r-- | tests/nameref11.sub | 21 | ||||
| -rw-r--r-- | tests/nameref12.sub | 65 | ||||
| -rw-r--r-- | tests/nameref13.sub | 102 | ||||
| -rw-r--r-- | variables.c | 73 | ||||
| -rw-r--r-- | variables.h | 6 |
23 files changed, 663 insertions, 77 deletions
diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index b33d763..3163415 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -10798,3 +10798,146 @@ variables.c variable, throw an error if valid_nameref_value fails (with a second argument of 1). More fixes for bug reported by Grisha Levit <grishalevit@gmail.com> + + 5/2 + --- +builtins/declare.def + - declare_internal: don't allow nameref attribute to be applied to an + existing readonly variable; it can be used to circumvent readonly + value. Fix for bug reported by Grisha Levit <grishalevit@gmail.com> + +variables.[ch] + - find_variable_last_nameref, find_global_variable_last_nameref: takes a + new flags argument. If flags is non-zero, and we find a nameref + variable that is unset (has no value), return that variable instead + of NULL. + +{variables,execute_cmd,arrayfunc,subst}.c,builtins/{declare,set}.def + - find_variable_last_nameref, find_global_variable_last_nameref: change + callers to add flags argument (initially 0) + + 5/3 + --- +variables.c + - bind_variable_internal: make sure we run the value of a namref variable + through valid_nameref_value before doing the assignment. This can go + away if we stop allowing namerefs to refer to positional parameters + +execute_cmd.c + - execute_select_command: if bind_variable returns NULL, handle it as an + error, as if attempting assignment to a readonly variable + - execute_for_command: use 1 as second argument to + find_variable_last_nameref, so it will return an invisible nameref + to assign for each variable in the list + - execute_for_command: if the current word in the list is an invalid + identifier and the loop variable is a nameref, handle it as an error, + as if attempting assignment to a readonly variable + + 5/4 + --- +variables.c + - bind_int_variable: add warning if assigning an int to a nameref + variable + - assign_in_env: if assigning a variable in the temporary environment + that is a namref, throw an error if trying to assign an invalid + value + - bind_variable_value: use valid_nameref_value instead of calls to + legal_identifier and valid_array_reference + +execute_cmd.c + - coproc_setvars: if we have a nameref variable as the coproc name, but + it can't be assigned to for some reason, remove the nameref attribute + and issue a warning that we are doing so + - coproc_setvars: don't allow assignment to a nameref variable with an + invalid variable name, using same code as find_or_make_array_variable + +general.c + - valid_nameref_value: disallow values consisting solely of digits, + like the positional parameters + +builtins/declare.def + - declare_internal: don't call valid_nameref_value on the existing value + of a variable that's being converted to a nameref -- that value is + going to be thrown away and we've already checked the new value + - declare_internal: call bind_variable_value with the ASS_NAMEREF flag + if we're assigning to an existing nameref variable (for instance, + `declare -n x ; declare x=42') + + 5/5 + --- +variables.c + - make_local_variable: if we are being asked to create a local copy of + a nameref variable from a prior scope (checked by looking up + using find_variable_noref), use the nameref variable, not the variable + it references (which we find using find_variable). Bug report from + Grisha Levit <grishalevit@gmail.com> ; fix by Piotr Grzybowski + <narsil.pl@gmail.com> + +builtins/declare.def + - declare_internal: if asked to do the same thing as above (difference + is declare -n r=foo in previous case; declare -n r in this one), + don't follow reference var from a previous context. Create a new + local variable (using make_local_variable) and inherit attributes + from previous scope's nameref as above + + 5/6 + --- +builtins/declare.def + - declare_internal: if we are assigning a value to an existing + invisible nameref variable, validate value early so we don't end up + removing the variable after the assignment fails + +builtins/shopt.def + - toggle_shopts: don't call set_bashopts here unless $BASHOPTS exists, + since we don't want to set it up before it gets read from the + environment. Keeping BASHOPTS read-only should keep users from + unsetting it. Fix from Grisha Levit <grishalevit@gmail.com> + - shopt_set_debug_mode: make sure error_trace_mode reflects the setting + of extdebug. This one is tentative. Fix from Grisha Levit + <grishalevit@gmail.com> + - shopt_set_debug_mode: call set_shellopts after setting error_trace_mode + or function_trace_mode. Fix from Grisha Levit <grishalevit@gmail.com> + +shell.c + - start_debugger: make sure that function_trace_mode and error_trace_mode + reflect the value of debugging_mode, so they are both disabled if we + disable debugging mode because we can't find the debugger start file. + Fix from Grisha Levit <grishalevit@gmail.com> + - start_debugger: set $SHELLOPTS and $BASHOPTS to the option values are + reflected if we change or set them here. Fix from Grisha Levit + <grishalevit@gmail.com> + +builtins/set.def + - reset_shell_options: add reset values for: posix, nolog, pipefail. + Fix from Grisha Levit <grishalevit@gmail.com> + +builtins/shopt.def + - reset_shopt_options: add reset values for: autocd, checkjobs, + complete_fullquote, dirspell, failglob, globstar, gnu_errfmt, + huponexit, inherit_errexit, interactive_comments, lastpipe, + no_empty_cmd_completion, progcomp. Fix from Grisha Levit + <grishalevit@gmail.com> + - reset_shopt_options: make sure the following options have the right + defaults based on #defines: checkjobs, checkwinsize, direxpand, + extglob, globasciiranges. Fix from Grisha Levit + <grishalevit@gmail.com> + +flags.c + - reset_shell_flags: add missing flags, re-initialize history_expansion + based on STRICT_POSIX + + 5/8 + --- +lib/readline/histexpand.c + - history_expand: if any expansion returns 1 from history_expand_internal, + indicating that :p was supplied, make it apply to the entire line + like tcsh and csh. Fixes bug reported by Dean Stanton + <dstanton@tintri.com> + +variables.[ch] + - ifsname: move define to variables.h + +execute_cmd.c + - execute_for_command: check whether or not the word in the for command + is IFS; call setifs every time the variable is assigned a value. + Fixes bug report from Grisha Levit <grishalevit@gmail.com> @@ -1080,6 +1080,9 @@ tests/nameref7.sub f tests/nameref8.sub f tests/nameref9.sub f tests/nameref10.sub f +tests/nameref11.sub f +tests/nameref12.sub f +tests/nameref13.sub f tests/nameref.right f tests/new-exp.tests f tests/new-exp1.sub f diff --git a/arrayfunc.c b/arrayfunc.c index 4a9fd1d..e1de5fb 100644 --- a/arrayfunc.c +++ b/arrayfunc.c @@ -347,9 +347,21 @@ find_or_make_array_variable (name, flags) { /* See if we have a nameref pointing to a variable that hasn't been created yet. */ - var = find_variable_last_nameref (name); + var = find_variable_last_nameref (name, 1); + if (var && nameref_p (var) && invisible_p (var)) + { + internal_warning (_("%s: removing nameref attribute"), name); + VUNSETATTR (var, att_nameref); + } if (var && nameref_p (var)) - var = (flags & 2) ? make_new_assoc_variable (nameref_cell (var)) : make_new_array_variable (nameref_cell (var)); + { + if (valid_nameref_value (nameref_cell (var), 1) == 0) + { + sh_invalidid (nameref_cell (var)); + return ((SHELL_VAR *)NULL); + } + var = (flags & 2) ? make_new_assoc_variable (nameref_cell (var)) : make_new_array_variable (nameref_cell (var)); + } } if (var == 0) diff --git a/builtins/declare.def b/builtins/declare.def index d8339b1..b9c0132 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -1,7 +1,7 @@ This file is declare.def, from which is created declare.c. It implements the builtins "declare" and "local" in Bash. -Copyright (C) 1987-2015 Free Software Foundation, Inc. +Copyright (C) 1987-2016 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -404,8 +404,24 @@ declare_internal (list, local_var) #endif if (offset == 0 && (flags_on & att_nameref)) { - refvar = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name); - var = 0; + /* First look for refvar at current scope */ + refvar = find_variable_last_nameref (name, 1); + var = find_variable (name); + /* VARIABLE_CONTEXT != 0, so we are attempting to create or modify + the attributes for a local variable at the same scope. If we've + used a reference from a previous context to resolve VAR, we + want to throw REFVAR and VAR away and create a new local var. */ + if (refvar && refvar->context != variable_context) + { + refvar = 0; + var = make_local_variable (name); + } + else if (refvar && refvar->context == variable_context) + var = refvar; + /* Maybe we just want to create a new local variable */ + else if (var == 0 || var->context != variable_context) + var = make_local_variable (name); + /* otherwise we have a var at the right context */ } else var = make_local_variable (name); /* sets att_invisible for new vars */ @@ -488,7 +504,7 @@ declare_internal (list, local_var) if (var == 0 && (flags_on & att_nameref)) { /* See if we are trying to modify an existing nameref variable */ - var = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name); + var = mkglobal ? find_global_variable_last_nameref (name, 1) : find_variable_last_nameref (name, 1); if (var && nameref_p (var) == 0) var = 0; } @@ -500,7 +516,7 @@ declare_internal (list, local_var) else if (var == 0 && (flags_off & att_nameref)) { /* See if we are trying to modify an existing nameref variable */ - refvar = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name); + refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0); if (refvar && nameref_p (refvar) == 0) refvar = 0; if (refvar) @@ -516,7 +532,7 @@ declare_internal (list, local_var) declare -p foo */ if (var == 0 && (flags_on || flags_off || offset)) { - refvar = mkglobal ? find_global_variable_last_nameref (name) : find_variable_last_nameref (name); + refvar = mkglobal ? find_global_variable_last_nameref (name, 0) : find_variable_last_nameref (name, 0); if (refvar && nameref_p (refvar) == 0) refvar = 0; if (refvar) @@ -574,16 +590,30 @@ declare_internal (list, local_var) assign_error++; NEXT_VARIABLE (); } + else if (nameref_p (var) && (flags_on & att_nameref) == 0 && (flags_off & att_nameref) == 0 && offset && valid_nameref_value (value, 1) == 0) + { + builtin_error (_("%s: invalid variable name for name reference"), value); + any_failed++; + NEXT_VARIABLE (); + } else if (flags_on & att_nameref) { #if 1 - if (nameref_p (var) == 0 && var_isset (var) && var_isnull (var) == 0 && valid_nameref_value (value_cell (var), 0) == 0) + /* Check of offset is to allow an assignment to a nameref var as + part of the declare word to override existing value */ + if (nameref_p (var) == 0 && var_isset (var) && var_isnull (var) == 0 && offset == 0 && valid_nameref_value (value_cell (var), 0) == 0) { builtin_error (_("%s: invalid variable name for name reference"), value_cell (var)); any_failed++; NEXT_VARIABLE (); } #endif + if (readonly_p (var)) + { + sh_readonly (name); + any_failed++; + NEXT_VARIABLE (); + } /* ksh93 compat: turning on nameref attribute turns off -ilu */ VUNSETATTR (var, att_integer|att_uppercase|att_lowercase|att_capcase); } @@ -722,10 +752,10 @@ declare_internal (list, local_var) bind_variable() */ if (offset) { - if (onref) + if (onref || nameref_p (var)) aflags |= ASS_NAMEREF; v = bind_variable_value (var, value, aflags); - if (v == 0 && onref) + if (v == 0 && (onref || nameref_p (var))) { sh_invalidid (value); assign_error++; diff --git a/builtins/mapfile.def b/builtins/mapfile.def index 2b0db18..0d64f61 100644 --- a/builtins/mapfile.def +++ b/builtins/mapfile.def @@ -2,7 +2,7 @@ This file is mapfile.def, from which is created mapfile.c. It implements the builtin "mapfile" in Bash. Copyright (C) 2005-2006 Rocky Bernstein for Free Software Foundation, Inc. -Copyright (C) 2008-2015 Free Software Foundation, Inc. +Copyright (C) 2008-2016 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. diff --git a/builtins/set.def b/builtins/set.def index 829c659..1d9394c 100644 --- a/builtins/set.def +++ b/builtins/set.def @@ -183,7 +183,9 @@ static int previous_option_value; /* A struct used to match long options for set -o to the corresponding option letter or internal variable. The functions can be called to - dynamically generate values. */ + dynamically generate values. If you add a new variable name here + that doesn't have a corresponding single-character option letter, make + sure to set the value appropriately in reset_shell_options. */ const struct { char *name; int letter; @@ -623,10 +625,18 @@ initialize_shell_options (no_shellopts) void reset_shell_options () { + pipefail_opt = 0; + ignoreeof = 0; + +#if defined (STRICT_POSIX) + posixly_correct = 1; +#else + posixly_correct = 0; +#endif #if defined (HISTORY) + dont_save_function_defs = 0; remember_on_history = enable_history_list = 1; #endif - ignoreeof = 0; } /* Set some flags from the word values in the input list. If LIST is empty, @@ -870,7 +880,7 @@ unset_builtin (list) /* Only search for functions here if -f supplied. */ var = unset_function ? find_function (name) - : (nameref ? find_variable_last_nameref (name) : find_variable (name)); + : (nameref ? find_variable_last_nameref (name, 0) : find_variable (name)); /* Some variables (but not functions yet) cannot be unset, period. */ if (var && unset_function == 0 && non_unsettable_p (var)) @@ -921,7 +931,7 @@ unset_builtin (list) variable, make sure we still try to unset the nameref's value */ if (var == 0 && nameref == 0 && unset_function == 0) { - var = find_variable_last_nameref (name); + var = find_variable_last_nameref (name, 0); tem = (var && nameref_p (var)) ? unbind_variable (nameref_cell (var)) : unbind_variable (name); } else diff --git a/builtins/shopt.def b/builtins/shopt.def index c4a75ea..2febb7e 100644 --- a/builtins/shopt.def +++ b/builtins/shopt.def @@ -1,7 +1,7 @@ This file is shopt.def, from which is created shopt.c. It implements the Bash `shopt' builtin. -Copyright (C) 1994-2015 Free Software Foundation, Inc. +Copyright (C) 1994-2016 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -144,6 +144,9 @@ static int shopt_compat43; typedef int shopt_set_func_t __P((char *, int)); +/* If you add a new variable name here, make sure to set the default value + appropriately in reset_shopt_options. */ + static struct { char *name; int *value; @@ -304,33 +307,68 @@ shopt_builtin (list) } /* Reset the options managed by `shopt' to the values they would have at - shell startup. */ + shell startup. Variables from shopt_vars. */ void reset_shopt_options () { + autocd = cdable_vars = cdspelling = 0; + check_hashed_filenames = CHECKHASH_DEFAULT; + check_window_size = CHECKWINSIZE_DEFAULT; allow_null_glob_expansion = glob_dot_filenames = 0; - cdable_vars = mail_warning = 0; - no_exit_on_failed_exec = print_shift_error = 0; - check_hashed_filenames = cdspelling = expand_aliases = 0; - + no_exit_on_failed_exec = 0; + expand_aliases = 0; + extended_quote = 1; + fail_glob_expansion = 0; + glob_asciirange = GLOBASCII_DEFAULT; + glob_star = 0; + gnu_error_format = 0; + hup_on_exit = 0; + inherit_errexit = 0; + interactive_comments = 1; + lastpipe_opt = 0; + mail_warning = 0; + glob_ignore_case = match_ignore_case = 0; + print_shift_error = 0; source_uses_path = promptvars = 1; - check_window_size = CHECKWINSIZE_DEFAULT; +#if defined (JOB_CONTROL) + check_jobs_at_exit = 0; +#endif #if defined (EXTENDED_GLOB) - extended_glob = 0; + extended_glob = EXTGLOB_DEFAULT; #endif #if defined (HISTORY) - literal_history = force_append_history = 0; + literal_history = 0; + force_append_history = 0; command_oriented_history = 1; #endif #if defined (READLINE) + complete_fullquote = 1; + force_fignore = 1; hist_verify = history_reediting = 0; perform_hostname_completion = 1; +# if DIRCOMPLETE_EXPAND_DEFAULT + dircomplete_expand = 1; +# else + dircomplete_expand = 0; +#endif + dircomplete_spelling = 0; + no_empty_command_completion = 0; #endif +#if defined (PROGRAMMABLE_COMPLETION) + prog_completion_enabled = 1; +#endif + +#if defined (DEFAULT_ECHO_TO_XPG) || defined (STRICT_POSIX) + xpg_echo = 1; +#else + xpg_echo = 0; +#endif /* DEFAULT_ECHO_TO_XPG */ + shopt_login_shell = login_shell; } @@ -361,6 +399,7 @@ toggle_shopts (mode, list, quiet) { WORD_LIST *l; int ind, rval; + SHELL_VAR *v; for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next) { @@ -378,7 +417,9 @@ toggle_shopts (mode, list, quiet) } } - set_bashopts (); + /* Don't set $BASHOPTS here if it hasn't already been initialized */ + if (v = find_variable ("BASHOPTS")) + set_bashopts (); return (rval); } @@ -529,7 +570,8 @@ shopt_set_debug_mode (option_name, mode) int mode; { #if defined (DEBUGGER) - function_trace_mode = debugging_mode; + error_trace_mode = function_trace_mode = debugging_mode; + set_shellopts (); #endif return (0); } diff --git a/execute_cmd.c b/execute_cmd.c index 05f3d03..c70717e 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -2172,13 +2172,31 @@ coproc_setvars (cp) #if defined (ARRAY_VARS) v = find_variable (cp->c_name); + /* This is the same code as in find_or_make_array_variable */ + if (v == 0) + { + v = find_variable_last_nameref (cp->c_name, 1); + if (v && nameref_p (v) && invisible_p (v)) + { + internal_warning (_("coproc: %s: removing nameref attribute"), cp->c_name); + VUNSETATTR (v, att_nameref); + } + if (v && nameref_p (v)) + { + if (valid_nameref_value (cp->c_name, 1) == 0) + { + sh_invalidid (cp->c_name); + return; + } + } + } + if (v && (readonly_p (v) || noassign_p (v))) { if (readonly_p (v)) err_readonly (cp->c_name); return; } - if (v == 0) v = make_new_array_variable (cp->c_name); if (array_p (v) == 0) @@ -2255,7 +2273,7 @@ execute_coproc (command, pipe_in, pipe_out, fds_to_close) /* XXX -- can be removed after changes to handle multiple coprocs */ #if !MULTIPLE_COPROCS if (sh_coproc.c_pid != NO_PID) - internal_warning ("execute_coproc: coproc [%d:%s] still exists", sh_coproc.c_pid, sh_coproc.c_name); + internal_warning (_("execute_coproc: coproc [%d:%s] still exists"), sh_coproc.c_pid, sh_coproc.c_name); coproc_init (&sh_coproc); #endif @@ -2750,17 +2768,24 @@ execute_for_command (for_command) this_command_name = (char *)NULL; /* XXX - special ksh93 for command index variable handling */ - v = find_variable_last_nameref (identifier); + v = find_variable_last_nameref (identifier, 1); if (v && nameref_p (v)) - { - v = bind_variable_value (v, list->word->word, 0); - } + { + if (valid_nameref_value (list->word->word, 1) == 0) + { + sh_invalidid (list->word->word); + v = 0; + } + else + v = bind_variable_value (v, list->word->word, 0); + } else - v = bind_variable (identifier, list->word->word, 0); - if (readonly_p (v) || noassign_p (v)) + v = bind_variable (identifier, list->word->word, 0); + + if (v == 0 || readonly_p (v) || noassign_p (v)) { line_number = save_line_number; - if (readonly_p (v) && interactive_shell == 0 && posixly_correct) + if (v && readonly_p (v) && interactive_shell == 0 && posixly_correct) { last_command_exit_value = EXECUTION_FAILURE; jump_to_top_level (FORCE_EOF); @@ -2773,6 +2798,10 @@ execute_for_command (for_command) return (EXECUTION_FAILURE); } } + + if (ifsname (identifier)) + setifs (v); + retval = execute_command (for_command->action); REAP (); QUIT; @@ -3250,9 +3279,9 @@ execute_select_command (select_command) } v = bind_variable (identifier, selection, 0); - if (readonly_p (v) || noassign_p (v)) + if (v == 0 || readonly_p (v) || noassign_p (v)) { - if (readonly_p (v) && interactive_shell == 0 && posixly_correct) + if (v && readonly_p (v) && interactive_shell == 0 && posixly_correct) { last_command_exit_value = EXECUTION_FAILURE; jump_to_top_level (FORCE_EOF); @@ -356,11 +356,17 @@ set_current_flags (bitmap) void reset_shell_flags () { - mark_modified_vars = exit_immediately_on_error = disallow_filename_globbing = 0; + mark_modified_vars = disallow_filename_globbing = 0; place_keywords_in_env = read_but_dont_execute = just_one_command = 0; - noclobber = unbound_vars_is_error = echo_input_at_read = verbose_flag = 0; + noclobber = unbound_vars_is_error = 0; echo_command_at_execute = jobs_m_flag = forced_interactive = 0; - no_symbolic_links = no_invisible_vars = privileged_mode = pipefail_opt = 0; + no_symbolic_links = no_invisible_vars = 0; + privileged_mode = pipefail_opt = 0; + + error_trace_mode = function_trace_mode = 0; + + exit_immediately_on_error = errexit_flag = 0; + echo_input_at_read = verbose_flag = 0; hashing_enabled = interactive_comments = 1; @@ -369,7 +375,11 @@ reset_shell_flags () #endif #if defined (BANG_HISTORY) +# if defined (STRICT_POSIX) + history_expansion = 0; +# else history_expansion = 1; +# endif /* STRICT_POSIX */ #endif #if defined (BRACE_EXPANSION) @@ -227,6 +227,10 @@ legal_identifier (name) return (1); } +/* 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 + be used to allow values to be stored and indirectly referenced, but + not used in assignments. */ int valid_nameref_value (name, for_assignment) char *name; @@ -240,8 +244,10 @@ valid_nameref_value (name, for_assignment) if (legal_identifier (name)) #endif return 1; +#if 0 if (for_assignment == 0 && legal_number (name, &r)) return 1; +#endif return 0; } diff --git a/lib/readline/histexpand.c b/lib/readline/histexpand.c index 457cdb4..46a99aa 100644 --- a/lib/readline/histexpand.c +++ b/lib/readline/histexpand.c @@ -1220,7 +1220,7 @@ history_expand (hstring, output) ADD_STRING (temp); xfree (temp); } - only_printing = r == 1; + only_printing += r == 1; i = eindex; } break; @@ -2314,7 +2314,7 @@ shell_getc (remove_quoted_newline) if (n <= 2) /* we have to save 1 for the newline added below */ { if (truncating == 0) - internal_warning("shell_getc: shell_input_line_size (%zu) exceeds SIZE_MAX (%lu): line truncated", shell_input_line_size, (unsigned long)SIZE_MAX); + internal_warning(_("shell_getc: shell_input_line_size (%zu) exceeds SIZE_MAX (%lu): line truncated"), shell_input_line_size, (unsigned long)SIZE_MAX); shell_input_line[i] = '\0'; truncating = 1; } diff --git a/pcomplete.c b/pcomplete.c index 74fcc8d..ba5e9ff 100644 --- a/pcomplete.c +++ b/pcomplete.c @@ -1643,7 +1643,7 @@ programmable_completions (cmd, word, start, end, foundp) if (count > 32) { - internal_warning ("programmable_completion: %s: possible retry loop", cmd); + internal_warning (_("programmable_completion: %s: possible retry loop"), cmd); break; } } @@ -1455,11 +1455,13 @@ start_debugger () r = force_execute_file (DEBUGGER_START_FILE, 1); if (r < 0) { - internal_warning ("cannot start debugger; debugging mode disabled"); - debugging_mode = function_trace_mode = 0; + internal_warning (_("cannot start debugger; debugging mode disabled")); + debugging_mode = 0; } - else - function_trace_mode = 1; + error_trace_mode = function_trace_mode = debugging_mode; + + set_shellopts (); + set_bashopts (); exit_immediately_on_error += old_errexit; #endif @@ -5645,7 +5645,7 @@ process_substitute (string, open_for_read_in_child) #else /* HAVE_DEV_FD */ if (pipe (fildes) < 0) { - sys_error (_("cannot make pipe for process substitution")); + sys_error ("%s", _("cannot make pipe for process substitution")); return ((char *)NULL); } /* If OPEN_FOR_READ_IN_CHILD == 1, we want to use the write end of @@ -5661,7 +5661,7 @@ process_substitute (string, open_for_read_in_child) if (pathname == 0) { - sys_error (_("cannot make pipe for process substitution")); + sys_error ("%s", _("cannot make pipe for process substitution")); return ((char *)NULL); } @@ -5703,7 +5703,7 @@ process_substitute (string, open_for_read_in_child) if (pid < 0) { - sys_error (_("cannot make child for process substitution")); + sys_error ("%s", _("cannot make child for process substitution")); free (pathname); #if defined (HAVE_DEV_FD) close (parent_pipe_fd); @@ -5864,7 +5864,7 @@ read_comsub (fd, quoted, rflag) if (c == 0) { #if 1 - internal_warning ("command substitution: ignored null byte in input"); + internal_warning ("%s", _("command substitution: ignored null byte in input")); #endif continue; } @@ -5988,7 +5988,7 @@ command_substitute (string, quoted) /* Pipe the output of executing STRING into the current shell. */ if (pipe (fildes) < 0) { - sys_error (_("cannot make pipe for command substitution")); + sys_error ("%s", _("cannot make pipe for command substitution")); goto error_exit; } @@ -6050,7 +6050,7 @@ command_substitute (string, quoted) if (dup2 (fildes[1], 1) < 0) { - sys_error (_("command_substitute: cannot duplicate pipe as fd 1")); + sys_error ("%s", _("command_substitute: cannot duplicate pipe as fd 1")); exit (EXECUTION_FAILURE); } @@ -6463,7 +6463,7 @@ expand_arrayref: else temp = (char *)NULL; } - else if (var = find_variable_last_nameref (name)) + else if (var = find_variable_last_nameref (name, 0)) { temp = nameref_cell (var); #if defined (ARRAY_VARS) @@ -6506,7 +6506,7 @@ parameter_brace_find_indir (name, var_is_special, quoted, find_nameref) WORD_DESC *w; SHELL_VAR *v; - if (find_nameref && var_is_special == 0 && (v = find_variable_last_nameref (name)) && + if (find_nameref && var_is_special == 0 && (v = find_variable_last_nameref (name, 0)) && nameref_p (v) && (t = nameref_cell (v)) && *t) return (savestring (t)); @@ -6546,7 +6546,7 @@ parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, c bash performs an indirect lookup on foo[0] and expands the result; ksh93 expands bar[0]. We could do that here -- there are enough usable primitives to do that -- but do not at this point. */ - if (var_is_special == 0 && (v = find_variable_last_nameref (name))) + if (var_is_special == 0 && (v = find_variable_last_nameref (name, 0))) { if (nameref_p (v) && (t = nameref_cell (v)) && *t) { @@ -8798,7 +8798,7 @@ comsub: } else if (var && (invisible_p (var) || var_isset (var) == 0)) temp = (char *)NULL; - else if ((var = find_variable_last_nameref (temp1)) && var_isset (var) && invisible_p (var) == 0) + else if ((var = find_variable_last_nameref (temp1, 0)) && var_isset (var) && invisible_p (var) == 0) { temp = nameref_cell (var); #if defined (ARRAY_VARS) diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index a5ab273..d29259a 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -1,4 +1,4 @@ -BUILD_DIR=/usr/local/build/bash/bash-current +BUILD_DIR=/usr/local/build/chet/bash/bash-current THIS_SH=$BUILD_DIR/bash PATH=$PATH:$BUILD_DIR diff --git a/tests/nameref.right b/tests/nameref.right index 596c548..3c6255d 100644 --- a/tests/nameref.right +++ b/tests/nameref.right @@ -166,3 +166,68 @@ declare -i bar="8" 8 declare -n foo="bar" ./nameref10.sub: line 64: typeset: bar: not found +./nameref11.sub: line 1: declare: /: invalid variable name for name reference +./nameref11.sub: line 2: declare: /: invalid variable name for name reference +./nameref11.sub: line 3: `/': not a valid identifier +./nameref11.sub: line 4: declare: `/': not a valid identifier +./nameref11.sub: line 5: `/': not a valid identifier +1) / +#? ./nameref11.sub: line 6: `/': not a valid identifier +x + +./nameref11.sub: line 7: ((: `0': not a valid identifier +./nameref11.sub: line 8: declare: 0: invalid variable name for name reference +./nameref11.sub: line 9: declare: /: invalid variable name for name reference +./nameref11.sub: line 10: declare: /: invalid variable name for name reference +./nameref11.sub: line 11: `/': not a valid identifier + +./nameref11.sub: line 12: `/': not a valid identifier +./nameref11.sub: line 13: exec: `10': not a valid identifier +./nameref11.sub: line 13: r: cannot assign fd to variable +./nameref11.sub: line 14: warning: coproc: r: removing nameref attribute +63 +./nameref11.sub: line 15: declare: RO: readonly variable +./nameref11.sub: line 15: RO: readonly variable +./nameref11.sub: line 16: declare: /: invalid variable name for name reference +/ +./nameref11.sub: line 17: declare: /: invalid variable name for name reference +./nameref11.sub: illegal option -- h +./nameref11.sub: line 18: getopts: `?': not a valid identifier +./nameref11.sub: line 19: warning: r: removing nameref attribute +declare -a r=() +./nameref11.sub: line 20: declare: r: reference variable cannot be an array +./nameref11.sub: line 21: printf: `/': not a valid identifier +./nameref12.sub: line 6: declare: /: invalid variable name for name reference +./nameref12.sub: line 9: declare: %: invalid variable name for name reference +./nameref12.sub: line 13: `^': not a valid identifier +declare -n r +declare -a foo +declare -a foo=([0]="7") +./nameref12.sub: line 26: declare: `42': not a valid identifier +./nameref12.sub: line 27: declare: x: not found +declare -nr RO="foo" +./nameref12.sub: line 37: `/': not a valid identifier +0 0 +./nameref12.sub: line 38: `/': not a valid identifier + +./nameref12.sub: line 43: declare: `7*6': not a valid identifier +./nameref12.sub: line 43: declare: foo: not found +./nameref12.sub: line 45: `7*6': not a valid identifier +declare -n ref="var" +declare -n ref="var" +declare -- a +declare -n r="a" +declare -- a +declare -n r="a" +0 +declare -n r="P" +declare -n ref="var" +declare -- a +declare -n r="a" +0 +declare -n r +declare -n r +./nameref13.sub: line 88: typeset: 12345: invalid variable name for name reference +declare -n foo +./nameref13.sub: line 97: typeset: 12345: invalid variable name for name reference +declare -n foo diff --git a/tests/nameref.tests b/tests/nameref.tests index c20100f..548daa8 100644 --- a/tests/nameref.tests +++ b/tests/nameref.tests @@ -125,3 +125,6 @@ ${THIS_SH} ./nameref7.sub ${THIS_SH} ./nameref8.sub ${THIS_SH} ./nameref9.sub ${THIS_SH} ./nameref10.sub +${THIS_SH} ./nameref11.sub +${THIS_SH} ./nameref12.sub +${THIS_SH} ./nameref13.sub diff --git a/tests/nameref11.sub b/tests/nameref11.sub new file mode 100644 index 0000000..a790ce1 --- /dev/null +++ b/tests/nameref11.sub @@ -0,0 +1,21 @@ +r=/; declare -n r ; unset r +declare -n r=/ ; unset -n r +declare -n r; r=/ ; unset -n r +declare -n r; declare r=/ ; unset -n r +declare -n r; for r in /; do :; done ; unset -n r +declare -n r; select r in /; do :; done <<< 1; echo x; echo $r ; unset -n r +declare -n r; ((r=0)) ; unset -n r +((r=0)); declare -n r ; unset -n r +r=/ declare -n r ; unset -n r +f() { declare -n r; }; r=/ f ; unset r +f() { echo $r; }; declare -n r; r=/ f ; unset -n r +declare -n r; : ${r:=/} ; unset -n r +declare -n r; exec {r}>/dev/null ; unset -n r +declare -n r; coproc r { :; }; echo $r ; unset r +declare -r RO=x; r=$RO; declare -n r; x=y; declare -n RO; RO=z; declare -p RO; echo "$RO" +s=/; declare -n r=s; declare -n s; echo $r ; unset -n r ; unset -n s +declare -n r=s; declare -n s; s=/ ; unset -n r; unset -n s +declare -n r; getopts x r -h ; unset r; unset -n r +declare -n r; mapfile r < /dev/null ; declare -p r; unset r ; unset -n r +mapfile r < /dev/null; declare -n r ; unset r ; unset -n r +declare -n r; printf -v r / diff --git a/tests/nameref12.sub b/tests/nameref12.sub new file mode 100644 index 0000000..7a5936c --- /dev/null +++ b/tests/nameref12.sub @@ -0,0 +1,65 @@ +declare -n r +declare -n r +unset -n r + +r=foo +declare -n r=/ + +r=% +declare -n r +unset r + +declare -n r +r=^ +declare -p r + +unset -n r + +declare -n foo +declare -a foo +declare -p foo +foo[0]=7 +declare -p foo +unset foo + +declare -n x +declare x=42 +declare -p x + +declare -n -r RO=foo +declare -p RO + +unset -n r; unset r + +f() { echo $r; } + +declare -n r +r=/ /usr/bin/sum < /dev/null +r=/ f + +unset -f f + +# the details of this may change; this will tell me when they do +declare -n foo ; declare -i foo=7*6 ; declare -p foo +unset -n foo +declare -n foo ; declare -i foo ; foo=7*6 ; declare -p foo + +# used to be buggy +f() +{ + unset var + declare -n ref=var + declare -n ref + declare -p ref +} +f + +unset -f f +f() +{ + local var + declare -n ref=var + declare -n ref + declare -p ref +} +f diff --git a/tests/nameref13.sub b/tests/nameref13.sub new file mode 100644 index 0000000..556fbdb --- /dev/null +++ b/tests/nameref13.sub @@ -0,0 +1,102 @@ +declare -nt r=a + +f() +{ + declare a + declare -n r=a + declare -p a r +} + +f +unset -f f + +f() +{ + declare a + declare -n r + r=a + declare -p a r +} +f +echo $? + +unset -f f + +P=12345 +function foo +{ + typeset -n r + typeset -n r=P + typeset -p r +} + +foo +unset P foo + +ref=outside + +f() +{ + unset var + declare -n ref=var + declare -n ref; + declare -p ref; +} +f + +unset ref foo + +typeset -n r=a + +f() +{ + typeset a + typeset -n r + typeset -n r + r=a + + typeset -p a r +} +f +echo $? +unset -n r +unset -f f + +function foo +{ + typeset -n r + typeset -n r + typeset -p r +} + +foo +unset -f foo + + +function foo +{ + typeset r + typeset -n r + typeset -p r +} +foo +unset -f foo + +foo() +{ + typeset -n foo + typeset foo=12345 + typeset -p foo +} +foo +unset -f foo + +foo() +{ + typeset -n foo + typeset -n foo=12345 + typeset -p foo +} +foo +unset -f foo + diff --git a/variables.c b/variables.c index 839f563..1877b17 100644 --- a/variables.c +++ b/variables.c @@ -1,6 +1,6 @@ /* variables.c -- Functions for hacking shell variables. */ -/* Copyright (C) 1987-2015 Free Software Foundation, Inc. +/* Copyright (C) 1987-2016 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -83,8 +83,6 @@ #define FUNCTIONS_HASH_BUCKETS 512 #define TEMPENV_HASH_BUCKETS 4 /* must be power of two */ -#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0') - #define BASHFUNC_PREFIX "BASH_FUNC_" #define BASHFUNC_PREFLEN 10 /* == strlen(BASHFUNC_PREFIX */ #define BASHFUNC_SUFFIX "%%" @@ -1929,8 +1927,9 @@ find_variable_nameref (v) /* Resolve the chain of nameref variables for NAME. XXX - could change later */ SHELL_VAR * -find_variable_last_nameref (name) +find_variable_last_nameref (name, vflags) const char *name; + int vflags; { SHELL_VAR *v, *nv; char *newname; @@ -1945,7 +1944,11 @@ find_variable_last_nameref (name) return ((SHELL_VAR *)0); /* error message here? */ newname = nameref_cell (v); if (newname == 0 || *newname == '\0') +#if 0 return ((SHELL_VAR *)0); +#else + return ((vflags && invisible_p (v)) ? v : (SHELL_VAR *)0); +#endif nv = v; flags = 0; if (expanding_redir == 0 && (assigning_in_environment || executing_builtin)) @@ -1957,8 +1960,9 @@ find_variable_last_nameref (name) /* Resolve the chain of nameref variables for NAME. XXX - could change later */ SHELL_VAR * -find_global_variable_last_nameref (name) +find_global_variable_last_nameref (name, vflags) const char *name; + int vflags; { SHELL_VAR *v, *nv; char *newname; @@ -1973,7 +1977,11 @@ find_global_variable_last_nameref (name) return ((SHELL_VAR *)0); /* error message here? */ newname = nameref_cell (v); if (newname == 0 || *newname == '\0') +#if 0 return ((SHELL_VAR *)0); +#else + return ((vflags && invisible_p (v)) ? v : (SHELL_VAR *)0); +#endif nv = v; v = find_global_variable_noref (newname); } @@ -2297,16 +2305,29 @@ SHELL_VAR * make_local_variable (name) const char *name; { - SHELL_VAR *new_var, *old_var; + SHELL_VAR *new_var, *old_var, *old_ref; VAR_CONTEXT *vc; int was_tmpvar; char *tmp_value; + /* We don't want to follow the nameref chain when making local variables; we + just want to create them. */ + old_ref = find_variable_noref (name); + if (old_ref && nameref_p (old_ref) == 0) + old_ref = 0; /* local foo; local foo; is a no-op. */ old_var = find_variable (name); - if (old_var && local_p (old_var) && old_var->context == variable_context) + if (old_ref == 0 && old_var && local_p (old_var) && old_var->context == variable_context) return (old_var); + /* local -n foo; local -n foo; is a no-op. */ + if (old_ref && local_p (old_ref) && old_ref->context == variable_context) + return (old_ref); + + /* From here on, we want to use the refvar, not the variable it references */ + if (old_ref) + old_var = old_ref; + was_tmpvar = old_var && tempvar_p (old_var); /* If we're making a local variable in a shell function, the temporary env has already been merged into the function's variable context stack. We @@ -2622,15 +2643,16 @@ bind_variable_internal (name, value, table, hflags, aflags) /* Let's see if we have a nameref referencing a variable that hasn't yet been created. */ if (entry == 0) - entry = find_variable_last_nameref (name); /* XXX */ + entry = find_variable_last_nameref (name, 0); /* XXX */ if (entry == 0) /* just in case */ return (entry); } - /* The first clause handles `declare -n ref; ref=x;' */ + /* The first clause handles `declare -n ref; ref=x;' or `declare -n ref; + declare -n ref' */ if (entry && invisible_p (entry) && nameref_p (entry)) { - if (valid_nameref_value (value, 1) == 0) + if (value && *value && valid_nameref_value (value, 0) == 0) { sh_invalidid (value); return ((SHELL_VAR *)NULL); @@ -2640,6 +2662,15 @@ 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)) @@ -2843,11 +2874,7 @@ bind_variable_value (var, value, aflags) else { t = make_variable_value (var, value, aflags); -#if defined (ARRAY_VARS) - if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || (legal_identifier (t) == 0 && valid_array_reference (t, 0) == 0))) -#else - if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || legal_identifier (t) == 0)) -#endif + if ((aflags & ASS_NAMEREF) && (t == 0 || *t == 0 || valid_nameref_value (t, 0) == 0)) { free (t); if (invis) @@ -2923,6 +2950,9 @@ bind_int_variable (lhs, rhs) VUNSETATTR (v, att_invisible); } + if (v && nameref_p (v)) + internal_warning (_("%s: assigning integer to name reference"), lhs); + return (v); } @@ -3047,6 +3077,9 @@ assign_in_env (word, flags) } var = find_variable (name); + if (var == 0) + var = find_variable_last_nameref (name, 1); + if (var && (readonly_p (var) || noassign_p (var))) { if (readonly_p (var)) @@ -3054,8 +3087,16 @@ assign_in_env (word, flags) free (name); return (0); } - temp = name + offset + 1; + if (var && nameref_p (var) && valid_nameref_value (temp, 0) == 0) + { + /* If we're assigning a value to a nameref variable in the temp + environment that's an invalid name, flag an error. */ + sh_invalidid (temp); + free (name); + return (0); + } + value = expand_assignment_string_to_string (temp, 0); if (var && (aflags & ASS_APPEND)) diff --git a/variables.h b/variables.h index 43cb725..84e49d4 100644 --- a/variables.h +++ b/variables.h @@ -215,6 +215,8 @@ typedef struct _vlist { (var)->exportstr = (char *)NULL; \ } \ } while (0) + +#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0') /* Stuff for hacking variables. */ typedef int sh_var_map_func_t __P((SHELL_VAR *)); @@ -244,8 +246,8 @@ extern SHELL_VAR *find_function __P((const char *)); extern FUNCTION_DEF *find_function_def __P((const char *)); extern SHELL_VAR *find_variable __P((const char *)); extern SHELL_VAR *find_variable_noref __P((const char *)); -extern SHELL_VAR *find_variable_last_nameref __P((const char *)); -extern SHELL_VAR *find_global_variable_last_nameref __P((const char *)); +extern SHELL_VAR *find_variable_last_nameref __P((const char *, int)); +extern SHELL_VAR *find_global_variable_last_nameref __P((const char *, int)); extern SHELL_VAR *find_variable_nameref __P((SHELL_VAR *)); extern SHELL_VAR *find_variable_internal __P((const char *, int)); extern SHELL_VAR *find_variable_tempenv __P((const char *)); |
