diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 4c6c161b..194927b1 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -13947,3 +13947,40 @@ lib/readline/display.c callers who call CHECK_INV_LBREAKS must update wrapped_line[newlines] when in HANDLE_MULTIBYTE mode. Fuzzing bug reported by Eduardo Bustamante + + 5/24 + ---- +lib/readline/search.c + - _rl_nsearch_callback,noninc_search: handle _rl_search_getchar + returning -1 (EOF or read error) by aborting the search. + Fuzzing bug reported by Eduardo Bustamante + + 5/25 + ---- +variables.c + - localvar_inherit: new variable, controlled by shopt localvar_inherit + option + - make_local_variable: if localvar_inherit is set, the new local + variable inherits a previous scope's variable's value, attributes + (except nameref), and dynamic variable information. If a local + variable inherits a value, the local is not invisible + +builtins/shopt.def + - localvar_inherit: new option + +doc/{bash.1,bashref.texi} + - localvar_inherit: document new shopt option + + 5/29 + ---- +lib/readline/readline.c + - _rl_subseq_result: only return -1 and back up the chain if we are + dealing with a result (r) that's already < 0 and we are at the end + of a multi-key sequence. Otherwise, a failing readline command (e.g., + delete-char at the end of a line) could cause this code to be + executed. Report from Nuzhna Pomoshch + +lib/readline/histfile.c + - read_history_range: if the file isn't a regular file, return an + error. Bug report from Eduardo Bustamante , + relaying from IRC diff --git a/builtins/declare.def b/builtins/declare.def index 4a8afbbe..cb944feb 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -311,7 +311,7 @@ declare_internal (list, local_var) if (local_var && variable_context && STREQ (name, "-")) { - var = make_local_variable ("-"); + var = make_local_variable ("-", 0); FREE (value_cell (var)); /* just in case */ value = get_current_options (); var_setvalue (var, value); @@ -433,18 +433,18 @@ restart_new_var_name: if (refvar && refvar->context != variable_context) { refvar = 0; - var = make_local_variable (name); + var = make_local_variable (name, 0); } 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); + var = make_local_variable (name, 0); /* 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 */ + var = make_local_variable (name, 0); /* sets att_invisible for new vars */ if (var == 0) { any_failed++; diff --git a/builtins/shopt.def b/builtins/shopt.def index 1ad2b74d..2106893b 100644 --- a/builtins/shopt.def +++ b/builtins/shopt.def @@ -91,6 +91,7 @@ extern int glob_star; extern int glob_asciirange; extern int lastpipe_opt; extern int inherit_errexit; +extern int localvar_inherit; #if defined (EXTENDED_GLOB) extern int extended_glob; @@ -210,6 +211,7 @@ static struct { #if defined (HISTORY) { "lithist", &literal_history, (shopt_set_func_t *)NULL }, #endif + { "localvar_inherit", &localvar_inherit, (shopt_set_func_t *)NULL }, { "login_shell", &shopt_login_shell, set_login_shell }, { "mailwarn", &mail_warning, (shopt_set_func_t *)NULL }, #if defined (READLINE) diff --git a/doc/bash.1 b/doc/bash.1 index 1546222e..da12a5f0 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -5,12 +5,12 @@ .\" Case Western Reserve University .\" chet.ramey@case.edu .\" -.\" Last Change: Tue Apr 25 09:44:48 EDT 2017 +.\" Last Change: Thu May 25 15:58:43 EDT 2017 .\" .\" bash_builtins, strip all but Built-Ins section .if \n(zZ=1 .ig zZ .if \n(zY=1 .ig zY -.TH BASH 1 "2017 April 25" "GNU Bash 4.4" +.TH BASH 1 "2017 May 25" "GNU Bash 4.4" .\" .\" There's some problem with having a `@' .\" in a tagged paragraph with the BSD man macros. @@ -9974,6 +9974,11 @@ If set, and the option is enabled, multi-line commands are saved to the history with embedded newlines rather than using semicolon separators where possible. .TP 8 +.B localvar_inherit +If set, local variables inherit the value and attributes of a variable of +the same name that exists at a previous scope before any new value is +assigned. The nameref attribute is not inherited. +.TP 8 .B login_shell The shell sets this option if it is started as a login shell (see .SM diff --git a/doc/bashref.texi b/doc/bashref.texi index dcbb2019..10259810 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -5359,6 +5359,11 @@ If enabled, and the @code{cmdhist} option is enabled, multi-line commands are saved to the history with embedded newlines rather than using semicolon separators where possible. +@item localvar_inherit +If set, local variables inherit the value and attributes of a variable of +the same name that exists at a previous scope before any new value is +assigned. The @var{nameref} attribute is not inherited. + @item login_shell The shell sets this option if it is started as a login shell (@pxref{Invoking Bash}). diff --git a/doc/version.texi b/doc/version.texi index e258876f..77dff083 100644 --- a/doc/version.texi +++ b/doc/version.texi @@ -2,10 +2,10 @@ Copyright (C) 1988-2017 Free Software Foundation, Inc. @end ignore -@set LASTCHANGE Tue Apr 25 09:45:02 EDT 2017 +@set LASTCHANGE Thu May 25 16:01:44 EDT 2017 @set EDITION 4.4 @set VERSION 4.4 -@set UPDATED 25 April 2017 -@set UPDATED-MONTH April 2017 +@set UPDATED 25 May 2017 +@set UPDATED-MONTH May 2017 diff --git a/lib/readline/histfile.c b/lib/readline/histfile.c index d68b40e7..399bcc39 100644 --- a/lib/readline/histfile.c +++ b/lib/readline/histfile.c @@ -283,6 +283,16 @@ read_history_range (const char *filename, int from, int to) if ((file < 0) || (fstat (file, &finfo) == -1)) goto error_and_exit; + if (S_ISREG (finfo.st_mode) == 0) + { +#ifdef EFTYPE + errno = EFTYPE; +#else + errno = EINVAL; +#endif + goto error_and_exit; + } + file_size = (size_t)finfo.st_size; /* check for overflow on very large files */ diff --git a/lib/readline/readline.c b/lib/readline/readline.c index e51f0c75..f174d5d3 100644 --- a/lib/readline/readline.c +++ b/lib/readline/readline.c @@ -1067,7 +1067,7 @@ _rl_subseq_result (int r, Keymap map, int key, int got_subseq) _rl_dispatching_keymap = map; return -2; } - else if (r && got_subseq) + else if (r < 0 && got_subseq) /* XXX */ { /* OK, back up the chain. */ if (RL_ISSTATE (RL_STATE_MACROINPUT)) diff --git a/lib/readline/search.c b/lib/readline/search.c index 2cbee629..64925611 100644 --- a/lib/readline/search.c +++ b/lib/readline/search.c @@ -267,6 +267,9 @@ _rl_nsearch_abort (_rl_search_cxt *cxt) static int _rl_nsearch_dispatch (_rl_search_cxt *cxt, int c) { + if (c < 0) + c = CTRL ('C'); + switch (c) { case CTRL('W'): @@ -374,6 +377,12 @@ noninc_search (int dir, int pchar) { c = _rl_search_getchar (cxt); + if (c < 0) + { + _rl_nsearch_abort (cxt); + return 1; + } + if (c == 0) break; @@ -455,6 +464,12 @@ _rl_nsearch_callback (_rl_search_cxt *cxt) int c, r; c = _rl_search_getchar (cxt); + if (c <= 0) + { + if (c < 0) + _rl_nsearch_abort (cxt); + return 1; + } r = _rl_nsearch_dispatch (cxt, c); if (r != 0) return 1; diff --git a/tests/getopts5.sub b/tests/getopts5.sub index 30614ef9..874b2810 100644 --- a/tests/getopts5.sub +++ b/tests/getopts5.sub @@ -2,7 +2,7 @@ getop () { - local OPTIND + local OPTIND=1 local OPTERR=1 echo getop: OPTERR=$OPTERR diff --git a/variables.c b/variables.c index 944de86e..b53e1b3b 100644 --- a/variables.c +++ b/variables.c @@ -120,6 +120,10 @@ HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL; executing functions we are. */ int variable_context = 0; +/* If non-zero, local variables inherit values and attributes from a variable + with the same name at a previous scope. */ +int localvar_inherit = 1; + /* The set of shell assignments which are made only in the environment for a single command. */ HASH_TABLE *temporary_env = (HASH_TABLE *)NULL; @@ -2421,13 +2425,14 @@ set_if_not (name, value) /* Create a local variable referenced by NAME. */ SHELL_VAR * -make_local_variable (name) +make_local_variable (name, flags) const char *name; + int flags; { SHELL_VAR *new_var, *old_var, *old_ref; VAR_CONTEXT *vc; int was_tmpvar; - char *tmp_value; + char *old_value; /* We don't want to follow the nameref chain when making local variables; we just want to create them. */ @@ -2463,8 +2468,10 @@ make_local_variable (name) VUNSETATTR (old_var, att_invisible); /* XXX */ return (old_var); } - if (was_tmpvar) - tmp_value = value_cell (old_var); + + /* If we want to change to "inherit the old variable's value" semantics, + here is where to save the old value. */ + old_value = was_tmpvar ? value_cell (old_var) : (char *)NULL; for (vc = shell_variables; vc; vc = vc->down) if (vc_isfuncenv (vc) && vc->scope == variable_context) @@ -2510,10 +2517,36 @@ make_local_variable (name) things like `x=4 local x'. XXX - see above for temporary env variables with the same context level as variable_context */ /* XXX - we should only do this if the variable is not an array. */ + /* If we want to change the local variable semantics to "inherit + the old variable's value" here is where to set it. And we would + need to use copy_variable (currently unused) to do it for all + possible variable values. */ if (was_tmpvar) - var_setvalue (new_var, savestring (tmp_value)); + var_setvalue (new_var, savestring (old_value)); + else if (localvar_inherit) + { + /* This may not make sense for nameref variables that are shadowing + variables with the same name, but we don't know that yet. */ + if (assoc_p (old_var)) + var_setassoc (new_var, assoc_copy (assoc_cell (old_var))); + else if (array_p (old_var)) + var_setarray (new_var, array_copy (array_cell (old_var))); + else if (value_cell (old_var)) + var_setvalue (new_var, savestring (value_cell (old_var))); + else + var_setvalue (new_var, (char *)NULL); + } - new_var->attributes = exported_p (old_var) ? att_exported : 0; + if (localvar_inherit) + { + /* It doesn't make sense to inherit the nameref attribute */ + new_var->attributes = old_var->attributes & ~att_nameref; + new_var->dynamic_value = old_var->dynamic_value; + new_var->assign_func = old_var->assign_func; + } + else + /* We inherit the export attribute, but no others. */ + new_var->attributes = exported_p (old_var) ? att_exported : 0; } vc->flags |= VC_HASLOCAL; @@ -2524,7 +2557,9 @@ make_local_variable (name) if (ifsname (name)) setifs (new_var); - if (was_tmpvar == 0 && no_invisible_vars == 0) + /* value_cell will be 0 if localvar_inherit == 0 or there was no old variable + with the same name or the old variable was invisible */ + if (was_tmpvar == 0 && no_invisible_vars == 0 && value_cell (new_var) == 0) VSETATTR (new_var, att_invisible); /* XXX */ return (new_var); } @@ -2601,7 +2636,7 @@ make_local_array_variable (name, assoc_ok) SHELL_VAR *var; ARRAY *array; - var = make_local_variable (name); + var = make_local_variable (name, 0); /* XXX for now */ if (var == 0 || array_p (var) || (assoc_ok && assoc_p (var))) return var; @@ -2635,7 +2670,7 @@ make_local_assoc_variable (name) SHELL_VAR *var; HASH_TABLE *hash; - var = make_local_variable (name); + var = make_local_variable (name, 0); /* XXX for now */ if (var == 0 || assoc_p (var)) return var; diff --git a/variables.h b/variables.h index 3884f56a..46883c92 100644 --- a/variables.h +++ b/variables.h @@ -273,7 +273,7 @@ extern SHELL_VAR *find_tempenv_variable __P((const char *)); extern SHELL_VAR *find_variable_no_invisible __P((const char *)); extern SHELL_VAR *find_variable_for_assignment __P((const char *)); extern SHELL_VAR *copy_variable __P((SHELL_VAR *)); -extern SHELL_VAR *make_local_variable __P((const char *)); +extern SHELL_VAR *make_local_variable __P((const char *, int)); extern SHELL_VAR *bind_variable __P((const char *, char *, int)); extern SHELL_VAR *bind_global_variable __P((const char *, char *, int)); extern SHELL_VAR *bind_function __P((const char *, COMMAND *));