by having the entry being removed as part of the undo list in
_rl_saved_line_for_history. Fixes fuzzing bug reported by
Eduardo Bustamante <dualbus@gmail.com>
+
+ 9/17
+ ----
+[bash-5.0-beta released]
+
+ 9/18
+ ----
+lib/readline/bind.c
+ - name_and_keymap: new struct for keymap names and maps
+ - builtin_keymap_names: static array of builtin keymap names and
+ maps; preparing for allowing applications to set the names of
+ keymaps they create; keymap_names is initially a pointer to
+ this array
+ - _rl_get_keymap_by_name,_rl_get_keymap_by_map: new functions for
+ searching the keymap_names array and returning an index
+ - rl_get_keymap_by_name, rl_get_keymap_name: rewritten in terms of
+ new functions above
+ - rl_set_keymap_name (char *name, Keymap map): new function, set
+ name of MAP to NAME. NAME must not be builtin; MAP must not be one
+ of the builtin keymaps. Request and initial implementation from
+ Tom Tromey <tom@tromey.com>
+
+lib/readline/readline.h
+ - rl_set_keymap_name: new extern declaration for new public function
+
+lib/readline/doc/rltech.texi
+ - rl_set_keymap_name: add documentation
+
+lib/readline/doc/rluser.texi
+ - add text to `set keymap' description to note that applications
+ can add keymap names that can be used there
+
+ 9/20
+ ----
+parse.y
+ - shell_getc: don't execute the alias hack (returning a space at the
+ end of the string) if we are parsing a command substitution that
+ starts with a double paren (subshell inside a comsub), in which
+ case the flags are PSH_DPAREN. Fixes fuzzing bug reported by
+ Eduardo Bustamante <dualbus@gmail.com>
+
+lib/readline/isearch.c
+ - _rl_isearch_dispatch: default case: make sure we check multibyte
+ char length when deciding whether to enlarge the search string
+ buffer, instead of using the old assumption. Fixes fuzzing bug
+ reported by Eduardo Bustamante <dualbus@gmail.com>
+
+builtins/fc.def,execute_cmd.c
+ - fixed some missing free()s uncovered by coverity. Report from
+ Siteshwar Vashisht <svashisht@redhat.com>
+
+lib/glob/glob.c
+ - glob_vector: make sure name_vector is initialized to NULL
+
+lib/sh/{pathcanon,pathphys}.c
+ - {pathcanon,pathphys}: use memmove instead of strcpy on a possibly-
+ overlapping region of memory
+
+subst.c
+ - parameter_list_transform: make sure to dispose the word list in all
+ cases before returning
+ - parameter_brace_expand_rhs: make sure t1 is freed before returning
+ due to an invalid name resulting from an indirect expansion
+
+support/man2html.c
+ - fixed a couple of memory leaks
+
+ 9/21
+ ----
+subst.c
+ - process_substitute: if we are part of a job control process chain
+ (pipeline_pgrp != shell_pgrp), have the child shell forked to run
+ the process substitution set pipeline_pgrp to its own PID,
+ effectively becoming a process group leader without changing
+ its own process group. Fixes stray SIGHUP issue reported by
+ Jeremy Townshend <jeremy.townshend@gmail.com>
+
+ 9/23
+ ----
+arrayfunc.c
+ - assign_array_element: if we are assigning to an existing associative
+ array, and assoc_expand_once is set, allow `*' and `@' as subscripts.
+ Partial fix for report from Grisha Levit <grishalevit@gmail.com>
+
+variables.c
+ - bind_int_variable: if valid_array_reference (lhs) is not true,
+ make sure that the lhs is a valid identifier before assigning the
+ value
+
+arrayfunc.c
+ - valid_array_reference: allow blank subscripts. They are treated as
+ `normal' keys for associative arrays and evaluate to 0 for indexed
+ arrays. More of fix for report from Grisha Levit
+ <grishalevit@gmail.com>
int flags;
{
char *sub, *vname;
- int sublen;
+ int sublen, isassoc;
SHELL_VAR *entry;
vname = array_variable_name (name, (flags & ASS_NOEXPAND) != 0, &sub, &sublen);
if (vname == 0)
return ((SHELL_VAR *)NULL);
- if ((ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']') || (sublen <= 1))
+ entry = find_variable (vname);
+ isassoc = entry && assoc_p (entry);
+
+ if (((isassoc == 0 || (flags & ASS_NOEXPAND) == 0) && (ALL_ELEMENT_SUB (sub[0]) && sub[1] == ']')) || (sublen <= 1))
{
free (vname);
err_badarraysub (name);
return ((SHELL_VAR *)NULL);
}
- entry = find_variable (vname);
entry = assign_array_element_internal (entry, name, vname, sub, sublen, value, flags);
free (vname);
return 0;
if (t[len+1] != '\0')
return 0;
-#if 1
+#if 0
/* Could check and allow subscripts consisting only of whitespace for
existing associative arrays. */
for (r = 1; r < len; r++)
{
sh_wrerror ();
fclose (stream);
+ FREE (fn);
return (EXECUTION_FAILURE);
}
fclose (stream);
{
v = find_variable_nameref_for_create (cp->c_name, 1);
if (v == INVALID_NAMEREF_VALUE)
- return;
+ {
+ free (namevar);
+ return;
+ }
if (v && nameref_p (v))
{
free (cp->c_name);
{
if (readonly_p (v))
err_readonly (cp->c_name);
+ free (namevar);
return;
}
if (v == 0)
order of decreasing precedence.
"id++", "id--" [post-increment and post-decrement]
- "++id", "--id" [pre-increment and pre-decrement]
"-", "+" [(unary operators)]
+ "++id", "--id" [pre-increment and pre-decrement]
"!", "~"
"**" [(exponentiation)]
"*", "/", "%"
/* Could force parsing as preinc or predec and throw an error */
#if 0
{
- /* bash-5.0 */
+ /* Posix says unary plus and minus have higher priority than
+ preinc and predec. */
/* This catches something like --4++ */
if (c == '-')
evalerror ("--: assignment requires lvalue");
firstmalloc = 0;
nalloca = 0;
+ name_vector = NULL;
+
/*itrace("glob_vector: pat = `%s' dir = `%s' flags = 0x%x", pat, dir, flags);*/
/* If PAT is empty, skip the loop, but return one (empty) filename. */
if (pat == 0 || *pat == '\0')
static char *_rl_get_string_variable_value PARAMS((const char *));
static int substring_member_of_array PARAMS((const char *, const char * const *));
+static int _rl_get_keymap_by_name PARAMS((const char *));
+static int _rl_get_keymap_by_map PARAMS((Keymap));
+
static int currently_reading_init_file;
/* used only in this file */
}
/* Auxiliary functions to manage keymaps. */
-static const struct {
- const char * const name;
+struct name_and_keymap {
+ char *name;
Keymap map;
-} keymap_names[] = {
+};
+
+static struct name_and_keymap builtin_keymap_names[] = {
{ "emacs", emacs_standard_keymap },
{ "emacs-standard", emacs_standard_keymap },
{ "emacs-meta", emacs_meta_keymap },
{ (char *)0x0, (Keymap)0x0 }
};
+/* -1 for NULL entry */
+#define NUM_BUILTIN_KEYMAPS (sizeof (builtin_keymap_names) / sizeof (builtin_keymap_names[0]) - 1)
+
+static struct name_and_keymap *keymap_names = builtin_keymap_names;
+
+static int
+_rl_get_keymap_by_name (const char *name)
+{
+ register int i;
+
+ for (i = 0; keymap_names[i].name; i++)
+ if (_rl_stricmp (name, keymap_names[i].name) == 0)
+ return (i);
+ return -1;
+}
+
Keymap
rl_get_keymap_by_name (const char *name)
+{
+ int i;
+
+ i = _rl_get_keymap_by_name (name);
+ return ((i >= 0) ? keymap_names[i].map : (Keymap) NULL);
+}
+
+static int
+_rl_get_keymap_by_map (Keymap map)
{
register int i;
for (i = 0; keymap_names[i].name; i++)
- if (_rl_stricmp (name, keymap_names[i].name) == 0)
- return (keymap_names[i].map);
- return ((Keymap) NULL);
+ if (map == keymap_names[i].map)
+ return (i);
+ return -1;
}
char *
rl_get_keymap_name (Keymap map)
{
- register int i;
+ int i;
+
+ i = _rl_get_keymap_by_map (map);
+ return ((i >= 0) ? keymap_names[i].name : (char *)NULL);
+}
+
+int
+rl_set_keymap_name (const char *name, Keymap map)
+{
+ int i, ni, mi;
+
+ /* First check whether or not we're trying to rename a builtin keymap */
+ mi = _rl_get_keymap_by_map (map);
+ if (mi >= 0 && mi < NUM_BUILTIN_KEYMAPS)
+ return -1;
+
+ /* Then reject attempts to set one of the builtin names to a new map */
+ ni = _rl_get_keymap_by_name (name);
+ if (ni >= 0 && ni < NUM_BUILTIN_KEYMAPS)
+ return -1;
+
+ /* Renaming a keymap we already added */
+ if (mi >= 0) /* XXX - could be >= NUM_BUILTIN_KEYMAPS */
+ {
+ xfree (keymap_names[mi].name);
+ keymap_names[mi].name = savestring (name);
+ return mi;
+ }
+
+ /* Associating new keymap with existing name */
+ if (ni >= 0)
+ {
+ keymap_names[ni].map = map;
+ return ni;
+ }
+
for (i = 0; keymap_names[i].name; i++)
- if (map == keymap_names[i].map)
- return ((char *)keymap_names[i].name);
- return ((char *)NULL);
+ ;
+
+ if (keymap_names == builtin_keymap_names)
+ {
+ keymap_names = xmalloc ((i + 2) * sizeof (struct name_and_keymap));
+ memcpy (keymap_names, builtin_keymap_names, i * sizeof (struct name_and_keymap));
+ }
+ else
+ keymap_names = xrealloc (keymap_names, (i + 2) * sizeof (struct name_and_keymap));
+
+ keymap_names[i].name = savestring (name);
+ keymap_names[i].map = map;
+
+ keymap_names[i+1].name = NULL;
+ keymap_names[i+1].map = NULL;
+
+ return i;
}
-
+
void
rl_set_keymap (Keymap map)
{
be supplied in a @code{set keymap} inputrc line (@pxref{Readline Init File}).
@end deftypefun
+@deftypefun void rl_set_keymap (const char *name, Keymap keymap)
+Set the name of @var{keymap}. This name will then be "registered" and
+available for use in a @code{set keymap} inputrc directive
+@pxref{Readline Init File}).
+The @var{name} may not be one of Readline's builtin names;
+you may not add a different name for one of Readline's builtin keymaps.
+Readline will make a copy of @var{name}.
+You may replace the name associated with a given keymap by calling this
+function two or more times with the same @var{keymap} argument.
+You can associate a registered name with a new keymap by calling this
+function two or more times with the same @var{name} argument.
+There is no way to remove a named keymap once the name has been
+registered.
+@end deftypefun
+
@node Binding Keys
@subsection Binding Keys
@item keymap
@vindex keymap
Sets Readline's idea of the current keymap for key binding commands.
-Acceptable @code{keymap} names are
+Built-in @code{keymap} names are
@code{emacs},
@code{emacs-standard},
@code{emacs-meta},
@code{vi-insert}.
@code{vi} is equivalent to @code{vi-command} (@code{vi-move} is also a
synonym); @code{emacs} is equivalent to @code{emacs-standard}.
+Applications may add additional names.
The default value is @code{emacs}.
The value of the @code{editing-mode} variable also affects the
default keymap.
@set EDITION 8.0
@set VERSION 8.0
-@set UPDATED 6 July 2018
-@set UPDATED-MONTH July 2018
+@set UPDATED 18 September 2018
+@set UPDATED-MONTH September 2018
-@set LASTCHANGE Fri Jul 6 16:25:22 MDT 2018
+@set LASTCHANGE Tue Sep 18 13:08:12 EDT 2018
int
_rl_isearch_dispatch (_rl_search_cxt *cxt, int c)
{
- int n, wstart, wlen, limit, cval;
+ int n, wstart, wlen, limit, cval, incr;
rl_command_func_t *f;
f = (rl_command_func_t *)NULL;
/* Add character to search string and continue search. */
default:
- if (cxt->search_string_index + 2 >= cxt->search_string_size)
+#if defined (HANDLE_MULTIBYTE)
+ wlen = (cxt->mb[0] == 0 || cxt->mb[1] == 0) ? 1 : RL_STRLEN (cxt->mb);
+#else
+ wlen = 1;
+#endif
+ if (cxt->search_string_index + wlen + 1 >= cxt->search_string_size)
{
- cxt->search_string_size += 128;
+ cxt->search_string_size += 128; /* 128 much greater than MB_CUR_MAX */
cxt->search_string = (char *)xrealloc (cxt->search_string, cxt->search_string_size);
}
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
{
- int j, l;
+ int j;
if (cxt->mb[0] == 0 || cxt->mb[1] == 0)
cxt->search_string[cxt->search_string_index++] = cxt->mb[0];
else
- for (j = 0, l = RL_STRLEN (cxt->mb); j < l; )
+ for (j = 0; j < wlen; )
cxt->search_string[cxt->search_string_index++] = cxt->mb[j++];
}
else
/* Set the current keymap to MAP. */
extern void rl_set_keymap PARAMS((Keymap));
+/* Set the name of MAP to NAME */
+extern int rl_set_keymap_name PARAMS((const char *, Keymap));
+
#ifdef __cplusplus
}
#endif
extern char *rl_get_keymap_name PARAMS((Keymap));
extern void rl_set_keymap PARAMS((Keymap));
extern Keymap rl_get_keymap PARAMS((void));
+
+extern int rl_set_keymap_name PARAMS((const char *, Keymap));
+
/* Undocumented; used internally only. */
extern void rl_set_keymap_from_edit_mode PARAMS((void));
extern char *rl_get_keymap_name_from_edit_mode PARAMS((void));
/* Currently this is only used on AIX */
static void
rltty_warning (char *msg)
- char *msg;
{
_rl_errmsg ("warning: %s", msg);
}
if (result[2] == '\0') /* short-circuit for bare `//' */
result[1] = '\0';
else
- strcpy (result, result + 1);
+ memmove (result, result + 1, strlen (result + 1) + 1);
}
return (result);
if (result[2] == '\0') /* short-circuit for bare `//' */
result[1] = '\0';
else
- strcpy (result, result + 1);
+ memmove (result, result + 1, strlen (result + 1) + 1);
}
return (result);
reading a quoted string. */
#ifndef OLD_ALIAS_HACK
if (uc == 0 && pushed_string_list && pushed_string_list->flags != PSH_SOURCE &&
+ pushed_string_list->flags != PSH_DPAREN &&
shell_input_line_index > 0 &&
shell_input_line[shell_input_line_index-1] != ' ' &&
shell_input_line[shell_input_line_index-1] != '\n' &&
#endif
pop_alias:
+ /* This case works for PSH_DPAREN as well */
if (uc == 0 && pushed_string_list && pushed_string_list->flags != PSH_SOURCE)
{
pop_string ();
for (i = 0, set_opts = 0; shell_builtins[i].name; i++)
if (STREQ (shell_builtins[i].name, "set"))
- set_opts = savestring (shell_builtins[i].short_doc);
+ {
+ set_opts = savestring (shell_builtins[i].short_doc);
+ break;
+ }
+
if (set_opts)
{
s = strchr (set_opts, '[');
#if defined (JOB_CONTROL)
if (sig == SIGHUP && (interactive || (subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB))))
hangup_all_jobs ();
+
if ((subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB)) == 0)
end_job_control ();
#endif /* JOB_CONTROL */
if (dollar_dollar_pid != 1)
exit (128+sig); /* just in case the kill fails? */
+ /* We get here only under extraordinary circumstances. */
+
/* We are PID 1, and the kill above failed to kill the process. We assume
this means that we are running as an init process in a pid namespace
on Linux. In this case, we can't send ourselves a fatal signal, so we
set_sigint_handler ();
#if defined (JOB_CONTROL)
+ /* make sure we don't have any job control */
set_job_control (0);
+
+ /* The idea is that we want all the jobs we start from an async process
+ substitution to be in the same process group, but not the same pgrp
+ as our parent shell, since we don't want to affect our parent shell's
+ jobs if we get a SIGHUP and end up calling hangup_all_jobs, for example.
+ If pipeline_pgrp != shell_pgrp, we assume that there is a job control
+ shell somewhere in our parent process chain (since make_child initializes
+ pipeline_pgrp to shell_pgrp if job_control == 0). What we do in this
+ case is to set pipeline_pgrp to our PID, so all jobs started by this
+ process have that same pgrp and we are basically the process group leader.
+ This should not have negative effects on child processes surviving
+ after we exit, since we wait for the children we create, but that is
+ something to watch for. */
+
+ if (pipeline_pgrp != shell_pgrp)
+ pipeline_pgrp = getpid ();
#endif /* JOB_CONTROL */
#if !defined (HAVE_DEV_FD)
{
report_error (_("%s: invalid indirect expansion"), name);
free (vname);
+ free (t1);
dispose_word (w);
return &expand_wdesc_error;
}
{
report_error (_("%s: invalid variable name"), vname);
free (vname);
+ free (t1);
dispose_word (w);
return &expand_wdesc_error;
}
if (list == 0)
return ((char *)NULL);
if (xc == 'A')
- return (pos_params_assignment (list, itype, quoted));
- ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted);
+ ret = pos_params_assignment (list, itype, quoted);
+ else
+ ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted);
dispose_words (list);
return (ret);
}
man_buf[buf_size] = '\n';
man_buf[buf_size + 1] = man_buf[buf_size + 2] = '\0';
} else {
+ free(man_buf);
man_buf = NULL;
}
fclose(man_stream);
h = name;
if (stat(h, &stbuf) != -1)
l = stbuf.st_size;
- buf = stralloc(l + 4);
#if NOCGI
if (!out_length) {
char *t, *s;
-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
./array.tests: line 103: a: readonly variable
./array.tests: line 105: b[]: bad array subscript
./array.tests: line 106: b[*]: bad array subscript
-./array.tests: line 107: ${b[ ]}: bad substitution
+this
./array.tests: line 109: c[-2]: bad array subscript
./array.tests: line 110: c: bad array subscript
jkl
1. indexed:
reference:
-./array25.sub: line 10: ${a[ ]}: bad substitution
+1. 0
./array25.sub: line 11: ' ': syntax error: operand expected (error token is "' '")
-./array25.sub: line 12: ${a[ ]}: bad substitution
+3. 0
4. 0
5. 0
6. 0
3.declare -a a=([0]="12" [1]="1")
4.declare -a a=([0]="13" [1]="1")
arithmetic:
-1.declare -a a=([0]="0" [1]="1")
-2.declare -a a=([0]="0" [1]="1")
-3.declare -a a=([0]="0" [1]="1")
-4.declare -a a=([0]="0" [1]="1")
-5.declare -a a=([0]="0" [1]="1")
+1.declare -a a=([0]="10" [1]="1")
+2.declare -a a=([0]="11" [1]="1")
+3.declare -a a=([0]="12" [1]="1")
+4.declare -a a=([0]="13" [1]="1")
+5.declare -a a=([0]="10" [1]="1")
6.declare -a a=([0]="11" [1]="1")
-7.declare -a a=([0]="0" [1]="1")
+7.declare -a a=([0]="12" [1]="1")
8.declare -a a=([0]="13" [1]="1")
2. associative:
reference:
-./array25.sub: line 47: ${a[ ]}: bad substitution
+1.
2.
-./array25.sub: line 49: ${a[ ]}: bad substitution
+3.
4.
5.
6.
3.declare -A a=([" "]="12" [0]="0" [1]="1" )
4.declare -A a=([" "]="13" [0]="0" [1]="1" )
arithmetic:
-1.declare -A a=([" "]="13" [0]="0" [1]="1" )
-2.declare -A a=([" "]="13" [0]="0" [1]="1" )
-3.declare -A a=([" "]="13" [0]="0" [1]="1" )
+1.declare -A a=([" "]="10" [0]="0" [1]="1" )
+2.declare -A a=([" "]="11" [0]="0" [1]="1" )
+3.declare -A a=([" "]="12" [0]="0" [1]="1" )
4.declare -A a=([" "]="13" [0]="0" [1]="1" )
-5.declare -A a=([" "]="13" [0]="0" [1]="1" )
-6.declare -A a=([" "]="13" [0]="0" [1]="1" ["\" \""]="11" )
-7.declare -A a=([" "]="13" [0]="0" [1]="1" ["\" \""]="11" )
-8.declare -A a=([" "]="13" [0]="0" [1]="1" ["\" \""]="13" )
+5.declare -A a=([" "]="10" [0]="0" [1]="1" )
+6.declare -A a=([" "]="10" [0]="0" [1]="1" ["\" \""]="11" )
+7.declare -A a=([" "]="12" [0]="0" [1]="1" ["\" \""]="11" )
+8.declare -A a=([" "]="12" [0]="0" [1]="1" ["\" \""]="13" )
argv[1] = <aa>
argv[2] = <bb>
argv[1] = <aa>
after 1: 1
after 2: 1
after 3: 1
-array after 1: 1
-array after 2: 1
+4
+array after 1: 0
+
+array after 2: 0
./errors6.sub: uvar: parameter not set
./errors6.sub: uvar: parameter null or not set
./errors6.sub: line 41: invalid-ident: invalid variable name
./errors6.sub: line 42: invalid-ident: invalid variable name
./errors6.sub: line 43: invalid-ident: invalid variable name
+4
+array after 1: 0
+
+array after 2: 0
./errors6.sub: uvar: parameter not set
./errors6.sub: uvar: parameter null or not set
isarr = 1;
v = array_variable_part (lhs, (flags & ASS_NOEXPAND) != 0, (char **)0, (int *)0);
}
+ else if (legal_identifier (lhs) == 0)
+ {
+ sh_invalidid (lhs);
+ return ((SHELL_VAR *)NULL);
+ }
else
#endif
v = find_variable (lhs);