bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#14803: Setting close-on-exec flag consistently


From: Paul Eggert
Subject: bug#14803: Setting close-on-exec flag consistently
Date: Sat, 06 Jul 2013 02:13:19 -0700
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130623 Thunderbird/17.0.7

Tags: patch

Here's a patch I'd like to install into Emacs soon.
It changes Emacs so that it creates file descriptors
that are close-on-exec unless they are intended to
be propagated to child processes.
This patch may affect the Microsoft Windows ports
so I'm sending it to bug-gnu-emacs first.
Much of the new code is imported from gnulib.

=== modified file 'ChangeLog'
--- ChangeLog   2013-07-03 03:20:04 +0000
+++ ChangeLog   2013-07-06 08:31:57 +0000
@@ -1,3 +1,12 @@
+2013-07-06  Paul Eggert  <address@hidden>
+
+       Make file descriptors close-on-exec when possible.
+       * configure.ac (mkostemp): New function to check for.
+       (PTY_OPEN): Pass O_CLOEXEC to posix_openpt.
+       * lib/fcntl.c, lib/getdtablesize.c, lib/pipe2.c, m4/fcntl.m4:
+       * m4/getdtablesize.m4, m4/pipe2.m4: New files, taken from gnulib.
+       * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
+
 2013-07-03  Christoph Egger  <address@hidden>  (tiny change)
 
        * configure.ac (emacs_broken_SIGIO): Set on gnu-kfreebsd to avoid hang.

=== modified file 'admin/ChangeLog'
--- admin/ChangeLog     2013-07-06 02:32:13 +0000
+++ admin/ChangeLog     2013-07-06 08:31:57 +0000
@@ -1,3 +1,9 @@
+2013-07-06  Paul Eggert  <address@hidden>
+
+       Make file descriptors close-on-exec when possible.
+       * merge-gnulib (GNULIB_MODULES): Add fcntl, pipe2.
+       (GNULIB_TOOL_FLAGS): Avoid binary-io, close.  Do not avoid fcntl.
+
 2013-07-06  Glenn Morris  <address@hidden>
 
        * admin.el (manual-misc-manuals): New function.

=== modified file 'admin/merge-gnulib'
--- admin/merge-gnulib  2013-05-07 21:34:03 +0000
+++ admin/merge-gnulib  2013-07-06 07:04:07 +0000
@@ -29,11 +29,11 @@
   alloca-opt c-ctype c-strcase
   careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512
   dtoastr dtotimespec dup2 environ execinfo faccessat
-  fcntl-h fdatasync fdopendir filemode fstatat fsync
+  fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync
   getloadavg getopt-gnu gettime gettimeofday
   ignore-value intprops largefile lstat
   manywarnings memrchr mktime
-  pselect pthread_sigmask putenv qacl readlink readlinkat
+  pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat
   sig2str socklen stat-time stdalign stdarg stdbool stdio
   strftime strtoimax strtoumax symlink sys_stat
   sys_time time timer-time timespec-add timespec-sub unsetenv utimens
@@ -41,8 +41,8 @@
 '
 
 GNULIB_TOOL_FLAGS='
-  --avoid=dup
-  --avoid=fchdir --avoid=fcntl --avoid=fstat
+  --avoid=binary-io --avoid=close --avoid=dup
+  --avoid=fchdir --avoid=fstat
   --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow
   --avoid=open --avoid=openat-die --avoid=opendir
   --avoid=raise

=== modified file 'configure.ac'
--- configure.ac        2013-07-03 03:20:04 +0000
+++ configure.ac        2013-07-06 07:04:07 +0000
@@ -3244,7 +3244,7 @@
 getrlimit setrlimit shutdown getaddrinfo \
 strsignal setitimer \
 sendto recvfrom getsockname getpeername getifaddrs freeifaddrs \
-gai_strerror mkstemp getline getdelim sync \
+gai_strerror mkostemp mkstemp getline getdelim sync \
 difftime posix_memalign \
 getpwent endpwent getgrent endgrent \
 touchlock \
@@ -3934,7 +3934,7 @@
       AC_DEFINE(PTY_TTY_NAME_SPRINTF, [{ char *ptyname = 0; sigset_t blocked; 
sigemptyset (&blocked); sigaddset (&blocked, SIGCHLD); pthread_sigmask 
(SIG_BLOCK, &blocked, 0); if (grantpt (fd) != -1 && unlockpt (fd) != -1) 
ptyname = ptsname(fd); pthread_sigmask (SIG_UNBLOCK, &blocked, 0); if 
(!ptyname) { close (fd); return -1; } snprintf (pty_name, sizeof pty_name, 
"%s", ptyname); }])
       dnl if HAVE_POSIX_OPENPT
       if test "x$ac_cv_func_posix_openpt" = xyes; then
-        AC_DEFINE(PTY_OPEN, [fd = posix_openpt (O_RDWR | O_NOCTTY)])
+        AC_DEFINE(PTY_OPEN, [fd = posix_openpt (O_RDWR | O_CLOEXEC | 
O_NOCTTY)])
         AC_DEFINE(PTY_NAME_SPRINTF, [])
       dnl if HAVE_GETPT
       elif test "x$ac_cv_func_getpt" = xyes; then

=== added file 'lib/fcntl.c'
--- lib/fcntl.c 1970-01-01 00:00:00 +0000
+++ lib/fcntl.c 2013-07-06 07:04:07 +0000
@@ -0,0 +1,311 @@
+/* Provide file descriptor control.
+
+   Copyright (C) 2009-2013 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Eric Blake <address@hidden>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <fcntl.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#if !HAVE_FCNTL
+# define rpl_fcntl fcntl
+#endif
+#undef fcntl
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+/* Get declarations of the native Windows API functions.  */
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+
+/* Get _get_osfhandle.  */
+# include "msvc-nothrow.h"
+
+/* Upper bound on getdtablesize().  See lib/getdtablesize.c.  */
+# define OPEN_MAX_MAX 0x10000
+
+/* Duplicate OLDFD into the first available slot of at least NEWFD,
+   which must be positive, with FLAGS determining whether the duplicate
+   will be inheritable.  */
+static int
+dupfd (int oldfd, int newfd, int flags)
+{
+  /* Mingw has no way to create an arbitrary fd.  Iterate until all
+     file descriptors less than newfd are filled up.  */
+  HANDLE curr_process = GetCurrentProcess ();
+  HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd);
+  unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT];
+  unsigned int fds_to_close_bound = 0;
+  int result;
+  BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE;
+  int mode;
+
+  if (newfd < 0 || getdtablesize () <= newfd)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+  if (old_handle == INVALID_HANDLE_VALUE
+      || (mode = setmode (oldfd, O_BINARY)) == -1)
+    {
+      /* oldfd is not open, or is an unassigned standard file
+         descriptor.  */
+      errno = EBADF;
+      return -1;
+    }
+  setmode (oldfd, mode);
+  flags |= mode;
+
+  for (;;)
+    {
+      HANDLE new_handle;
+      int duplicated_fd;
+      unsigned int index;
+
+      if (!DuplicateHandle (curr_process,           /* SourceProcessHandle */
+                            old_handle,             /* SourceHandle */
+                            curr_process,           /* TargetProcessHandle */
+                            (PHANDLE) &new_handle,  /* TargetHandle */
+                            (DWORD) 0,              /* DesiredAccess */
+                            inherit,                /* InheritHandle */
+                            DUPLICATE_SAME_ACCESS)) /* Options */
+        {
+          /* TODO: Translate GetLastError () into errno.  */
+          errno = EMFILE;
+          result = -1;
+          break;
+        }
+      duplicated_fd = _open_osfhandle ((intptr_t) new_handle, flags);
+      if (duplicated_fd < 0)
+        {
+          CloseHandle (new_handle);
+          errno = EMFILE;
+          result = -1;
+          break;
+        }
+      if (newfd <= duplicated_fd)
+        {
+          result = duplicated_fd;
+          break;
+        }
+
+      /* Set the bit duplicated_fd in fds_to_close[].  */
+      index = (unsigned int) duplicated_fd / CHAR_BIT;
+      if (fds_to_close_bound <= index)
+        {
+          if (sizeof fds_to_close <= index)
+            /* Need to increase OPEN_MAX_MAX.  */
+            abort ();
+          memset (fds_to_close + fds_to_close_bound, '\0',
+                  index + 1 - fds_to_close_bound);
+          fds_to_close_bound = index + 1;
+        }
+      fds_to_close[index] |= 1 << ((unsigned int) duplicated_fd % CHAR_BIT);
+    }
+
+  /* Close the previous fds that turned out to be too small.  */
+  {
+    int saved_errno = errno;
+    unsigned int duplicated_fd;
+
+    for (duplicated_fd = 0;
+         duplicated_fd < fds_to_close_bound * CHAR_BIT;
+         duplicated_fd++)
+      if ((fds_to_close[duplicated_fd / CHAR_BIT]
+           >> (duplicated_fd % CHAR_BIT))
+          & 1)
+        close (duplicated_fd);
+
+    errno = saved_errno;
+  }
+
+# if REPLACE_FCHDIR
+  if (0 <= result)
+    result = _gl_register_dup (oldfd, result);
+# endif
+  return result;
+}
+#endif /* W32 */
+
+/* Perform the specified ACTION on the file descriptor FD, possibly
+   using the argument ARG further described below.  This replacement
+   handles the following actions, and forwards all others on to the
+   native fcntl.  An unrecognized ACTION returns -1 with errno set to
+   EINVAL.
+
+   F_DUPFD - duplicate FD, with int ARG being the minimum target fd.
+   If successful, return the duplicate, which will be inheritable;
+   otherwise return -1 and set errno.
+
+   F_DUPFD_CLOEXEC - duplicate FD, with int ARG being the minimum
+   target fd.  If successful, return the duplicate, which will not be
+   inheritable; otherwise return -1 and set errno.
+
+   F_GETFD - ARG need not be present.  If successful, return a
+   non-negative value containing the descriptor flags of FD (only
+   FD_CLOEXEC is portable, but other flags may be present); otherwise
+   return -1 and set errno.  */
+
+int
+rpl_fcntl (int fd, int action, /* arg */...)
+{
+  va_list arg;
+  int result = -1;
+  va_start (arg, action);
+  switch (action)
+    {
+
+#if !HAVE_FCNTL
+    case F_DUPFD:
+      {
+        int target = va_arg (arg, int);
+        result = dupfd (fd, target, 0);
+        break;
+      }
+#elif FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR
+    case F_DUPFD:
+      {
+        int target = va_arg (arg, int);
+        /* Detect invalid target; needed for cygwin 1.5.x.  */
+        if (target < 0 || getdtablesize () <= target)
+          errno = EINVAL;
+        else
+          {
+            /* Haiku alpha 2 loses fd flags on original.  */
+            int flags = fcntl (fd, F_GETFD);
+            if (flags < 0)
+              {
+                result = -1;
+                break;
+              }
+            result = fcntl (fd, action, target);
+            if (0 <= result && fcntl (fd, F_SETFD, flags) == -1)
+              {
+                int saved_errno = errno;
+                close (result);
+                result = -1;
+                errno = saved_errno;
+              }
+# if REPLACE_FCHDIR
+            if (0 <= result)
+              result = _gl_register_dup (fd, result);
+# endif
+          }
+        break;
+      } /* F_DUPFD */
+#endif /* FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR */
+
+    case F_DUPFD_CLOEXEC:
+      {
+        int target = va_arg (arg, int);
+
+#if !HAVE_FCNTL
+        result = dupfd (fd, target, O_CLOEXEC);
+        break;
+#else /* HAVE_FCNTL */
+        /* Try the system call first, if the headers claim it exists
+           (that is, if GNULIB_defined_F_DUPFD_CLOEXEC is 0), since we
+           may be running with a glibc that has the macro but with an
+           older kernel that does not support it.  Cache the
+           information on whether the system call really works, but
+           avoid caching failure if the corresponding F_DUPFD fails
+           for any reason.  0 = unknown, 1 = yes, -1 = no.  */
+        static int have_dupfd_cloexec = GNULIB_defined_F_DUPFD_CLOEXEC ? -1 : 
0;
+        if (0 <= have_dupfd_cloexec)
+          {
+            result = fcntl (fd, action, target);
+            if (0 <= result || errno != EINVAL)
+              {
+                have_dupfd_cloexec = 1;
+# if REPLACE_FCHDIR
+                if (0 <= result)
+                  result = _gl_register_dup (fd, result);
+# endif
+              }
+            else
+              {
+                result = rpl_fcntl (fd, F_DUPFD, target);
+                if (result < 0)
+                  break;
+                have_dupfd_cloexec = -1;
+              }
+          }
+        else
+          result = rpl_fcntl (fd, F_DUPFD, target);
+        if (0 <= result && have_dupfd_cloexec == -1)
+          {
+            int flags = fcntl (result, F_GETFD);
+            if (flags < 0 || fcntl (result, F_SETFD, flags | FD_CLOEXEC) == -1)
+              {
+                int saved_errno = errno;
+                close (result);
+                errno = saved_errno;
+                result = -1;
+              }
+          }
+        break;
+#endif /* HAVE_FCNTL */
+      } /* F_DUPFD_CLOEXEC */
+
+#if !HAVE_FCNTL
+    case F_GETFD:
+      {
+# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+        HANDLE handle = (HANDLE) _get_osfhandle (fd);
+        DWORD flags;
+        if (handle == INVALID_HANDLE_VALUE
+            || GetHandleInformation (handle, &flags) == 0)
+          errno = EBADF;
+        else
+          result = (flags & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC;
+# else /* !W32 */
+        /* Use dup2 to reject invalid file descriptors.  No way to
+           access this information, so punt.  */
+        if (0 <= dup2 (fd, fd))
+          result = 0;
+# endif /* !W32 */
+        break;
+      } /* F_GETFD */
+#endif /* !HAVE_FCNTL */
+
+      /* Implementing F_SETFD on mingw is not trivial - there is no
+         API for changing the O_NOINHERIT bit on an fd, and merely
+         changing the HANDLE_FLAG_INHERIT bit on the underlying handle
+         can lead to odd state.  It may be possible by duplicating the
+         handle, using _open_osfhandle with the right flags, then
+         using dup2 to move the duplicate onto the original, but that
+         is not supported for now.  */
+
+    default:
+      {
+#if HAVE_FCNTL
+        void *p = va_arg (arg, void *);
+        result = fcntl (fd, action, p);
+#else
+        errno = EINVAL;
+#endif
+        break;
+      }
+    }
+  va_end (arg);
+  return result;
+}

=== added file 'lib/getdtablesize.c'
--- lib/getdtablesize.c 1970-01-01 00:00:00 +0000
+++ lib/getdtablesize.c 2013-07-06 07:04:07 +0000
@@ -0,0 +1,86 @@
+/* getdtablesize() function for platforms that don't have it.
+   Copyright (C) 2008-2013 Free Software Foundation, Inc.
+   Written by Bruno Haible <address@hidden>, 2008.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+
+#include <stdio.h>
+
+#include "msvc-inval.h"
+
+#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
+static int
+_setmaxstdio_nothrow (int newmax)
+{
+  int result;
+
+  TRY_MSVC_INVAL
+    {
+      result = _setmaxstdio (newmax);
+    }
+  CATCH_MSVC_INVAL
+    {
+      result = -1;
+    }
+  DONE_MSVC_INVAL;
+
+  return result;
+}
+# define _setmaxstdio _setmaxstdio_nothrow
+#endif
+
+/* Cache for the previous getdtablesize () result.  */
+static int dtablesize;
+
+int
+getdtablesize (void)
+{
+  if (dtablesize == 0)
+    {
+      /* We are looking for the number N such that the valid file descriptors
+         are 0..N-1.  It can be obtained through a loop as follows:
+           {
+             int fd;
+             for (fd = 3; fd < 65536; fd++)
+               if (dup2 (0, fd) == -1)
+                 break;
+             return fd;
+           }
+         On Windows XP, the result is 2048.
+         The drawback of this loop is that it allocates memory for a libc
+         internal array that is never freed.
+
+         The number N can also be obtained as the upper bound for
+         _getmaxstdio ().  _getmaxstdio () returns the maximum number of open
+         FILE objects.  The sanity check in _setmaxstdio reveals the maximum
+         number of file descriptors.  This too allocates memory, but it is
+         freed when we call _setmaxstdio with the original value.  */
+      int orig_max_stdio = _getmaxstdio ();
+      unsigned int bound;
+      for (bound = 0x10000; _setmaxstdio (bound) < 0; bound = bound / 2)
+        ;
+      _setmaxstdio (orig_max_stdio);
+      dtablesize = bound;
+    }
+  return dtablesize;
+}
+
+#endif

=== modified file 'lib/gnulib.mk'
--- lib/gnulib.mk       2013-05-07 21:34:03 +0000
+++ lib/gnulib.mk       2013-07-06 07:04:07 +0000
@@ -21,7 +21,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib 
--m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=dup 
--avoid=fchdir --avoid=fcntl --avoid=fstat --avoid=malloc-posix 
--avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die 
--avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select 
--avoid=sigprocmask --avoid=sys_types --avoid=threadlib 
--makefile-name=gnulib.mk --conditional-dependencies --no-libtool 
--macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat 
close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr 
dtotimespec dup2 environ execinfo faccessat fcntl-h fdatasync fdopendir 
filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday ignore-value 
intprops largefile lstat manywarnings memrchr mktime pselect pthread_sigmask 
putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stdarg 
stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_ti
 me time t
imer-time timespec-add timespec-sub unsetenv utimens warnings
+# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib 
--m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux 
--avoid=binary-io --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat 
--avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open 
--avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd 
--avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib 
--makefile-name=gnulib.mk --conditional-dependencies --no-libtool 
--macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat 
close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr 
dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir 
filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday ignore-value 
intprops largefile lstat manywarnings memrchr mktime pipe2 pselect 
pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time 
stdalign stdarg stdbool stdio strftime strtoimax str
 toumax sy
mlink sys_stat sys_time time timer-time timespec-add timespec-sub unsetenv 
utimens warnings
 
 
 MOSTLYCLEANFILES += core *.stackdump
@@ -296,6 +296,15 @@
 
 ## end   gnulib module faccessat
 
+## begin gnulib module fcntl
+
+
+EXTRA_DIST += fcntl.c
+
+EXTRA_libgnu_a_SOURCES += fcntl.c
+
+## end   gnulib module fcntl
+
 ## begin gnulib module fcntl-h
 
 BUILT_SOURCES += fcntl.h
@@ -384,6 +393,17 @@
 
 ## end   gnulib module fsync
 
+## begin gnulib module getdtablesize
+
+if gl_GNULIB_ENABLED_getdtablesize
+
+endif
+EXTRA_DIST += getdtablesize.c
+
+EXTRA_libgnu_a_SOURCES += getdtablesize.c
+
+## end   gnulib module getdtablesize
+
 ## begin gnulib module getgroups
 
 if gl_GNULIB_ENABLED_getgroups
@@ -568,6 +588,12 @@
 
 ## end   gnulib module pathmax
 
+## begin gnulib module pipe2
+
+libgnu_a_SOURCES += pipe2.c
+
+## end   gnulib module pipe2
+
 ## begin gnulib module pselect
 
 
@@ -1704,9 +1730,7 @@
 
 ## begin gnulib module verify
 
-if gl_GNULIB_ENABLED_verify
 
-endif
 EXTRA_DIST += verify.h
 
 ## end   gnulib module verify

=== added file 'lib/pipe2.c'
--- lib/pipe2.c 1970-01-01 00:00:00 +0000
+++ lib/pipe2.c 2013-07-06 07:04:07 +0000
@@ -0,0 +1,171 @@
+/* Create a pipe, with specific opening flags.
+   Copyright (C) 2009-2013 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include <errno.h>
+#include <fcntl.h>
+
+#if GNULIB_BINARY_IO
+# include "binary-io.h"
+#endif
+
+#include "verify.h"
+
+#if GNULIB_defined_O_NONBLOCK
+# include "nonblocking.h"
+#endif
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+/* Native Windows API.  */
+
+# include <io.h>
+
+#endif
+
+int
+pipe2 (int fd[2], int flags)
+{
+  /* Mingw _pipe() corrupts fd on failure; also, if we succeed at
+     creating the pipe but later fail at changing fcntl, we want
+     to leave fd unchanged: http://austingroupbugs.net/view.php?id=467  */
+  int tmp[2];
+  tmp[0] = fd[0];
+  tmp[1] = fd[1];
+
+#if HAVE_PIPE2
+# undef pipe2
+  /* Try the system call first, if it exists.  (We may be running with a glibc
+     that has the function but with an older kernel that lacks it.)  */
+  {
+    /* Cache the information whether the system call really exists.  */
+    static int have_pipe2_really; /* 0 = unknown, 1 = yes, -1 = no */
+    if (have_pipe2_really >= 0)
+      {
+        int result = pipe2 (fd, flags);
+        if (!(result < 0 && errno == ENOSYS))
+          {
+            have_pipe2_really = 1;
+            return result;
+          }
+        have_pipe2_really = -1;
+      }
+  }
+#endif
+
+  /* Check the supported flags.  */
+  if ((flags & ~(O_CLOEXEC | O_NONBLOCK | O_BINARY | O_TEXT)) != 0)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+/* Native Windows API.  */
+
+  if (_pipe (fd, 4096, flags & ~O_NONBLOCK) < 0)
+    {
+      fd[0] = tmp[0];
+      fd[1] = tmp[1];
+      return -1;
+    }
+
+  /* O_NONBLOCK handling.
+     On native Windows platforms, O_NONBLOCK is defined by gnulib.  Use the
+     functions defined by the gnulib module 'nonblocking'.  */
+# if GNULIB_defined_O_NONBLOCK
+  if (flags & O_NONBLOCK)
+    {
+      if (set_nonblocking_flag (fd[0], true) != 0
+          || set_nonblocking_flag (fd[1], true) != 0)
+        goto fail;
+    }
+# else
+  {
+    verify (O_NONBLOCK == 0);
+  }
+# endif
+
+  return 0;
+
+#else
+/* Unix API.  */
+
+  if (pipe (fd) < 0)
+    return -1;
+
+  /* POSIX <http://www.opengroup.org/onlinepubs/9699919799/functions/pipe.html>
+     says that initially, the O_NONBLOCK and FD_CLOEXEC flags are cleared on
+     both fd[0] and fd[1].  */
+
+  /* O_NONBLOCK handling.
+     On Unix platforms, O_NONBLOCK is defined by the system.  Use fcntl().  */
+  if (flags & O_NONBLOCK)
+    {
+      int fcntl_flags;
+
+      if ((fcntl_flags = fcntl (fd[1], F_GETFL, 0)) < 0
+          || fcntl (fd[1], F_SETFL, fcntl_flags | O_NONBLOCK) == -1
+          || (fcntl_flags = fcntl (fd[0], F_GETFL, 0)) < 0
+          || fcntl (fd[0], F_SETFL, fcntl_flags | O_NONBLOCK) == -1)
+        goto fail;
+    }
+
+  if (flags & O_CLOEXEC)
+    {
+      int fcntl_flags;
+
+      if ((fcntl_flags = fcntl (fd[1], F_GETFD, 0)) < 0
+          || fcntl (fd[1], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1
+          || (fcntl_flags = fcntl (fd[0], F_GETFD, 0)) < 0
+          || fcntl (fd[0], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1)
+        goto fail;
+    }
+
+# if O_BINARY
+  if (flags & O_BINARY)
+    {
+      setmode (fd[1], O_BINARY);
+      setmode (fd[0], O_BINARY);
+    }
+  else if (flags & O_TEXT)
+    {
+      setmode (fd[1], O_TEXT);
+      setmode (fd[0], O_TEXT);
+    }
+# endif
+
+  return 0;
+
+#endif
+
+#if GNULIB_defined_O_NONBLOCK || \
+  !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
+ fail:
+  {
+    int saved_errno = errno;
+    close (fd[0]);
+    close (fd[1]);
+    fd[0] = tmp[0];
+    fd[1] = tmp[1];
+    errno = saved_errno;
+    return -1;
+  }
+#endif
+}

=== added file 'm4/fcntl.m4'
--- m4/fcntl.m4 1970-01-01 00:00:00 +0000
+++ m4/fcntl.m4 2013-07-06 07:04:07 +0000
@@ -0,0 +1,95 @@
+# fcntl.m4 serial 5
+dnl Copyright (C) 2009-2013 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# For now, this module ensures that fcntl()
+# - supports F_DUPFD correctly
+# - supports or emulates F_DUPFD_CLOEXEC
+# - supports F_GETFD
+# Still to be ported to mingw:
+# - F_SETFD
+# - F_GETFL, F_SETFL
+# - F_GETOWN, F_SETOWN
+# - F_GETLK, F_SETLK, F_SETLKW
+AC_DEFUN([gl_FUNC_FCNTL],
+[
+  dnl Persuade glibc to expose F_DUPFD_CLOEXEC.
+  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+  AC_REQUIRE([gl_FCNTL_H_DEFAULTS])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  AC_CHECK_FUNCS_ONCE([fcntl])
+  if test $ac_cv_func_fcntl = no; then
+    gl_REPLACE_FCNTL
+  else
+    dnl cygwin 1.5.x F_DUPFD has wrong errno, and allows negative target
+    dnl haiku alpha 2 F_DUPFD has wrong errno
+    AC_CACHE_CHECK([whether fcntl handles F_DUPFD correctly],
+      [gl_cv_func_fcntl_f_dupfd_works],
+      [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <fcntl.h>
+#include <errno.h>
+]], [[int result = 0;
+      if (fcntl (0, F_DUPFD, -1) != -1) result |= 1;
+      if (errno != EINVAL) result |= 2;
+      return result;
+         ]])],
+         [gl_cv_func_fcntl_f_dupfd_works=yes],
+         [gl_cv_func_fcntl_f_dupfd_works=no],
+         [# Guess that it works on glibc systems
+          case $host_os in #((
+            *-gnu*) gl_cv_func_fcntl_f_dupfd_works="guessing yes";;
+            *)      gl_cv_func_fcntl_f_dupfd_works="guessing no";;
+          esac])])
+    case $gl_cv_func_fcntl_f_dupfd_works in
+      *yes) ;;
+      *) gl_REPLACE_FCNTL
+        AC_DEFINE([FCNTL_DUPFD_BUGGY], [1], [Define this to 1 if F_DUPFD
+          behavior does not match POSIX]) ;;
+    esac
+
+    dnl Many systems lack F_DUPFD_CLOEXEC
+    AC_CACHE_CHECK([whether fcntl understands F_DUPFD_CLOEXEC],
+      [gl_cv_func_fcntl_f_dupfd_cloexec],
+      [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <fcntl.h>
+#ifndef F_DUPFD_CLOEXEC
+choke me
+#endif
+         ]])],
+         [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#ifdef __linux__
+/* The Linux kernel only added F_DUPFD_CLOEXEC in 2.6.24, so we always replace
+   it to support the semantics on older kernels that failed with EINVAL.  */
+choke me
+#endif
+           ]])],
+           [gl_cv_func_fcntl_f_dupfd_cloexec=yes],
+           [gl_cv_func_fcntl_f_dupfd_cloexec="needs runtime check"])],
+         [gl_cv_func_fcntl_f_dupfd_cloexec=no])])
+    if test "$gl_cv_func_fcntl_f_dupfd_cloexec" != yes; then
+      gl_REPLACE_FCNTL
+      dnl No witness macro needed for this bug.
+    fi
+  fi
+  dnl Replace fcntl() for supporting the gnulib-defined fchdir() function,
+  dnl to keep fchdir's bookkeeping up-to-date.
+  m4_ifdef([gl_FUNC_FCHDIR], [
+    gl_TEST_FCHDIR
+    if test $HAVE_FCHDIR = 0; then
+      gl_REPLACE_FCNTL
+    fi
+  ])
+])
+
+AC_DEFUN([gl_REPLACE_FCNTL],
+[
+  AC_REQUIRE([gl_FCNTL_H_DEFAULTS])
+  AC_CHECK_FUNCS_ONCE([fcntl])
+  if test $ac_cv_func_fcntl = no; then
+    HAVE_FCNTL=0
+  else
+    REPLACE_FCNTL=1
+  fi
+])

=== added file 'm4/getdtablesize.m4'
--- m4/getdtablesize.m4 1970-01-01 00:00:00 +0000
+++ m4/getdtablesize.m4 2013-07-06 07:04:07 +0000
@@ -0,0 +1,17 @@
+# getdtablesize.m4 serial 4
+dnl Copyright (C) 2008-2013 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_GETDTABLESIZE],
+[
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  AC_CHECK_FUNCS_ONCE([getdtablesize])
+  if test $ac_cv_func_getdtablesize != yes; then
+    HAVE_GETDTABLESIZE=0
+  fi
+])
+
+# Prerequisites of lib/getdtablesize.c.
+AC_DEFUN([gl_PREREQ_GETDTABLESIZE], [:])

=== modified file 'm4/gnulib-comp.m4'
--- m4/gnulib-comp.m4   2013-05-07 21:34:03 +0000
+++ m4/gnulib-comp.m4   2013-07-06 07:04:07 +0000
@@ -63,6 +63,7 @@
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
   # Code from module extern-inline:
   # Code from module faccessat:
+  # Code from module fcntl:
   # Code from module fcntl-h:
   # Code from module fdatasync:
   # Code from module fdopendir:
@@ -70,6 +71,7 @@
   # Code from module fpending:
   # Code from module fstatat:
   # Code from module fsync:
+  # Code from module getdtablesize:
   # Code from module getgroups:
   # Code from module getloadavg:
   # Code from module getopt-gnu:
@@ -92,6 +94,7 @@
   # Code from module nocrash:
   # Code from module openat-h:
   # Code from module pathmax:
+  # Code from module pipe2:
   # Code from module pselect:
   # Code from module pthread_sigmask:
   # Code from module putenv:
@@ -191,6 +194,11 @@
   fi
   gl_MODULE_INDICATOR([faccessat])
   gl_UNISTD_MODULE_INDICATOR([faccessat])
+  gl_FUNC_FCNTL
+  if test $HAVE_FCNTL = 0 || test $REPLACE_FCNTL = 1; then
+    AC_LIBOBJ([fcntl])
+  fi
+  gl_FCNTL_MODULE_INDICATOR([fcntl])
   gl_FCNTL_H
   gl_FUNC_FDATASYNC
   if test $HAVE_FDATASYNC = 0; then
@@ -273,6 +281,8 @@
   fi
   gl_TIME_MODULE_INDICATOR([mktime])
   gl_MULTIARCH
+  gl_FUNC_PIPE2
+  gl_UNISTD_MODULE_INDICATOR([pipe2])
   gl_FUNC_PSELECT
   if test $HAVE_PSELECT = 0 || test $REPLACE_PSELECT = 1; then
     AC_LIBOBJ([pselect])
@@ -364,6 +374,7 @@
   gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b=false
   gl_gnulib_enabled_dosname=false
   gl_gnulib_enabled_euidaccess=false
+  gl_gnulib_enabled_getdtablesize=false
   gl_gnulib_enabled_getgroups=false
   gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=false
   gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1=false
@@ -373,7 +384,6 @@
   gl_gnulib_enabled_stat=false
   gl_gnulib_enabled_strtoll=false
   gl_gnulib_enabled_strtoull=false
-  gl_gnulib_enabled_verify=false
   gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false
   func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b ()
   {
@@ -407,6 +417,18 @@
       fi
     fi
   }
+  func_gl_gnulib_m4code_getdtablesize ()
+  {
+    if ! $gl_gnulib_enabled_getdtablesize; then
+      gl_FUNC_GETDTABLESIZE
+      if test $HAVE_GETDTABLESIZE = 0; then
+        AC_LIBOBJ([getdtablesize])
+        gl_PREREQ_GETDTABLESIZE
+      fi
+      gl_UNISTD_MODULE_INDICATOR([getdtablesize])
+      gl_gnulib_enabled_getdtablesize=true
+    fi
+  }
   func_gl_gnulib_m4code_getgroups ()
   {
     if ! $gl_gnulib_enabled_getgroups; then
@@ -479,9 +501,6 @@
       if test $REPLACE_STAT = 1; then
         func_gl_gnulib_m4code_pathmax
       fi
-      if test $REPLACE_STAT = 1; then
-        func_gl_gnulib_m4code_verify
-      fi
     fi
   }
   func_gl_gnulib_m4code_strtoll ()
@@ -508,12 +527,6 @@
       gl_gnulib_enabled_strtoull=true
     fi
   }
-  func_gl_gnulib_m4code_verify ()
-  {
-    if ! $gl_gnulib_enabled_verify; then
-      gl_gnulib_enabled_verify=true
-    fi
-  }
   func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec ()
   {
     if ! $gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec; then
@@ -532,6 +545,9 @@
   if test $HAVE_FACCESSAT = 0; then
     func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7
   fi
+  if test $HAVE_FCNTL = 0 || test $REPLACE_FCNTL = 1; then
+    func_gl_gnulib_m4code_getdtablesize
+  fi
   if test $HAVE_FDOPENDIR = 0; then
     func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b
   fi
@@ -568,19 +584,14 @@
   if { test $HAVE_STRTOIMAX = 0 || test $REPLACE_STRTOIMAX = 1; } && test 
$ac_cv_type_long_long_int = yes; then
     func_gl_gnulib_m4code_strtoll
   fi
-  if test $HAVE_STRTOIMAX = 0 || test $REPLACE_STRTOIMAX = 1; then
-    func_gl_gnulib_m4code_verify
-  fi
   if test $ac_cv_func_strtoumax = no && test 
$ac_cv_type_unsigned_long_long_int = yes; then
     func_gl_gnulib_m4code_strtoull
   fi
-  if test $ac_cv_func_strtoumax = no; then
-    func_gl_gnulib_m4code_verify
-  fi
   m4_pattern_allow([^gl_GNULIB_ENABLED_])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_260941c0e5dc67ec9e87d1fb321c300b], 
[$gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_dosname], [$gl_gnulib_enabled_dosname])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_euidaccess], 
[$gl_gnulib_enabled_euidaccess])
+  AM_CONDITIONAL([gl_GNULIB_ENABLED_getdtablesize], 
[$gl_gnulib_enabled_getdtablesize])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_getgroups], [$gl_gnulib_enabled_getgroups])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36], 
[$gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1], 
[$gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1])
@@ -590,7 +601,6 @@
   AM_CONDITIONAL([gl_GNULIB_ENABLED_stat], [$gl_gnulib_enabled_stat])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoull], [$gl_gnulib_enabled_strtoull])
-  AM_CONDITIONAL([gl_GNULIB_ENABLED_verify], [$gl_gnulib_enabled_verify])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec], 
[$gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec])
   # End of code from modules
   m4_ifval(gl_LIBSOURCES_LIST, [
@@ -764,6 +774,7 @@
   lib/execinfo.c
   lib/execinfo.in.h
   lib/faccessat.c
+  lib/fcntl.c
   lib/fcntl.in.h
   lib/fdatasync.c
   lib/fdopendir.c
@@ -776,6 +787,7 @@
   lib/fsync.c
   lib/ftoastr.c
   lib/ftoastr.h
+  lib/getdtablesize.c
   lib/getgroups.c
   lib/getloadavg.c
   lib/getopt.c
@@ -799,6 +811,7 @@
   lib/openat-proc.c
   lib/openat.h
   lib/pathmax.h
+  lib/pipe2.c
   lib/pselect.c
   lib/pthread_sigmask.c
   lib/putenv.c
@@ -870,6 +883,7 @@
   m4/extern-inline.m4
   m4/faccessat.m4
   m4/fcntl-o.m4
+  m4/fcntl.m4
   m4/fcntl_h.m4
   m4/fdatasync.m4
   m4/fdopendir.m4
@@ -877,6 +891,7 @@
   m4/fpending.m4
   m4/fstatat.m4
   m4/fsync.m4
+  m4/getdtablesize.m4
   m4/getgroups.m4
   m4/getloadavg.m4
   m4/getopt.m4
@@ -897,6 +912,7 @@
   m4/nocrash.m4
   m4/off_t.m4
   m4/pathmax.m4
+  m4/pipe2.m4
   m4/pselect.m4
   m4/pthread_sigmask.m4
   m4/putenv.m4

=== added file 'm4/pipe2.m4'
--- m4/pipe2.m4 1970-01-01 00:00:00 +0000
+++ m4/pipe2.m4 2013-07-06 07:04:07 +0000
@@ -0,0 +1,18 @@
+# pipe2.m4 serial 2
+dnl Copyright (C) 2009-2013 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_PIPE2],
+[
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+
+  dnl Persuade glibc <unistd.h> to declare pipe2().
+  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+  AC_CHECK_FUNCS_ONCE([pipe2])
+  if test $ac_cv_func_pipe2 != yes; then
+    HAVE_PIPE2=0
+  fi
+])

=== modified file 'nt/ChangeLog'
--- nt/ChangeLog        2013-06-25 15:08:47 +0000
+++ nt/ChangeLog        2013-07-06 08:25:40 +0000
@@ -1,3 +1,9 @@
+2013-07-06  Paul Eggert  <address@hidden>
+
+       Make file descriptors close-on-exec when possible.
+       * gnulib.mk: Remove empty gl_GNULIB_ENABLED_verify section;
+       otherwise, gnulib-tool complains given close-on-exec changes.
+
 2013-06-25  Juanma Barranquero  <address@hidden>
 
        * configure.bat: Add warning to the help text about using the

=== modified file 'nt/gnulib.mk'
--- nt/gnulib.mk        2013-05-16 05:51:39 +0000
+++ nt/gnulib.mk        2013-07-06 07:04:07 +0000
@@ -876,9 +876,6 @@
 
 ## begin gnulib module verify
 
-if gl_GNULIB_ENABLED_verify
-
-endif
 EXTRA_DIST += verify.h
 
 ## end   gnulib module verify

=== modified file 'src/ChangeLog'
--- src/ChangeLog       2013-07-06 08:26:18 +0000
+++ src/ChangeLog       2013-07-06 08:57:16 +0000
@@ -1,3 +1,39 @@
+2013-07-06  Paul Eggert  <address@hidden>
+
+       Make file descriptors close-on-exec when possible.
+       This simplifies Emacs a bit, since it no longer needs to worry
+       about closing file descriptors by hand in some cases.
+       It also fixes some unlikely races.  Not all such races, as
+       libraries often open files internally without setting
+       close-on-exec, but it's an improvement.
+       * alloc.c (valid_pointer_p) [!WINDOWSNT]:
+       * callproc.c (Fcall_process) [!MSDOS]:
+       * emacs.c (main) [!DOS_NT]:
+       * nsterm.m (ns_term_init):
+       * process.c (create_process):
+       Use 'pipe2' with O_CLOEXEC instead of 'pipe'.
+       * emacs.c (Fcall_process_region) [HAVE_MKOSTEMP]:
+       * filelock.c (create_lock_file) [HAVE_MKOSTEMP]:
+       Prefer mkostemp with O_CLOEXEC to mkstemp.
+       * callproc.c (relocate_fd) [!WINDOWSNT]:
+       * emacs.c (main): Use F_DUPFD_CLOEXEC, not plain F_DUPFD.
+       No need to use fcntl (..., F_SETFD, FD_CLOEXEC), since we're
+       now using pipe2.
+       * filelock.c (create_lock_file) [! HAVE_MKOSTEMP]:
+       Make the resulting file descriptor close-on-exec.
+       * lisp.h, lread.c, process.c (close_load_descs, close_process_descs):
+       * lread.c (load_descriptor_list, load_descriptor_unwind):
+       Remove; no longer needed.  All uses removed.
+       * process.c (SOCK_CLOEXEC): Define to 0 if not supplied by system.
+       (close_on_exec, accept4, process_socket) [!SOCK_CLOEXEC]:
+       New functions.
+       (socket) [!SOCK_CLOEXEC]: Supply a substitute.
+       (Fmake_network_process, Fnetwork_interface_list):
+       (Fnetwork_interface_info, server_accept_connection):
+       Make newly-created socket close-on-exec.
+       * sysdep.c (emacs_open, emacs_fopen):
+       Make new-created descriptor close-on-exec.
+
 2013-07-06  Eli Zaretskii  <address@hidden>
 
        * data.c (Fmultibyte_string_p): Doc fix.

=== modified file 'src/alloc.c'
--- src/alloc.c 2013-07-05 16:58:01 +0000
+++ src/alloc.c 2013-07-06 07:04:07 +0000
@@ -4741,7 +4741,7 @@
      Unfortunately, we cannot use NULL_DEVICE here, as emacs_write may
      not validate p in that case.  */
 
-  if (pipe (fd) == 0)
+  if (pipe2 (fd, O_CLOEXEC) == 0)
     {
       bool valid = emacs_write (fd[1], (char *) p, 16) == 16;
       emacs_close (fd[1]);

=== modified file 'src/callproc.c'
--- src/callproc.c      2013-07-06 07:02:40 +0000
+++ src/callproc.c      2013-07-06 07:05:58 +0000
@@ -517,7 +517,7 @@
     {
 #ifndef MSDOS
       int fd[2];
-      if (pipe (fd) == -1)
+      if (pipe2 (fd, O_CLOEXEC) != 0)
        {
          int pipe_errno = errno;
          emacs_close (filefd);
@@ -1034,12 +1034,16 @@
     memcpy (tempfile, SDATA (encoded_tem), SBYTES (encoded_tem) + 1);
     coding_systems = Qt;
 
-#ifdef HAVE_MKSTEMP
+#if defined HAVE_MKOSTEMP || defined HAVE_MKSTEMP
     {
       int fd;
 
       block_input ();
+# ifdef HAVE_MKOSTEMP
+      fd = mkostemp (tempfile, O_CLOEXEC);
+# else
       fd = mkstemp (tempfile);
+# endif
       unblock_input ();
       if (fd == -1)
        report_file_error ("Failed to open temporary file",
@@ -1182,15 +1186,6 @@
 
   pid_t pid = getpid ();
 
-  /* Close Emacs's descriptors that this process should not have.  */
-  close_process_descs ();
-
-  /* DOS_NT isn't in a vfork, so if we are in the middle of load-file,
-     we will lose if we call close_load_descs here.  */
-#ifndef DOS_NT
-  close_load_descs ();
-#endif
-
   /* Note that use of alloca is always safe here.  It's obvious for systems
      that do not have true vfork or that have true (stack) alloca.
      If using vfork and C_ALLOCA (when Emacs used to include
@@ -1352,9 +1347,11 @@
   emacs_close (1);
   emacs_close (2);
 
+  /* Redirect file descriptors and clear FD_CLOEXEC on the redirected ones.  */
   dup2 (in, 0);
   dup2 (out, 1);
   dup2 (err, 2);
+
   emacs_close (in);
   if (out != in)
     emacs_close (out);
@@ -1392,7 +1389,7 @@
     return fd;
   else
     {
-      int new = fcntl (fd, F_DUPFD, minfd);
+      int new = fcntl (fd, F_DUPFD_CLOEXEC, minfd);
       if (new == -1)
        {
          const char *message_1 = "Error while setting up child: ";

=== modified file 'src/emacs.c'
--- src/emacs.c 2013-07-06 07:02:40 +0000
+++ src/emacs.c 2013-07-06 07:05:58 +0000
@@ -889,7 +889,7 @@
          emacs_close (0);
          emacs_close (1);
          result = emacs_open (term, O_RDWR, 0);
-         if (result < 0 || dup (0) < 0)
+         if (result < 0 || fcntl (0, F_DUPFD_CLOEXEC, 1) < 0)
            {
              char *errstring = strerror (errno);
              fprintf (stderr, "%s: %s: %s\n", argv[0], term, errstring);
@@ -969,7 +969,7 @@
         use a pipe for synchronization.  The parent waits for the child
         to close its end of the pipe (using `daemon-initialized')
         before exiting.  */
-      if (pipe (daemon_pipe) == -1)
+      if (pipe2 (daemon_pipe, O_CLOEXEC) != 0)
        {
          fprintf (stderr, "Cannot pipe!\n");
          exit (1);
@@ -1065,9 +1065,6 @@
                daemon_name = xstrdup (dname_arg);
       /* Close unused reading end of the pipe.  */
       close (daemon_pipe[0]);
-      /* Make sure that the used end of the pipe is closed on exec, so
-        that it is not accessible to programs started from .emacs.  */
-      fcntl (daemon_pipe[1], F_SETFD, FD_CLOEXEC);
 
       setsid ();
 #else /* DOS_NT */

=== modified file 'src/filelock.c'
--- src/filelock.c      2013-05-05 00:51:49 +0000
+++ src/filelock.c      2013-07-06 07:04:07 +0000
@@ -416,8 +416,13 @@
       memcpy (nonce, lfname, lfdirlen);
       strcpy (nonce + lfdirlen, nonce_base);
 
-#if HAVE_MKSTEMP
-      /* Prefer mkstemp if available, as it avoids a race between
+#if HAVE_MKOSTEMP
+      /* Prefer mkostemp to mkstemp, as it avoids a window where FD is
+        temporarily open without close-on-exec.  */
+      fd = mkostemp (nonce, O_BINARY | O_CLOEXEC);
+      need_fchmod = 1;
+#elif HAVE_MKSTEMP
+      /* Prefer mkstemp to mktemp, as it avoids a race between
         mktemp and emacs_open.  */
       fd = mkstemp (nonce);
       need_fchmod = 1;
@@ -432,7 +437,11 @@
        err = errno;
       else
        {
-         ptrdiff_t lock_info_len = strlen (lock_info_str);
+         ptrdiff_t lock_info_len;
+#if ! HAVE_MKOSTEMP
+         fcntl (fd, F_SETFD, FD_CLOEXEC);
+#endif
+         lock_info_len = strlen (lock_info_str);
          err = 0;
          if (emacs_write (fd, lock_info_str, lock_info_len) != lock_info_len
              || (need_fchmod && fchmod (fd, world_readable) != 0))

=== modified file 'src/lisp.h'
--- src/lisp.h  2013-07-04 09:29:28 +0000
+++ src/lisp.h  2013-07-06 07:04:07 +0000
@@ -3668,7 +3668,6 @@
 extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object),
                          Lisp_Object);
 extern void dir_warning (const char *, Lisp_Object);
-extern void close_load_descs (void);
 extern void init_obarray (void);
 extern void init_lread (void);
 extern void syms_of_lread (void);
@@ -3995,7 +3994,6 @@
 extern void add_gpm_wait_descriptor (int);
 extern void delete_gpm_wait_descriptor (int);
 #endif
-extern void close_process_descs (void);
 extern void init_process_emacs (void);
 extern void syms_of_process (void);
 extern void setup_process_coding_systems (Lisp_Object);

=== modified file 'src/lread.c'
--- src/lread.c 2013-07-06 07:02:40 +0000
+++ src/lread.c 2013-07-06 07:05:58 +0000
@@ -95,9 +95,6 @@
    It must be set to nil before all top-level calls to read0.  */
 static Lisp_Object read_objects;
 
-/* List of descriptors now open for Fload.  */
-static Lisp_Object load_descriptor_list;
-
 /* File for get_file_char to read from.  Use by load.  */
 static FILE *instream;
 
@@ -149,7 +146,6 @@
                           Lisp_Object, Lisp_Object,
                           Lisp_Object, Lisp_Object);
 static Lisp_Object load_unwind (Lisp_Object);
-static Lisp_Object load_descriptor_unwind (Lisp_Object);
 
 /* Functions that read one byte from the current source READCHARFUN
    or unreads one byte.  If the integer argument C is -1, it returns
@@ -1328,11 +1324,8 @@
     }
 
   record_unwind_protect (load_unwind, make_save_pointer (stream));
-  record_unwind_protect (load_descriptor_unwind, load_descriptor_list);
   specbind (Qload_file_name, found);
   specbind (Qinhibit_file_name_operation, Qnil);
-  load_descriptor_list
-    = Fcons (make_number (fileno (stream)), load_descriptor_list);
   specbind (Qload_in_progress, Qt);
 
   instream = stream;
@@ -1395,26 +1388,6 @@
     }
   return Qnil;
 }
-
-static Lisp_Object
-load_descriptor_unwind (Lisp_Object oldlist)
-{
-  load_descriptor_list = oldlist;
-  return Qnil;
-}
-
-/* Close all descriptors in use for Floads.
-   This is used when starting a subprocess.  */
-
-void
-close_load_descs (void)
-{
-#ifndef WINDOWSNT
-  Lisp_Object tail;
-  for (tail = load_descriptor_list; CONSP (tail); tail = XCDR (tail))
-    emacs_close (XFASTINT (XCAR (tail)));
-#endif
-}
 
 static bool
 complete_filename_p (Lisp_Object pathname)
@@ -4349,9 +4322,6 @@
 
   load_in_progress = 0;
   Vload_file_name = Qnil;
-
-  load_descriptor_list = Qnil;
-
   Vstandard_input = Qt;
   Vloads_in_progress = Qnil;
 }
@@ -4624,9 +4594,6 @@
 
   /* Vsource_directory was initialized in init_lread.  */
 
-  load_descriptor_list = Qnil;
-  staticpro (&load_descriptor_list);
-
   DEFSYM (Qcurrent_load_list, "current-load-list");
   DEFSYM (Qstandard_input, "standard-input");
   DEFSYM (Qread_char, "read-char");

=== modified file 'src/nsterm.m'
--- src/nsterm.m        2013-06-27 14:47:52 +0000
+++ src/nsterm.m        2013-07-06 07:04:07 +0000
@@ -4142,7 +4142,7 @@
 
   if (selfds[0] == -1)
     {
-      if (pipe (selfds) == -1)
+      if (pipe2 (selfds, O_CLOEXEC) != 0)
         {
           fprintf (stderr, "Failed to create pipe: %s\n",
                    emacs_strerror (errno));

=== modified file 'src/process.c'
--- src/process.c       2013-07-05 16:58:01 +0000
+++ src/process.c       2013-07-06 09:07:02 +0000
@@ -135,6 +135,34 @@
                       EMACS_TIME *, void *);
 #endif
 
+#ifndef SOCK_CLOEXEC
+# define SOCK_CLOEXEC 0
+
+/* Emulate GNU/Linux accept4 and socket well enough for this module.  */
+
+static int
+close_on_exec (int fd)
+{
+  if (0 <= fd)
+    fcntl (fd, F_SETFD, FD_CLOEXEC);
+  return fd;
+}
+
+static int
+accept4 (int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)
+{
+  return close_on_exec (accept (sockfd, addr, addrlen));
+}
+
+static int
+process_socket (int domain, int type, int protocol)
+{
+  return close_on_exec (socket (domain, type, protocol));
+}
+# undef socket
+# define socket(domain, type, protocol) process_socket (domain, type, protocol)
+#endif
+
 /* Work around GCC 4.7.0 bug with strict overflow checking; see
    <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52904>.
    These lines can be removed once the GCC bug is fixed.  */
@@ -1619,14 +1647,11 @@
   else
 #endif /* HAVE_PTYS */
     {
-      int tem;
-      tem = pipe (sv);
-      if (tem < 0)
+      if (pipe2 (sv, O_CLOEXEC) != 0)
        report_file_error ("Creating pipe", Qnil);
       inchannel = sv[0];
       forkout = sv[1];
-      tem = pipe (sv);
-      if (tem < 0)
+      if (pipe2 (sv, O_CLOEXEC) != 0)
        {
          emacs_close (inchannel);
          emacs_close (forkout);
@@ -1637,29 +1662,14 @@
     }
 
 #ifndef WINDOWSNT
-    {
-      int tem;
-
-      tem = pipe (wait_child_setup);
-      if (tem < 0)
-       report_file_error ("Creating pipe", Qnil);
-      tem = fcntl (wait_child_setup[1], F_GETFD, 0);
-      if (tem >= 0)
-       tem = fcntl (wait_child_setup[1], F_SETFD, tem | FD_CLOEXEC);
-      if (tem < 0)
-       {
-         emacs_close (wait_child_setup[0]);
-         emacs_close (wait_child_setup[1]);
-         report_file_error ("Setting file descriptor flags", Qnil);
-       }
-    }
+  if (pipe2 (wait_child_setup, O_CLOEXEC) != 0)
+    report_file_error ("Creating pipe", Qnil);
 #endif
 
   fcntl (inchannel, F_SETFL, O_NONBLOCK);
   fcntl (outchannel, F_SETFL, O_NONBLOCK);
 
-  /* Record this as an active process, with its channels.
-     As a result, child_setup will close Emacs's side of the pipes.  */
+  /* Record this as an active process, with its channels.  */
   chan_process[inchannel] = process;
   XPROCESS (process)->infd = inchannel;
   XPROCESS (process)->outfd = outchannel;
@@ -3135,7 +3145,8 @@
     retry_connect:
 #endif
 
-      s = socket (lres->ai_family, lres->ai_socktype, lres->ai_protocol);
+      s = socket (lres->ai_family, lres->ai_socktype | SOCK_CLOEXEC,
+                 lres->ai_protocol);
       if (s < 0)
        {
          xerrno = errno;
@@ -3532,7 +3543,7 @@
   int s;
   Lisp_Object res;
 
-  s = socket (AF_INET, SOCK_STREAM, 0);
+  s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
   if (s < 0)
     return Qnil;
 
@@ -3688,7 +3699,7 @@
     error ("interface name too long");
   strcpy (rq.ifr_name, SSDATA (ifname));
 
-  s = socket (AF_INET, SOCK_STREAM, 0);
+  s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
   if (s < 0)
     return Qnil;
 
@@ -3984,7 +3995,7 @@
   } saddr;
   socklen_t len = sizeof saddr;
 
-  s = accept (channel, &saddr.sa, &len);
+  s = accept4 (channel, &saddr.sa, &len, SOCK_CLOEXEC);
 
   if (s < 0)
     {
@@ -6858,32 +6869,6 @@
 #endif
 }
 
-/* Close all descriptors currently in use for communication
-   with subprocess.  This is used in a newly-forked subprocess
-   to get rid of irrelevant descriptors.  */
-
-void
-close_process_descs (void)
-{
-#ifndef DOS_NT
-  int i;
-  for (i = 0; i < MAXDESC; i++)
-    {
-      Lisp_Object process;
-      process = chan_process[i];
-      if (!NILP (process))
-       {
-         int in  = XPROCESS (process)->infd;
-         int out = XPROCESS (process)->outfd;
-         if (in >= 0)
-           emacs_close (in);
-         if (out >= 0 && in != out)
-           emacs_close (out);
-       }
-    }
-#endif
-}
-
 DEFUN ("get-buffer-process", Fget_buffer_process, Sget_buffer_process, 1, 1, 0,
        doc: /* Return the (or a) process associated with BUFFER.
 BUFFER may be a buffer or the name of one.  */)

=== modified file 'src/sysdep.c'
--- src/sysdep.c        2013-07-06 07:02:40 +0000
+++ src/sysdep.c        2013-07-06 07:05:58 +0000
@@ -543,8 +543,6 @@
 #endif
        }
 
-      close_process_descs ();  /* Close Emacs's pipes/ptys */
-
 #ifdef MSDOS    /* Demacs 1.1.2 91/10/20 Manabu Higashida */
       {
        char *epwd = getenv ("PWD");
@@ -2152,6 +2150,8 @@
 #endif
 
 /* Open FILE for Emacs use, using open flags OFLAG and mode MODE.
+   Arrange for subprograms to not inherit the file descriptor.
+   Prefer a method that is multithread-safe, if available.
    Do not fail merely because the open was interrupted by a signal.
    Allow the user to quit.  */
 
@@ -2159,8 +2159,11 @@
 emacs_open (const char *file, int oflags, int mode)
 {
   int fd;
+  oflags |= O_CLOEXEC;
   while ((fd = open (file, oflags, mode)) < 0 && errno == EINTR)
     QUIT;
+  if (! O_CLOEXEC && 0 <= fd)
+    fcntl (fd, F_SETFD, FD_CLOEXEC);
   return fd;
 }
 
@@ -2170,10 +2173,29 @@
 FILE *
 emacs_fopen (char const *file, char const *mode)
 {
-  FILE *fp;
-  while (! (fp = fopen (file, mode)) && errno == EINTR)
-    QUIT;
-  return fp;
+  int fd, omode, oflags;
+  int bflag = 0;
+  char const *m = mode;
+
+  switch (*m++)
+    {
+    case 'r': omode = O_RDONLY; oflags = 0; break;
+    case 'w': omode = O_WRONLY; oflags = O_CREAT | O_TRUNC; break;
+    case 'a': omode = O_WRONLY; oflags = O_CREAT | O_APPEND; break;
+    default: emacs_abort ();
+    }
+
+  while (*m)
+    switch (*m++)
+      {
+      case '+': omode = O_RDWR; break;
+      case 'b': bflag = O_BINARY; break;
+      case 't': bflag = O_TEXT; break;
+      default: /* Ignore.  */ break;
+      }
+
+  fd = emacs_open (file, omode | oflags | bflag, 0666);
+  return fd < 0 ? 0 : fdopen (fd, mode);
 }
 
 int






reply via email to

[Prev in Thread] Current Thread [Next in Thread]