From fed8129b153e3c83c3038cc3ddc71730cbb7d47e Mon Sep 17 00:00:00 2001
From: Ian Lance Taylor <ian@wasabisystems.com>
Date: Thu, 18 Mar 2004 03:16:37 +0000
Subject: [PATCH] pex-unix.c (pexecute): Use vfork instead of fork, with
 appropriate changes to make this safe.

	* pex-unix.c (pexecute): Use vfork instead of fork, with
	appropriate changes to make this safe.
	* pex-common.h (STDERR_FILE_NO): Define.

From-SVN: r79617
---
 libiberty/ChangeLog    |  4 +++
 libiberty/pex-common.h |  5 ++-
 libiberty/pex-unix.c   | 81 +++++++++++++++++++++++++++++++++---------
 3 files changed, 73 insertions(+), 17 deletions(-)

diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog
index 95cc22262ca1..2dce4d82d024 100644
--- a/libiberty/ChangeLog
+++ b/libiberty/ChangeLog
@@ -1,5 +1,9 @@
 2004-03-17  Ian Lance Taylor  <ian@wasabisystems.com>
 
+	* pex-unix.c (pexecute): Use vfork instead of fork, with
+	appropriate changes to make this safe.
+	* pex-common.h (STDERR_FILE_NO): Define.
+
 	* Makefile.in: Clean up REQUIRED_OFILES and CONFIGURED_OFILES for
 	an 80 column screen.  Run maint-deps.
 
diff --git a/libiberty/pex-common.h b/libiberty/pex-common.h
index da2f71e1247a..df3c0f6519c3 100644
--- a/libiberty/pex-common.h
+++ b/libiberty/pex-common.h
@@ -1,6 +1,6 @@
 /* Utilities to execute a program in a subprocess (possibly linked by pipes
    with other subprocesses), and wait for it.  Shared logic.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004
    Free Software Foundation, Inc.
 
 This file is part of the libiberty library.
@@ -33,6 +33,9 @@ Boston, MA 02111-1307, USA.  */
 /* stdout file number.  */
 #define STDOUT_FILE_NO 1
 
+/* stderr file number.  */
+#define STDERR_FILE_NO 2
+
 /* value of `pipe': port index for reading.  */
 #define READ_PORT 0
 
diff --git a/libiberty/pex-unix.c b/libiberty/pex-unix.c
index 14fe71ed09c0..ddbed8f4a05c 100644
--- a/libiberty/pex-unix.c
+++ b/libiberty/pex-unix.c
@@ -1,7 +1,7 @@
 /* Utilities to execute a program in a subprocess (possibly linked by pipes
    with other subprocesses), and wait for it.  Generic Unix version
    (also used for UWIN and VMS).
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004
    Free Software Foundation, Inc.
 
 This file is part of the libiberty library.
@@ -44,28 +44,66 @@ extern int errno;
 #define waitpid(pid, status, flags) wait(status)
 #endif
 
-extern int execv ();
-extern int execvp ();
+#ifdef vfork /* Autoconf may define this to fork for us. */
+# define VFORK_STRING "fork"
+#else
+# define VFORK_STRING "vfork"
+#endif
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+#ifdef VMS
+#define vfork() (decc$$alloc_vfork_blocks() >= 0 ? \
+               lib$get_current_invo_context(decc$$get_vfork_jmpbuf()) : -1)
+#endif /* VMS */
+
+/* Execute a program, possibly setting up pipes to programs executed
+   via other calls to this function.
+
+   This version of the function uses vfork.  In general vfork is
+   similar to setjmp/longmp, in that any variable which is modified by
+   the child process has an indeterminate value in the parent process.
+   We follow a safe approach here by not modifying any variables at
+   all in the child process (with the possible exception of variables
+   modified by xstrerror if exec fails, but this is unlikely to be
+   detectable).
+
+   We work a little bit harder to avoid gcc warnings.  gcc will warn
+   about any automatic variable which is live at the time of the
+   vfork, which is non-volatile, and which is either set more than
+   once or is an argument to the function.  This warning isn't quite
+   right, since what we really care about is whether the variable is
+   live at the time of the vfork and set afterward by the child
+   process, but gcc only checks whether the variable is set more than
+   once.  To avoid this warning, we ensure that any variable which is
+   live at the time of the vfork (i.e., used after the vfork) is set
+   exactly once and is not an argument, or is marked volatile.  */
 
 int
-pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
+pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg,
+	  flagsarg)
      const char *program;
      char * const *argv;
      const char *this_pname;
      const char *temp_base ATTRIBUTE_UNUSED;
      char **errmsg_fmt, **errmsg_arg;
-     int flags;
+     int flagsarg;
 {
-  int (*func)() = (flags & PEXECUTE_SEARCH ? execvp : execv);
   int pid;
   int pdes[2];
+  int out;
   int input_desc, output_desc;
-  int retries, sleep_interval;
+  int flags;
+  /* We declare these to be volatile to avoid warnings from gcc about
+     them being clobbered by vfork.  */
+  volatile int retries, sleep_interval;
   /* Pipe waiting from last process, to be used as input for the next one.
      Value is STDIN_FILE_NO if no pipe is waiting
      (i.e. the next command is the first of a group).  */
   static int last_pipe_input;
 
+  flags = flagsarg;
+
   /* If this is the first process, initialize.  */
   if (flags & PEXECUTE_FIRST)
     last_pipe_input = STDIN_FILE_NO;
@@ -82,22 +120,24 @@ pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
 	  *errmsg_arg = NULL;
 	  return -1;
 	}
-      output_desc = pdes[WRITE_PORT];
+      out = pdes[WRITE_PORT];
       last_pipe_input = pdes[READ_PORT];
     }
   else
     {
       /* Last process.  */
-      output_desc = STDOUT_FILE_NO;
+      out = STDOUT_FILE_NO;
       last_pipe_input = STDIN_FILE_NO;
     }
 
+  output_desc = out;
+
   /* Fork a subprocess; wait and retry if it fails.  */
   sleep_interval = 1;
   pid = -1;
   for (retries = 0; retries < 4; retries++)
     {
-      pid = fork ();
+      pid = vfork ();
       if (pid >= 0)
 	break;
       sleep (sleep_interval);
@@ -131,12 +171,21 @@ pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
 	close (last_pipe_input);
 
       /* Exec the program.  */
-      (*func) (program, argv);
-
-      fprintf (stderr, "%s: ", this_pname);
-      fprintf (stderr, install_error_msg, program);
-      fprintf (stderr, ": %s\n", xstrerror (errno));
-      exit (-1);
+      if (flags & PEXECUTE_SEARCH)
+	execvp (program, argv);
+      else
+	execv (program, argv);
+
+      /* We don't want to call fprintf after vfork.  */
+#define writeerr(s) write (STDERR_FILE_NO, s, strlen (s))
+      writeerr (this_pname);
+      writeerr (": ");
+      writeerr ("installation problem, cannot exec '");
+      writeerr (program);
+      writeerr ("': ");
+      writeerr (xstrerror (errno));
+      writeerr ("\n");
+      _exit (-1);
       /* NOTREACHED */
       return 0;
 
-- 
GitLab