File bash-4.4-bgpoverflow.patch of Package bash.11092

---
 execute_cmd.c |    4 ++
 jobs.c        |   45 +++++++++++++++++++------
 nojobs.c      |    5 ++
 subst.c       |  102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 subst.h       |    8 ++++
 5 files changed, 154 insertions(+), 10 deletions(-)

--- execute_cmd.c
+++ execute_cmd.c	2019-06-05 09:19:06.362106086 +0000
@@ -722,6 +722,10 @@ execute_command_internal (command, async
     stdin_redir = stdin_redirects (command->redirects);
 
 #if defined (PROCESS_SUBSTITUTION)
+#  if !defined (HAVE_DEV_FD)
+  reap_procsubs ();
+#  endif
+
   if (variable_context != 0)
     {
       ofifo = num_fifos ();
--- jobs.c
+++ jobs.c	2019-06-05 09:42:13.056119389 +0000
@@ -72,6 +72,8 @@
 #include "execute_cmd.h"
 #include "flags.h"
 
+#include "typemax.h"
+
 #include "builtins/builtext.h"
 #include "builtins/common.h"
 
@@ -92,7 +94,7 @@ extern int killpg __P((pid_t, int));
 #endif
 
 #if !MAX_CHILD_MAX
-#  define MAX_CHILD_MAX 8192
+#  define MAX_CHILD_MAX 32768
 #endif
 
 #if !defined (DEBUG)
@@ -751,7 +753,7 @@ stop_pipeline (async, deferred)
 static void
 bgp_resize ()
 {
-  ps_index_t nsize;
+  ps_index_t nsize, nsize_cur, nsize_max;
   ps_index_t psi;
 
   if (bgpids.nalloc == 0)
@@ -765,10 +767,19 @@ bgp_resize ()
   else
     nsize = bgpids.nalloc;
 
-  while (nsize < js.c_childmax)
-    nsize *= 2;
+  nsize_max = TYPE_MAXIMUM (ps_index_t);
+  nsize_cur = (ps_index_t)js.c_childmax;
+  if (nsize_cur < 0)				/* overflow */
+    nsize_cur = MAX_CHILD_MAX;
+
+  while (nsize > 0 && nsize < nsize_cur)	/* > 0 should catch overflow */
+    nsize <<= 1;
+  if (nsize > nsize_max || nsize <= 0)		/* overflow? */
+    nsize = nsize_max;
+  if (nsize > MAX_CHILD_MAX)
+    nsize = nsize_max = MAX_CHILD_MAX;		/* hard cap */
 
-  if (bgpids.nalloc < js.c_childmax)
+  if (bgpids.nalloc < nsize_cur && bgpids.nalloc < nsize_max)
     {
       bgpids.storage = (struct pidstat *)xrealloc (bgpids.storage, nsize * sizeof (struct pidstat));
 
@@ -785,9 +796,7 @@ bgp_resize ()
 static ps_index_t
 bgp_getindex ()
 {
-  ps_index_t psi;
-
-  if (bgpids.nalloc < js.c_childmax || bgpids.head >= bgpids.nalloc)
+  if (bgpids.nalloc < (ps_index_t)js.c_childmax || bgpids.head >= bgpids.nalloc)
     bgp_resize ();
 
   pshash_delindex (bgpids.head);		/* XXX - clear before reusing */
@@ -1010,6 +1019,7 @@ cleanup_dead_jobs ()
 {
   register int i;
   int os;
+  PROCESS *discard;
 
   if (js.j_jobslots == 0 || jobs_list_frozen)
     return;
@@ -1034,8 +1044,9 @@ cleanup_dead_jobs ()
   if (last_procsub_child && last_procsub_child->running == PS_DONE)
     {
       bgp_add (last_procsub_child->pid, process_exit_status (last_procsub_child->status));	/* XXX */
-      discard_pipeline (last_procsub_child);
+      discard = last_procsub_child;
       last_procsub_child = (PROCESS *)NULL;
+      discard_pipeline (discard);
     }
 #endif
 
@@ -2475,6 +2486,13 @@ wait_for_background_pids ()
 	waited_for++;
     }
 
+#if defined (PROCESS_SUBSTITUTION)
+  if (last_procsub_child && last_procsub_child->pid != NO_PID)
+    r = wait_for (last_procsub_child->pid);
+  wait_procsubs ();
+  reap_procsubs ();
+#endif
+
   /* POSIX.2 says the shell can discard the statuses of all completed jobs if
      `wait' is called with no arguments. */
   mark_dead_jobs_as_notified (1);
@@ -3498,6 +3516,7 @@ waitchld (wpid, block)
   WAIT status;
   PROCESS *child;
   pid_t pid;
+  int ind;
 
   int call_set_current, last_stopped_job, job, children_exited, waitpid_flags;
   static int wcontinued = WCONTINUED;	/* run-time fix for glibc problem */
@@ -3604,6 +3623,13 @@ itrace("waitchld: waitpid returns %d blo
       coproc_pidchk (pid, WSTATUS(status));
 #endif
 
+#if defined (PROCESS_SUBSTITUTION)
+      /* Only manipulate the list of process substitutions while SIGCHLD
+        is blocked. */
+      if ((ind = find_procsub_child (pid)) >= 0)
+	set_procsub_status (ind, pid, WSTATUS (status));
+#endif
+
       /* It is not an error to have a child terminate that we did
 	 not have a record of.  This child could have been part of
 	 a pipeline in backquote substitution.  Even so, I'm not
@@ -4838,5 +4864,4 @@ restore_pgrp_pipe (p)
   pgrp_pipe[0] = p[0];
   pgrp_pipe[1] = p[1];
 }
-
 #endif /* PGRP_PIPE */
--- nojobs.c
+++ nojobs.c	2019-06-05 09:28:29.891549557 +0000
@@ -273,6 +273,11 @@ set_pid_status (pid, status)
   coproc_pidchk (pid, status);
 #endif
 
+#if defined (PROCESS_SUBSTITUTION)
+  if ((slot = find_procsub_child (pid)) >= 0)
+    set_procsub_status (slot, pid, WSTATUS (status));
+#endif
+
   slot = find_index_by_pid (pid);
   if (slot == NO_PID)
     return;
--- subst.c
+++ subst.c	2019-06-05 09:34:35.696693909 +0000
@@ -5506,6 +5506,55 @@ close_new_fifos (list, lsize)
 }
 
 int
+find_procsub_child (pid)
+     pid_t pid;
+{
+  int i;
+
+  for (i = 0; i < nfifo; i++)
+    if (fifo_list[i].proc == pid)
+      return i;
+  return -1;
+}
+
+void
+set_procsub_status (ind, pid, status)
+     int ind;
+     pid_t pid;
+     int status;
+{
+  if (ind >= 0 && ind < nfifo)
+    fifo_list[ind].proc = (pid_t)-1;		/* sentinel */
+}
+
+/* If we've marked the process for this procsub as dead, close the
+   associated file descriptor and delete the FIFO. */
+void
+reap_procsubs ()
+{
+  int i;
+
+  for (i = 0; i < nfifo; i++)
+    if (fifo_list[i].proc == (pid_t)-1)	/* reaped */
+      unlink_fifo (i);
+}
+
+void
+wait_procsubs ()
+{
+  int i, r;
+
+  for (i = 0; i < nfifo; i++)
+    {
+      if (fifo_list[i].proc != (pid_t)-1 && fifo_list[i].proc > 0)
+	{
+	  r = wait_for (fifo_list[i].proc);
+	  fifo_list[i].proc = (pid_t)-1;
+	}
+    }
+}
+
+int
 fifos_pending ()
 {
   return nfifo;
@@ -5674,6 +5723,59 @@ close_new_fifos (list, lsize)
     unlink_fifo (i);  
 }
 
+int
+find_procsub_child (pid)
+     pid_t pid;
+{
+  int i;
+
+  if (nfds == 0)
+    return -1;
+
+  for (i = 0; i < totfds; i++)
+    if (dev_fd_list[i] == pid)
+      return i;
+
+  return -1;
+}
+
+void
+set_procsub_status (ind, pid, status)
+     int ind;
+     pid_t pid;
+     int status;
+{
+  if (ind >= 0 && ind < totfds)
+    dev_fd_list[ind] = (pid_t)-1;		/* sentinel */
+}
+
+/* If we've marked the process for this procsub as dead, close the
+   associated file descriptor. */
+void
+reap_procsubs ()
+{
+  int i;
+
+  for (i = 0; nfds > 0 && i < totfds; i++)
+    if (dev_fd_list[i] == (pid_t)-1)
+      unlink_fifo (i);
+}
+
+void
+wait_procsubs ()
+{
+  int i, r;
+
+  for (i = 0; nfds > 0 && i < totfds; i++)
+    {
+      if (dev_fd_list[i] != (pid_t)-1 && dev_fd_list[i] > 0)
+	{
+	  r = wait_for (dev_fd_list[i]);
+	  dev_fd_list[i] = (pid_t)-1;
+	}
+    }
+}
+
 #if defined (NOTDEF)
 print_dev_fd_list ()
 {
--- subst.h
+++ subst.h	2019-06-05 09:15:36.846029324 +0000
@@ -261,6 +261,7 @@ extern WORD_LIST *expand_words_shellexp
 extern WORD_DESC *command_substitute __P((char *, int));
 extern char *pat_subst __P((char *, char *, char *, int));
 
+#if defined (PROCESS_SUBSTITUTION)
 extern int fifos_pending __P((void));
 extern int num_fifos __P((void));
 extern void unlink_fifo_list __P((void));
@@ -272,6 +273,13 @@ extern void close_new_fifos __P((char *,
 
 extern void clear_fifo_list __P((void));
 
+extern int find_procsub_child __P((pid_t));
+extern void set_procsub_status __P((int, pid_t, int));
+
+extern void wait_procsubs __P((void));
+extern void reap_procsubs __P((void));
+#endif
+
 extern WORD_LIST *list_string_with_quotes __P((char *));
 
 #if defined (ARRAY_VARS)