Submitted By: Bruce Dubbs Date: 2017-02-07 Initial Package Version: 4.4 Upstream Status: Already in upstream patch repo Origin: Upstream Description: This patch contains upstream patch numbers 001 thru 012 diff -Naur bash-4.4.orig/bashline.c bash-4.4/bashline.c --- bash-4.4.orig/bashline.c 2016-08-05 20:44:05.000000000 -0500 +++ bash-4.4/bashline.c 2017-02-07 19:47:19.848288939 -0600 @@ -142,7 +142,7 @@ static rl_icppfunc_t *save_directory_hook __P((void)); static void restore_directory_hook __P((rl_icppfunc_t)); -static int directory_exists __P((const char *)); +static int directory_exists __P((const char *, int)); static void cleanup_expansion_error __P((void)); static void maybe_make_readline_line __P((char *)); @@ -3102,18 +3102,20 @@ rl_directory_rewrite_hook = hookf; } -/* Check whether not the (dequoted) version of DIRNAME, with any trailing slash - removed, exists. */ +/* Check whether not DIRNAME, with any trailing slash removed, exists. If + SHOULD_DEQUOTE is non-zero, we dequote the directory name first. */ static int -directory_exists (dirname) +directory_exists (dirname, should_dequote) const char *dirname; + int should_dequote; { char *new_dirname; int dirlen, r; struct stat sb; - /* First, dequote the directory name */ - new_dirname = bash_dequote_filename ((char *)dirname, rl_completion_quote_character); + /* We save the string and chop the trailing slash because stat/lstat behave + inconsistently if one is present. */ + new_dirname = should_dequote ? bash_dequote_filename ((char *)dirname, rl_completion_quote_character) : savestring (dirname); dirlen = STRLEN (new_dirname); if (new_dirname[dirlen - 1] == '/') new_dirname[dirlen - 1] = '\0'; @@ -3145,7 +3147,7 @@ else if (t = mbschr (local_dirname, '`')) /* XXX */ should_expand_dirname = '`'; - if (should_expand_dirname && directory_exists (local_dirname)) + if (should_expand_dirname && directory_exists (local_dirname, 0)) should_expand_dirname = 0; if (should_expand_dirname) @@ -3155,7 +3157,7 @@ have to worry about restoring this setting. */ global_nounset = unbound_vars_is_error; unbound_vars_is_error = 0; - wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB|W_COMPLETE); /* does the right thing */ + wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB|W_NOPROCSUB|W_COMPLETE); /* does the right thing */ unbound_vars_is_error = global_nounset; if (wl) { @@ -3244,13 +3246,13 @@ should_expand_dirname = '`'; } - if (should_expand_dirname && directory_exists (local_dirname)) + if (should_expand_dirname && directory_exists (local_dirname, 1)) should_expand_dirname = 0; if (should_expand_dirname) { new_dirname = savestring (local_dirname); - wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB|W_COMPLETE); /* does the right thing */ + wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB|W_NOPROCSUB|W_COMPLETE); /* does the right thing */ if (wl) { *dirname = string_list (wl); diff -Naur bash-4.4.orig/builtins/evalstring.c bash-4.4/builtins/evalstring.c --- bash-4.4.orig/builtins/evalstring.c 2016-08-11 13:18:51.000000000 -0500 +++ bash-4.4/builtins/evalstring.c 2017-02-07 19:47:19.846288923 -0600 @@ -104,12 +104,9 @@ running_trap == 0 && *bash_input.location.string == '\0' && command->type == cm_simple && -#if 0 signal_is_trapped (EXIT_TRAP) == 0 && signal_is_trapped (ERROR_TRAP) == 0 && -#else any_signals_trapped () < 0 && -#endif command->redirects == 0 && command->value.Simple->redirects == 0 && ((command->flags & CMD_TIME_PIPELINE) == 0) && ((command->flags & CMD_INVERT_RETURN) == 0)); diff -Naur bash-4.4.orig/builtins/pushd.def bash-4.4/builtins/pushd.def --- bash-4.4.orig/builtins/pushd.def 2016-01-25 12:31:49.000000000 -0600 +++ bash-4.4/builtins/pushd.def 2017-02-07 19:47:19.846288923 -0600 @@ -365,7 +365,7 @@ break; } - if (which > directory_list_offset || (directory_list_offset == 0 && which == 0)) + if (which > directory_list_offset || (which < -directory_list_offset) || (directory_list_offset == 0 && which == 0)) { pushd_error (directory_list_offset, which_word ? which_word : ""); return (EXECUTION_FAILURE); @@ -387,6 +387,11 @@ remove that directory from the list and shift the remainder of the list into place. */ i = (direction == '+') ? directory_list_offset - which : which; + if (i < 0 || i > directory_list_offset) + { + pushd_error (directory_list_offset, which_word ? which_word : ""); + return (EXECUTION_FAILURE); + } free (pushd_directory_list[i]); directory_list_offset--; diff -Naur bash-4.4.orig/builtins/read.def bash-4.4/builtins/read.def --- bash-4.4.orig/builtins/read.def 2016-05-16 13:24:56.000000000 -0500 +++ bash-4.4/builtins/read.def 2017-02-07 19:47:19.851288961 -0600 @@ -181,7 +181,8 @@ WORD_LIST *list; { register char *varname; - int size, i, nr, pass_next, saw_escape, eof, opt, retval, code, print_ps2; + int size, nr, pass_next, saw_escape, eof, opt, retval, code, print_ps2; + volatile int i; int input_is_tty, input_is_pipe, unbuffered_read, skip_ctlesc, skip_ctlnul; int raw, edit, nchars, silent, have_timeout, ignore_delim, fd, lastsig, t_errno; unsigned int tmsec, tmusec; diff -Naur bash-4.4.orig/expr.c bash-4.4/expr.c --- bash-4.4.orig/expr.c 2015-10-11 13:46:36.000000000 -0500 +++ bash-4.4/expr.c 2017-02-07 19:47:19.849288946 -0600 @@ -578,24 +578,23 @@ rval = cval = explor (); if (curtok == QUES) /* found conditional expr */ { - readtok (); - if (curtok == 0 || curtok == COL) - evalerror (_("expression expected")); if (cval == 0) { set_noeval = 1; noeval++; } + readtok (); + if (curtok == 0 || curtok == COL) + evalerror (_("expression expected")); + val1 = EXP_HIGHEST (); if (set_noeval) noeval--; if (curtok != COL) evalerror (_("`:' expected for conditional expression")); - readtok (); - if (curtok == 0) - evalerror (_("expression expected")); + set_noeval = 0; if (cval) { @@ -603,7 +602,11 @@ noeval++; } + readtok (); + if (curtok == 0) + evalerror (_("expression expected")); val2 = expcond (); + if (set_noeval) noeval--; rval = cval ? val1 : val2; diff -Naur bash-4.4.orig/jobs.c bash-4.4/jobs.c --- bash-4.4.orig/jobs.c 2016-08-23 15:38:44.000000000 -0500 +++ bash-4.4/jobs.c 2017-02-07 19:47:19.844288908 -0600 @@ -453,6 +453,21 @@ discard_pipeline (disposer); } +void +discard_last_procsub_child () +{ + PROCESS *disposer; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + disposer = last_procsub_child; + last_procsub_child = (PROCESS *)NULL; + UNBLOCK_CHILD (oset); + + if (disposer) + discard_pipeline (disposer); +} + struct pipeline_saver * alloc_pipeline_saver () { diff -Naur bash-4.4.orig/jobs.h bash-4.4/jobs.h --- bash-4.4.orig/jobs.h 2016-04-27 09:35:51.000000000 -0500 +++ bash-4.4/jobs.h 2017-02-07 19:47:19.844288908 -0600 @@ -190,6 +190,7 @@ extern void making_children __P((void)); extern void stop_making_children __P((void)); extern void cleanup_the_pipeline __P((void)); +extern void discard_last_procsub_child __P((void)); extern void save_pipeline __P((int)); extern PROCESS *restore_pipeline __P((int)); extern void start_pipeline __P((void)); diff -Naur bash-4.4.orig/lib/glob/sm_loop.c bash-4.4/lib/glob/sm_loop.c --- bash-4.4.orig/lib/glob/sm_loop.c 2016-04-10 10:23:21.000000000 -0500 +++ bash-4.4/lib/glob/sm_loop.c 2017-02-07 19:47:19.843288901 -0600 @@ -330,6 +330,12 @@ for (pc = 0; p[pc]; pc++) if (p[pc] == L('.') && p[pc+1] == L(']')) break; + if (p[pc] == 0) + { + if (vp) + *vp = INVALID; + return (p + pc); + } val = COLLSYM (p, pc); if (vp) *vp = val; @@ -483,6 +489,9 @@ c = *p++; c = FOLD (c); + if (c == L('\0')) + return ((test == L('[')) ? savep : (CHAR *)0); + if ((flags & FNM_PATHNAME) && c == L('/')) /* [/] can never match when matching a pathname. */ return (CHAR *)0; diff -Naur bash-4.4.orig/lib/readline/history.c bash-4.4/lib/readline/history.c --- bash-4.4.orig/lib/readline/history.c 2015-12-28 12:50:31.000000000 -0600 +++ bash-4.4/lib/readline/history.c 2017-02-07 19:47:19.850288954 -0600 @@ -57,6 +57,8 @@ /* How big to make the_history when we first allocate it. */ #define DEFAULT_HISTORY_INITIAL_SIZE 502 +#define MAX_HISTORY_INITIAL_SIZE 8192 + /* The number of slots to increase the_history by. */ #define DEFAULT_HISTORY_GROW_SIZE 50 @@ -277,6 +279,7 @@ const char *string; { HIST_ENTRY *temp; + int new_length; if (history_stifled && (history_length == history_max_entries)) { @@ -293,13 +296,9 @@ /* Copy the rest of the entries, moving down one slot. Copy includes trailing NULL. */ -#if 0 - for (i = 0; i < history_length; i++) - the_history[i] = the_history[i + 1]; -#else memmove (the_history, the_history + 1, history_length * sizeof (HIST_ENTRY *)); -#endif + new_length = history_length; history_base++; } else @@ -307,11 +306,13 @@ if (history_size == 0) { if (history_stifled && history_max_entries > 0) - history_size = history_max_entries + 2; + history_size = (history_max_entries > MAX_HISTORY_INITIAL_SIZE) + ? MAX_HISTORY_INITIAL_SIZE + : history_max_entries + 2; else history_size = DEFAULT_HISTORY_INITIAL_SIZE; the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *)); - history_length = 1; + new_length = 1; } else { @@ -321,14 +322,15 @@ the_history = (HIST_ENTRY **) xrealloc (the_history, history_size * sizeof (HIST_ENTRY *)); } - history_length++; + new_length = history_length + 1; } } temp = alloc_history_entry ((char *)string, hist_inittime ()); - the_history[history_length] = (HIST_ENTRY *)NULL; - the_history[history_length - 1] = temp; + the_history[new_length] = (HIST_ENTRY *)NULL; + the_history[new_length - 1] = temp; + history_length = new_length; } /* Change the time stamp of the most recent history entry to STRING. */ diff -Naur bash-4.4.orig/patchlevel.h bash-4.4/patchlevel.h --- bash-4.4.orig/patchlevel.h 2016-06-22 13:51:03.000000000 -0500 +++ bash-4.4/patchlevel.h 2017-02-07 19:47:19.853288976 -0600 @@ -25,6 +25,6 @@ regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh looks for to find the patch level (for the sccs version string). */ -#define PATCHLEVEL 0 +#define PATCHLEVEL 12 #endif /* _PATCHLEVEL_H_ */ diff -Naur bash-4.4.orig/sig.c bash-4.4/sig.c --- bash-4.4.orig/sig.c 2016-02-11 14:02:45.000000000 -0600 +++ bash-4.4/sig.c 2017-02-07 19:47:19.852288969 -0600 @@ -585,7 +585,8 @@ #if defined (JOB_CONTROL) if (sig == SIGHUP && (interactive || (subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB)))) hangup_all_jobs (); - end_job_control (); + if ((subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB)) == 0) + end_job_control (); #endif /* JOB_CONTROL */ #if defined (PROCESS_SUBSTITUTION) diff -Naur bash-4.4.orig/subst.c bash-4.4/subst.c --- bash-4.4.orig/subst.c 2016-08-30 15:46:38.000000000 -0500 +++ bash-4.4/subst.c 2017-02-07 19:47:19.853288976 -0600 @@ -2825,11 +2825,15 @@ /* Parse a single word from STRING, using SEPARATORS to separate fields. ENDPTR is set to the first character after the word. This is used by - the `read' builtin. This is never called with SEPARATORS != $IFS; - it should be simplified. + the `read' builtin. + + This is never called with SEPARATORS != $IFS, and takes advantage of that. XXX - this function is very similar to list_string; they should be combined - XXX */ + +#define islocalsep(c) (local_cmap[(unsigned char)(c)] != 0) + char * get_word_from_string (stringp, separators, endptr) char **stringp, *separators, **endptr; @@ -2837,6 +2841,7 @@ register char *s; char *current_word; int sindex, sh_style_split, whitesep, xflags; + unsigned char local_cmap[UCHAR_MAX+1]; /* really only need single-byte chars here */ size_t slen; if (!stringp || !*stringp || !**stringp) @@ -2846,20 +2851,23 @@ separators[1] == '\t' && separators[2] == '\n' && separators[3] == '\0'; - for (xflags = 0, s = ifs_value; s && *s; s++) + memset (local_cmap, '\0', sizeof (local_cmap)); + for (xflags = 0, s = separators; s && *s; s++) { if (*s == CTLESC) xflags |= SX_NOCTLESC; if (*s == CTLNUL) xflags |= SX_NOESCCTLNUL; + local_cmap[(unsigned char)*s] = 1; /* local charmap of separators */ } s = *stringp; slen = 0; /* Remove sequences of whitespace at the beginning of STRING, as - long as those characters appear in IFS. */ - if (sh_style_split || !separators || !*separators) + long as those characters appear in SEPARATORS. This happens if + SEPARATORS == $' \t\n' or if IFS is unset. */ + if (sh_style_split || separators == 0) { - for (; *s && spctabnl (*s) && isifs (*s); s++); + for (; *s && spctabnl (*s) && islocalsep (*s); s++); /* If the string is nothing but whitespace, update it and return. */ if (!*s) @@ -2878,9 +2886,9 @@ This obeys the field splitting rules in Posix.2. */ sindex = 0; - /* Don't need string length in ADVANCE_CHAR or string_extract_verbatim - unless multibyte chars are possible. */ - slen = (MB_CUR_MAX > 1) ? STRLEN (s) : 1; + /* Don't need string length in ADVANCE_CHAR unless multibyte chars are + possible, but need it in string_extract_verbatim for bounds checking */ + slen = STRLEN (s); current_word = string_extract_verbatim (s, slen, &sindex, separators, xflags); /* Set ENDPTR to the first character after the end of the word. */ @@ -2899,19 +2907,19 @@ /* Now skip sequences of space, tab, or newline characters if they are in the list of separators. */ - while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex])) + while (s[sindex] && spctabnl (s[sindex]) && islocalsep (s[sindex])) sindex++; /* If the first separator was IFS whitespace and the current character is a non-whitespace IFS character, it should be part of the current field delimiter, not a separate delimiter that would result in an empty field. Look at POSIX.2, 3.6.5, (3)(b). */ - if (s[sindex] && whitesep && isifs (s[sindex]) && !spctabnl (s[sindex])) + if (s[sindex] && whitesep && islocalsep (s[sindex]) && !spctabnl (s[sindex])) { sindex++; /* An IFS character that is not IFS white space, along with any adjacent IFS white space, shall delimit a field. */ - while (s[sindex] && spctabnl (s[sindex]) && isifs (s[sindex])) + while (s[sindex] && spctabnl (s[sindex]) && islocalsep(s[sindex])) sindex++; } @@ -5808,10 +5816,7 @@ { #if defined (JOB_CONTROL) if (last_procsub_child) - { - discard_pipeline (last_procsub_child); - last_procsub_child = (PROCESS *)NULL; - } + discard_last_procsub_child (); last_procsub_child = restore_pipeline (0); #endif @@ -5931,6 +5936,7 @@ char *istring, buf[128], *bufp, *s; int istring_index, istring_size, c, tflag, skip_ctlesc, skip_ctlnul; ssize_t bufn; + int nullbyte; istring = (char *)NULL; istring_index = istring_size = bufn = tflag = 0; @@ -5938,6 +5944,8 @@ for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++) skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL; + nullbyte = 0; + /* Read the output of the command through the pipe. This may need to be changed to understand multibyte characters in the future. */ while (1) @@ -5956,7 +5964,11 @@ if (c == 0) { #if 1 - internal_warning ("%s", _("command substitution: ignored null byte in input")); + if (nullbyte == 0) + { + internal_warning ("%s", _("command substitution: ignored null byte in input")); + nullbyte = 1; + } #endif continue; } @@ -9454,6 +9466,10 @@ tword->flags |= word->flags & (W_ASSIGNARG|W_ASSIGNRHS); /* affects $@ */ if (word->flags & W_COMPLETE) tword->flags |= W_COMPLETE; /* for command substitutions */ + if (word->flags & W_NOCOMSUB) + tword->flags |= W_NOCOMSUB; + if (word->flags & W_NOPROCSUB) + tword->flags |= W_NOPROCSUB; temp = (char *)NULL;