Commit 1af19a96 authored by Stiopa Koltsov's avatar Stiopa Koltsov Committed by Facebook GitHub Bot

File::dupCloseOnExec()

Summary:
Close-on-exec is an important feature to avoid leaking file descriptors to spawned processes.

This diff adds `File::dupCloseOnExec()` function which is equivalent to `File::dup` function, but sets close-on-exec flag where supported (i. e. everywhere except Windows).

Practically most users want to have `closeOnExec = true` by default, but we need to preserve backwards compatibility, thus this diff leaves `dup` function as is.

Reviewed By: yfeldblum

Differential Revision: D27495214

fbshipit-source-id: 540deb2bc6c8fec626a0120bc20c345950dc8af7
parent 03fa494f
...@@ -80,6 +80,7 @@ File::~File() { ...@@ -80,6 +80,7 @@ File::~File() {
checkFopenError(tmpFile, "tmpfile() failed"); checkFopenError(tmpFile, "tmpfile() failed");
SCOPE_EXIT { fclose(tmpFile); }; SCOPE_EXIT { fclose(tmpFile); };
// TODO(nga): consider setting close-on-exec for the resulting FD
int fd = ::dup(fileno(tmpFile)); int fd = ::dup(fileno(tmpFile));
checkUnixError(fd, "dup() failed"); checkUnixError(fd, "dup() failed");
...@@ -114,6 +115,22 @@ File File::dup() const { ...@@ -114,6 +115,22 @@ File File::dup() const {
return File(); return File();
} }
File File::dupCloseOnExec() const {
if (fd_ != -1) {
int fd;
#ifdef _WIN32
fd = ::dup(fd_);
#else
fd = ::fcntl(fd_, F_DUPFD_CLOEXEC, 0);
#endif
checkUnixError(fd, "dup() failed");
return File(fd, true);
}
return File();
}
void File::close() { void File::close() {
if (!closeNoThrow()) { if (!closeNoThrow()) {
throwSystemError("close() failed"); throwSystemError("close() failed");
......
...@@ -89,9 +89,20 @@ class File { ...@@ -89,9 +89,20 @@ class File {
/** /**
* Duplicate file descriptor and return File that owns it. * Duplicate file descriptor and return File that owns it.
*
* Duplicated file descriptor does not have close-on-exec flag set,
* so it is leaked to child processes. Consider using "dupCloseOnExec".
*/ */
File dup() const; File dup() const;
/**
* Duplicate file descriptor and return File that owns it.
*
* This functions creates a descriptor with close-on-exec flag set
* (where supported, otherwise it is equivalent to "dup").
*/
File dupCloseOnExec() const;
/** /**
* If we own the file descriptor, close the file and throw on error. * If we own the file descriptor, close the file and throw on error.
* Otherwise, do nothing. * Otherwise, do nothing.
......
...@@ -166,6 +166,26 @@ TEST(File, Truthy) { ...@@ -166,6 +166,26 @@ TEST(File, Truthy) {
} }
} }
TEST(File, Dup) {
auto f = File::temporary();
auto d = f.dup();
#ifndef _WIN32
EXPECT_EQ(::fcntl(d.fd(), F_GETFD, 0) & FD_CLOEXEC, 0);
#endif
(void)d;
}
TEST(File, DupCloseOnExec) {
auto f = File::temporary();
auto d = f.dupCloseOnExec();
#ifndef _WIN32
EXPECT_EQ(::fcntl(d.fd(), F_GETFD, 0) & FD_CLOEXEC, FD_CLOEXEC);
#endif
(void)d;
}
TEST(File, HelperCtor) { TEST(File, HelperCtor) {
TempDir tmpd; TempDir tmpd;
auto tmpf = tmpd.path / "foobar.txt"; auto tmpf = tmpd.path / "foobar.txt";
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment