aboutsummaryrefslogtreecommitdiff
path: root/butl
diff options
context:
space:
mode:
Diffstat (limited to 'butl')
-rw-r--r--butl/fdstream20
-rw-r--r--butl/fdstream.cxx23
-rw-r--r--butl/process.cxx2
3 files changed, 42 insertions, 3 deletions
diff --git a/butl/fdstream b/butl/fdstream
index 8d01b2f..8d6385f 100644
--- a/butl/fdstream
+++ b/butl/fdstream
@@ -486,6 +486,9 @@ namespace butl
// process' umask, so effective permissions are permissions & ~umask. On
// Windows permissions other than ru and wu are unlikelly to have effect.
//
+ // Also note that on POSIX the FD_CLOEXEC flag is set for the file descriptor
+ // to prevent its leakage into child processes.
+ //
LIBBUTL_EXPORT auto_fd
fdopen (const char*,
fdopen_mode,
@@ -510,6 +513,13 @@ namespace butl
// Duplicate an open file descriptor. Throw ios::failure on the underlying
// OS error.
//
+ // Note that on POSIX the FD_CLOEXEC flag is set for the new descriptor if it
+ // is present for the source one. That's in contrast to POSIX dup() that
+ // doesn't copy file descriptor flags. Also note that duplicating descriptor
+ // and setting the flag is not an atomic operation.
+ //
+ // @@ Should we copy HANDLE_FLAG_INHERIT flag on Windows as well?
+ //
LIBBUTL_EXPORT auto_fd
fddup (int fd);
@@ -563,6 +573,9 @@ namespace butl
// closed. One difference, however, would be if you were to both write to
// and read from the descriptor.
//
+ // Note that on POSIX the FD_CLOEXEC flag is set for the file descriptor to
+ // prevent its leakage into child processes.
+ //
// @@ You may have noticed that this interface doesn't match fdopen() (it
// does not throw and return int instead of auto_fd). The reason for this
// is process and its need to translate everything to process_error).
@@ -591,6 +604,13 @@ namespace butl
// In particular, the process class that uses fdpipe underneath makes the
// appropriate end of pipe (the one being passed to the child) inheritable.
//
+ // Note that on POSIX the FD_CLOEXEC flag is set for both ends, so they get
+ // automatically closed by the child process to prevent undesired behaviors
+ // (such as child deadlock on read from a pipe due to the write-end leakage
+ // into the child process). Opening pipe and setting the flag is not an
+ // atomic operation. Also note that you don't need to reset the flag for a
+ // pipe end being passed to the process class ctor.
+ //
LIBBUTL_EXPORT fdpipe
fdopen_pipe (fdopen_mode = fdopen_mode::none);
}
diff --git a/butl/fdstream.cxx b/butl/fdstream.cxx
index 370a75e..e28eb0f 100644
--- a/butl/fdstream.cxx
+++ b/butl/fdstream.cxx
@@ -658,7 +658,7 @@ namespace butl
of |= O_LARGEFILE;
#endif
- int fd (open (f, of, pf));
+ int fd (open (f, of | O_CLOEXEC, pf));
#else
@@ -745,6 +745,18 @@ namespace butl
{
#ifndef _WIN32
int nfd (dup (fd));
+
+ int f (fcntl (fd, F_GETFD));
+ if (f == -1)
+ throw_ios_failure (errno);
+
+ if ((f & FD_CLOEXEC) != 0)
+ {
+ f = fcntl (nfd, F_GETFD);
+ if (f == -1 || fcntl (nfd, F_SETFD, f | FD_CLOEXEC) == -1)
+ throw_ios_failure (errno);
+ }
+
#else
int nfd (_dup (fd));
#endif
@@ -766,7 +778,7 @@ namespace butl
int
fdnull () noexcept
{
- return open ("/dev/null", O_RDWR);
+ return open ("/dev/null", O_RDWR | O_CLOEXEC);
}
fdstream_mode
@@ -829,6 +841,13 @@ namespace butl
if (pipe (pd) == -1)
throw_ios_failure (errno);
+ for (size_t i (0); i < 2; ++i)
+ {
+ int f (fcntl (pd[i], F_GETFD));
+ if (f == -1 || fcntl (pd[i], F_SETFD, f | FD_CLOEXEC) == -1)
+ throw_ios_failure (errno);
+ }
+
return {auto_fd (pd[0]), auto_fd (pd[1])};
}
diff --git a/butl/process.cxx b/butl/process.cxx
index 526966e..892e930 100644
--- a/butl/process.cxx
+++ b/butl/process.cxx
@@ -865,7 +865,7 @@ namespace butl
// Resolve file descriptor to HANDLE and make sure it is inherited. Note
// that the handle is closed either when CloseHandle() is called for it or
// when _close() is called for the associated file descriptor. Make sure
- // that either the original file descriptor or the resulted HANDLE is
+ // that either the original file descriptor or the resulting HANDLE is
// closed but not both of them.
//
auto get_osfhandle = [&fail](int fd) -> HANDLE