Index: patches/bash-4.4-branch_update-1.patch
===================================================================
--- patches/bash-4.4-branch_update-1.patch	(revision 5344c0b4eaa83280675f8aab3762ff64141be372)
+++ patches/bash-4.4-branch_update-1.patch	(revision 5344c0b4eaa83280675f8aab3762ff64141be372)
@@ -0,0 +1,479 @@
+Submitted By: William Harrington (kb0iic at cross-lfs dot org)
+Date: 05-03-2017
+Initial Package Version: 4.4
+Origin: Upstream
+Upstream Status: Applied
+Description: Contains all upstream patches up to 4.4-012
+
+diff -Naur bash-4.4.orig/bashline.c bash-4.4/bashline.c
+--- bash-4.4.orig/bashline.c	2016-08-06 01:44:05.000000000 +0000
++++ bash-4.4/bashline.c	2017-04-13 23:33:07.549107403 +0000
+@@ -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 18:18:51.000000000 +0000
++++ bash-4.4/builtins/evalstring.c	2017-04-13 23:33:07.545107350 +0000
+@@ -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 18:31:49.000000000 +0000
++++ bash-4.4/builtins/pushd.def	2017-04-13 23:33:07.546107363 +0000
+@@ -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 18:24:56.000000000 +0000
++++ bash-4.4/builtins/read.def	2017-04-13 23:33:07.609108202 +0000
+@@ -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 18:46:36.000000000 +0000
++++ bash-4.4/expr.c	2017-04-13 23:33:07.552107443 +0000
+@@ -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 20:38:44.000000000 +0000
++++ bash-4.4/jobs.c	2017-04-13 23:33:07.542107310 +0000
+@@ -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 14:35:51.000000000 +0000
++++ bash-4.4/jobs.h	2017-04-13 23:33:07.542107310 +0000
+@@ -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 15:23:21.000000000 +0000
++++ bash-4.4/lib/glob/sm_loop.c	2017-04-13 23:33:07.540107283 +0000
+@@ -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 18:50:31.000000000 +0000
++++ bash-4.4/lib/readline/history.c	2017-04-13 23:33:07.607108175 +0000
+@@ -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 18:51:03.000000000 +0000
++++ bash-4.4/patchlevel.h	2017-04-13 23:33:07.612108242 +0000
+@@ -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 20:02:45.000000000 +0000
++++ bash-4.4/sig.c	2017-04-13 23:33:07.609108202 +0000
+@@ -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 20:46:38.000000000 +0000
++++ bash-4.4/subst.c	2017-04-13 23:33:07.612108242 +0000
+@@ -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;
+ 
