From: Chet Ramey Date: Fri, 1 Feb 2019 14:03:24 +0000 (-0500) Subject: commit bash-20190130 snapshot X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8a9718cfc93958b34e205d0507c3bbf64cba6db5;p=thirdparty%2Fbash.git commit bash-20190130 snapshot --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index caf2e2d4d..05ff6e463 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -5122,3 +5122,71 @@ builtins/complete.def mode characters and doesn't contain any shell break characters that would need to be quoted when defining a function. Fixes issue reported by Great Big Dot + + 1/28 + ---- +variables.c + - dispose_temporary_env: make sure to save temporary_env to a temp + pointer and set temporary_env to NULL before trying to dispose it, + so no flush function ever tries to add a temporary variable back + into the table (e.g., bind_variable()) + + 1/29 + ---- +builtins/evalstring.c + - can_optimize_connection,optimize_fork: add the last command in lists + separated by `;' to the list of candidates for fork optimization + + 1/30 + ---- +examples/loadables/strftime.c + - strftime_builtin: try to extend the buffer longer than tbsize*3, + which is a minimum of 24 characters, in case some of the formats + (e.g., %c) expand to something longer than that. Fixes bug + reported by Stan Marsh + + 1/31 + ---- +lib/readline/undo.c + - rl_do_undo: before inserting text while undoing UNDO_DELETE, or + performing a deletion while undoing UNDO_INSERT, make sure that + rl_point is valid by calling _rl_fix_point. Fuzzing bug and fix + from Eduardo Bustamante + +lib/readline/search.c + - _rl_nsearch_abort: validate new values for rl_point and rl_mark by + calling _rl_fix_point(). Fuzzing bug and fix from + Eduardo Bustamante + +subst.c + - string_extract_double_quoted: if we parse a syntactically-incorrect + $( expression while extracting a double-quoted string, si will + appear to go `backward'. Just skip over the rest of the string and + continue. Fuzzing bug from Eduardo Bustamante + +lib/readline/text.c + - rl_change_case: if towupper or towlower returns a valid wide char + that can't be converted back to a valid multibyte character, use + the original character and go on. Fuzzing bug from + Eduardo Bustamante + +lib/glob/glob.c + - wdequote_pathname: if there are no multibyte characters in pathname, + just call udequote_pathname and don't bother converting it to wide + characters + - glob_pattern_p: if there are no multibyte characters in the pattern, + just call internal_glob_pattern_p right away + +lib/glob/glob_loop.c + - INTERNAL_GLOB_PATTERN_P: return 2 if we see only backslash-quoted + characters without any other unquoted glob pattern characters, so + interested callers can shortcut and just dequote the pathname + +pathexp.c + - unquoted_glob_pattern_p: return 2 if we see only backslash-quoted + characters without any other unquoted glob pattern characters, + consistent with the glob library + - unquoted_glob_pattern_p: don't count a backslash quoting a slash as + a backslash that will trigger a call to shell_glob_filename, since + backslashes at the end of patterns (pathname components) will always + fail to match. XXX - this is provisional diff --git a/MANIFEST b/MANIFEST index 03de22102..dcfd192ce 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1060,6 +1060,7 @@ tests/glob1.sub f tests/glob2.sub f tests/glob3.sub f tests/glob4.sub f +tests/glob5.sub f tests/glob.right f tests/globstar.tests f tests/globstar.right f diff --git a/builtins/evalstring.c b/builtins/evalstring.c index 7a110d959..cadc9bc06 100644 --- a/builtins/evalstring.c +++ b/builtins/evalstring.c @@ -105,7 +105,7 @@ can_optimize_connection (command) COMMAND *command; { return (*bash_input.location.string == '\0' && - (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR) && + (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') && command->value.Connection->second->type == cm_simple); } @@ -114,7 +114,7 @@ optimize_fork (command) COMMAND *command; { if (command->type == cm_connection && - (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR) && + (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') && (command->value.Connection->second->flags & CMD_TRY_OPTIMIZING) && should_suppress_fork (command->value.Connection->second)) { diff --git a/examples/loadables/strftime.c b/examples/loadables/strftime.c index 2de09e348..a6190f1cc 100644 --- a/examples/loadables/strftime.c +++ b/examples/loadables/strftime.c @@ -86,7 +86,7 @@ strftime_builtin (list) /* Now try to figure out how big the buffer should really be. strftime(3) will return the number of bytes placed in the buffer unless it's greater than MAXSIZE, in which case it returns 0. */ - for (n = 1; n < 4; n++) + for (n = 1; n <= 8; n++) { tbuf = xrealloc (tbuf, tbsize * n); tsize = strftime (tbuf, tbsize * n, format, t); @@ -94,7 +94,8 @@ strftime_builtin (list) break; } - printf ("%s\n", tbuf); + if (tsize) + printf ("%s\n", tbuf); free (tbuf); return (EXECUTION_SUCCESS); diff --git a/lib/glob/glob.c b/lib/glob/glob.c index 79ab93398..51c585cee 100644 --- a/lib/glob/glob.c +++ b/lib/glob/glob.c @@ -159,7 +159,7 @@ glob_pattern_p (pattern) wchar_t *wpattern; int r; - if (MB_CUR_MAX == 1) + if (MB_CUR_MAX == 1 || mbsmbchar (pattern) == 0) return (internal_glob_pattern_p ((unsigned char *)pattern)); /* Convert strings to wide chars, and call the multibyte version. */ @@ -173,7 +173,7 @@ glob_pattern_p (pattern) return r; #else - return (internal_glob_pattern_p (pattern)); + return (internal_glob_pattern_p ((unsigned char *)pattern)); #endif } @@ -431,6 +431,12 @@ wdequote_pathname (pathname) int i, j; wchar_t *orig_wpathname; + if (mbsmbchar (pathname) == 0) + { + udequote_pathname (pathname); + return; + } + len = strlen (pathname); /* Convert the strings into wide characters. */ n = xdupmbstowcs (&wpathname, NULL, pathname); @@ -1071,7 +1077,7 @@ glob_filename (pathname, flags) char *directory_name, *filename, *dname, *fn; unsigned int directory_len; int free_dirname; /* flag */ - int dflags; + int dflags, hasglob; result = (char **) malloc (sizeof (char *)); result_size = 1; @@ -1120,9 +1126,12 @@ glob_filename (pathname, flags) free_dirname = 1; } + hasglob = 0; /* If directory_name contains globbing characters, then we - have to expand the previous levels. Just recurse. */ - if (directory_len > 0 && glob_pattern_p (directory_name)) + have to expand the previous levels. Just recurse. + If glob_pattern_p returns != [0,1] we have a pattern that has backslash + quotes but no unquoted glob pattern characters. We dequote it below. */ + if (directory_len > 0 && (hasglob = glob_pattern_p (directory_name)) == 1) { char **directories, *d, *p; register unsigned int i; @@ -1342,6 +1351,11 @@ only_filename: free (directory_name); return (NULL); } + if (directory_len > 0 && hasglob == 2) /* need to dequote */ + { + dequote_pathname (directory_name); + directory_len = strlen (directory_name); + } /* Handle GX_MARKDIRS here. */ result[0] = (char *) malloc (directory_len + 1); if (result[0] == NULL) diff --git a/lib/glob/glob_loop.c b/lib/glob/glob_loop.c index 7d6ae2113..6062f2f9f 100644 --- a/lib/glob/glob_loop.c +++ b/lib/glob/glob_loop.c @@ -26,10 +26,10 @@ INTERNAL_GLOB_PATTERN_P (pattern) { register const GCHAR *p; register GCHAR c; - int bopen; + int bopen, bsquote; p = pattern; - bopen = 0; + bopen = bsquote = 0; while ((c = *p++) != L('\0')) switch (c) @@ -55,13 +55,22 @@ INTERNAL_GLOB_PATTERN_P (pattern) case L('\\'): /* Don't let the pattern end in a backslash (GMATCH returns no match - if the pattern ends in a backslash anyway), but otherwise return 1, - since the matching engine uses backslash as an escape character - and it can be removed. */ - return (*p != L('\0')); + if the pattern ends in a backslash anyway), but otherwise note that + we have seen this, since the matching engine uses backslash as an + escape character and it can be removed. We return 2 later if we + have seen only backslash-escaped characters, so interested callers + know they can shortcut and just dequote the pathname. */ + if (*p != L('\0')) + { + p++; + bsquote = 1; + } + else if (*p == L('\0')) + return 0; + continue; } - return 0; + return bsquote ? 2 : 0; } #undef INTERNAL_GLOB_PATTERN_P diff --git a/lib/glob/smatch.c b/lib/glob/smatch.c index 64fdbbb7d..b2b8b35e4 100644 --- a/lib/glob/smatch.c +++ b/lib/glob/smatch.c @@ -529,7 +529,7 @@ xstrmatch (pattern, string, flags) if (MB_CUR_MAX == 1) return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags)); - if (mbsmbchar (string) == 0 && mbsmbchar (pattern) == 0 && posix_cclass_only (pattern) ) + if (mbsmbchar (string) == 0 && mbsmbchar (pattern) == 0 && posix_cclass_only (pattern)) return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags)); n = xdupmbstowcs (&wpattern, NULL, pattern); diff --git a/lib/readline/search.c b/lib/readline/search.c index c9c1f5d1d..d3920d4b6 100644 --- a/lib/readline/search.c +++ b/lib/readline/search.c @@ -256,6 +256,7 @@ _rl_nsearch_abort (_rl_search_cxt *cxt) rl_clear_message (); rl_point = cxt->save_point; rl_mark = cxt->save_mark; + _rl_fix_point (1); rl_restore_prompt (); RL_UNSETSTATE (RL_STATE_NSEARCH); diff --git a/lib/readline/text.c b/lib/readline/text.c index cddaeebd2..43aa4d97d 100644 --- a/lib/readline/text.c +++ b/lib/readline/text.c @@ -1452,7 +1452,18 @@ rl_change_case (int count, int op) if (nwc != wc) /* just skip unchanged characters */ { char *s, *e; - mlen = wcrtomb (mb, nwc, &mps); + mbstate_t ts; + + memset (&ts, 0, sizeof (mbstate_t)); + mlen = wcrtomb (mb, nwc, &ts); + if (mlen < 0) + { + nwc = wc; + memset (&ts, 0, sizeof (mbstate_t)); + mlen = wcrtomb (mb, nwc, &ts); + if (mlen < 0) /* should not happen */ + strncpy (mb, rl_line_buffer + start, mlen = m); + } if (mlen > 0) mb[mlen] = '\0'; /* what to do if m != mlen? adjust below */ diff --git a/lib/readline/undo.c b/lib/readline/undo.c index ae65d3804..147999119 100644 --- a/lib/readline/undo.c +++ b/lib/readline/undo.c @@ -196,6 +196,7 @@ rl_do_undo (void) /* Undoing deletes means inserting some text. */ case UNDO_DELETE: rl_point = start; + _rl_fix_point (1); rl_insert_text (rl_undo_list->text); xfree (rl_undo_list->text); break; @@ -204,6 +205,7 @@ rl_do_undo (void) case UNDO_INSERT: rl_delete_text (start, end); rl_point = start; + _rl_fix_point (1); break; /* Undoing an END means undoing everything 'til we get to a BEGIN. */ diff --git a/pathexp.c b/pathexp.c index b51729a7b..c1bf2d89b 100644 --- a/pathexp.c +++ b/pathexp.c @@ -65,11 +65,11 @@ unquoted_glob_pattern_p (string) { register int c; char *send; - int open; + int open, bsquote; DECLARE_MBSTATE; - open = 0; + open = bsquote = 0; send = string + strlen (string); while (c = *string++) @@ -100,7 +100,14 @@ unquoted_glob_pattern_p (string) can be removed by the matching engine, so we have to run it through globbing. */ case '\\': - return (*string != 0); + if (*string != '\0' && *string != '/') + { + bsquote = 1; + string++; + continue; + } + else if (*string == 0) + return (0); case CTLESC: if (*string++ == '\0') @@ -117,7 +124,8 @@ unquoted_glob_pattern_p (string) ADVANCE_CHAR_P (string, send - string); #endif } - return (0); + + return (bsquote ? 2 : 0); } /* Return 1 if C is a character that is `special' in a POSIX ERE and needs to diff --git a/subst.c b/subst.c index 4173547d2..f9d34ca7a 100644 --- a/subst.c +++ b/subst.c @@ -964,7 +964,9 @@ add_one_character: temp[j] = ret[t]; temp[j] = string[si]; - if (string[si]) + if (si < i + 2) /* we went back? */ + i += 2; + else if (string[si]) { j++; i = si + 1; diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index 58c375b70..554f3d6ec 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -1,4 +1,4 @@ -BUILD_DIR=/usr/local/build/chet/bash/bash-current +BUILD_DIR=/usr/local/build/bash/bash-current THIS_SH=$BUILD_DIR/bash PATH=$PATH:$BUILD_DIR diff --git a/tests/glob.right b/tests/glob.right index 964d83d1e..3e3ee55cb 100644 --- a/tests/glob.right +++ b/tests/glob.right @@ -63,6 +63,12 @@ a? aa +/tmp/a/b/c /tmp/a/b/c /tmp/a/b/c +/tmp/a/b/c /tmp/a/b/c /tmp/a/b/c +/tmp/a/b/c +/tmp/a/b/c +/tmp\/a/b/c +/tm[p]\/a/b/c argv[1] = argv[2] = argv[3] = @@ -77,7 +83,7 @@ argv[2] = argv[3] = argv[4] = tmp/l1 tmp/l2 tmp/*4 tmp/l3 -./glob.tests: line 47: no match: tmp/*4 +./glob.tests: line 48: no match: tmp/*4 argv[1] = argv[1] = <*> argv[1] = diff --git a/tests/glob.tests b/tests/glob.tests index 01913bbe0..a40dbbbbc 100644 --- a/tests/glob.tests +++ b/tests/glob.tests @@ -12,6 +12,7 @@ ${THIS_SH} ./glob1.sub ${THIS_SH} ./glob2.sub ${THIS_SH} ./glob3.sub ${THIS_SH} ./glob4.sub +${THIS_SH} ./glob5.sub MYDIR=$PWD # save where we are diff --git a/tests/glob5.sub b/tests/glob5.sub new file mode 100644 index 000000000..8075cb3ca --- /dev/null +++ b/tests/glob5.sub @@ -0,0 +1,16 @@ +mkdir -m700 /tmp/a /tmp/a/b +touch /tmp/a/b/c + +echo /tmp/a/b/* "/tmp/a/"b/* "/tmp/a/b"/* + +chmod -r /tmp/a +echo /tmp/a/b/* "/tmp/a/"b/* "/tmp/a/b"/* +echo "/tmp/a/b"/* + +bs=\\ +echo /tmp${bs}/a/b/* +echo /tmp${bs}/a/b/c +echo /tm[p]${bs}/a/b/c + +chmod +r /tmp/a +rm -rf /tmp/a diff --git a/variables.c b/variables.c index f6346eb59..90c16d875 100644 --- a/variables.c +++ b/variables.c @@ -3270,12 +3270,7 @@ bind_variable (name, value, flags) else if (nv == &nameref_maxloop_value) { internal_warning (_("%s: circular name reference"), v->name); -#if 1 - /* TAG:bash-5.1 */ return (bind_global_variable (v->name, value, flags)); -#else - v = 0; /* backwards compat */ -#endif } else v = nv; @@ -3283,12 +3278,7 @@ bind_variable (name, value, flags) else if (nv == &nameref_maxloop_value) { internal_warning (_("%s: circular name reference"), v->name); -#if 1 - /* TAG:bash-5.1 */ return (bind_global_variable (v->name, value, flags)); -#else - v = 0; /* backwards compat */ -#endif } else v = nv; @@ -4472,16 +4462,37 @@ push_posix_temp_var (data) var = (SHELL_VAR *)data; +#if 0 /* TAG:bash-5.1 */ + /* Just like do_assignment_internal(). This makes assignments preceding + special builtins act like standalone assignment statements when in + posix mode. */ + v = bind_variable (var->name, value_cell (var), ASS_FORCE|ASS_NOLONGJMP); + + /* If this modifies an existing local variable, v->context will be non-zero. + If it comes back with v->context == 0, we bound at the global context. + Set binding_table appropriately. It doesn't matter whether it's correct + if the variable is local, only that it's not global_variables->table */ + binding_table = v->context ? shell_variables->table : global_variables->table; +#else binding_table = global_variables->table; if (binding_table == 0) binding_table = global_variables->table = hash_create (VARIABLES_HASH_BUCKETS); v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE|ASS_NOLONGJMP); +#endif /* global variables are no longer temporary and don't need propagating. */ - var->attributes &= ~(att_tempvar|att_propagate); + if (binding_table == global_variables->table) + var->attributes &= ~(att_tempvar|att_propagate); + if (v) - v->attributes |= var->attributes; + { + v->attributes |= var->attributes; + v->attributes &= ~att_tempvar; /* not a temp var now */ +#if 1 /* TAG:bash-5.1 code doesn't need this, disable for bash-5.1 */ + v->context = (binding_table == global_variables->table) ? 0 : shell_variables->scope; +#endif + } if (find_special_var (var->name) >= 0) tempvar_list[tvlist_ind++] = savestring (var->name); @@ -4575,14 +4586,17 @@ dispose_temporary_env (pushf) sh_free_func_t *pushf; { int i; + HASH_TABLE *disposer; tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1); tempvar_list[tvlist_ind = 0] = 0; - - hash_flush (temporary_env, pushf); - hash_dispose (temporary_env); + + disposer = temporary_env; temporary_env = (HASH_TABLE *)NULL; + hash_flush (disposer, pushf); + hash_dispose (disposer); + tempvar_list[tvlist_ind] = 0; array_needs_making = 1;