fork() semantics can be problematic.  Most unix style OS'es have
posix_spawn which can be used to replace fork + exec in many cases.
For more information see
e.g. 
https://www.microsoft.com/en-us/research/uploads/prod/2019/04/fork-hotos19.pdf

This replaces the one use of fork in libgfortran with posix_spawn.

2019-05-16  Janne Blomqvist  <j...@gcc.gnu.org>

        PR libfortran/90038
        * configure.ac (AC_CHECK_FUNCS_ONCE): Check for posix_spawn
        instead of fork.
        * intrinsics/execute_command_line (execute_command_line): Use
        posix_spawn instead of fork.
        * Makefile.in: Regenerated.
        * config.h.in: Regenerated.
        * configure: Regenerated.

Regtested on x86_64-pc-linux-gnu, Ok for trunk?
---
 libgfortran/configure.ac                      |  2 +-
 libgfortran/intrinsics/execute_command_line.c | 19 +++++++++----------
 2 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/libgfortran/configure.ac b/libgfortran/configure.ac
index c06db7b1a78..66af512a292 100644
--- a/libgfortran/configure.ac
+++ b/libgfortran/configure.ac
@@ -315,7 +315,7 @@ else
    AC_CHECK_FUNCS_ONCE(getrusage times mkstemp strtof strtold snprintf \
    ftruncate chsize chdir getentropy getlogin gethostname kill link symlink \
    sleep ttyname \
-   alarm access fork setmode fcntl writev \
+   alarm access posix_spawn setmode fcntl writev \
    gettimeofday stat fstat lstat getpwuid vsnprintf dup \
    getcwd localtime_r gmtime_r getpwuid_r ttyname_r clock_gettime \
    getgid getpid getuid geteuid umask getegid \
diff --git a/libgfortran/intrinsics/execute_command_line.c 
b/libgfortran/intrinsics/execute_command_line.c
index a234bc328b5..3df99c10678 100644
--- a/libgfortran/intrinsics/execute_command_line.c
+++ b/libgfortran/intrinsics/execute_command_line.c
@@ -32,7 +32,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If 
not, see
 #ifdef  HAVE_SYS_WAIT_H
 #include <sys/wait.h>
 #endif
-
+#ifdef HAVE_POSIX_SPAWN
+#include <spawn.h>
+extern char **environ;
+#endif
 
 enum { EXEC_SYNCHRONOUS = -2, EXEC_NOERROR = 0, EXEC_SYSTEMFAILED,
        EXEC_CHILDFAILED, EXEC_INVALIDCOMMAND };
@@ -71,7 +74,7 @@ execute_command_line (const char *command, bool wait, int 
*exitstat,
   /* Flush all I/O units before executing the command.  */
   flush_all_units();
 
-#if defined(HAVE_FORK)
+#if defined(HAVE_POSIX_SPAWN)
   if (!wait)
     {
       /* Asynchronous execution.  */
@@ -79,14 +82,10 @@ execute_command_line (const char *command, bool wait, int 
*exitstat,
 
       set_cmdstat (cmdstat, EXEC_NOERROR);
 
-      if ((pid = fork()) < 0)
+      const char * const argv[] = {"sh", "-c", cmd, NULL};
+      if (posix_spawn (&pid, "/bin/sh", NULL, NULL,
+                      (char * const* restrict) argv, environ))
        set_cmdstat (cmdstat, EXEC_CHILDFAILED);
-      else if (pid == 0)
-       {
-         /* Child process.  */
-         int res = system (cmd);
-         _exit (WIFEXITED(res) ? WEXITSTATUS(res) : res);
-       }
     }
   else
 #endif
@@ -96,7 +95,7 @@ execute_command_line (const char *command, bool wait, int 
*exitstat,
 
       if (res == -1)
        set_cmdstat (cmdstat, EXEC_SYSTEMFAILED);
-#ifndef HAVE_FORK
+#ifndef HAVE_POSIX_SPAWN
       else if (!wait)
        set_cmdstat (cmdstat, EXEC_SYNCHRONOUS);
 #endif
-- 
2.17.1

Reply via email to