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() {
checkFopenError(tmpFile, "tmpfile() failed");
SCOPE_EXIT { fclose(tmpFile); };
// TODO(nga): consider setting close-on-exec for the resulting FD
int fd = ::dup(fileno(tmpFile));
checkUnixError(fd, "dup() failed");
......@@ -114,6 +115,22 @@ File File::dup() const {
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() {
if (!closeNoThrow()) {
throwSystemError("close() failed");
......
......@@ -89,9 +89,20 @@ class File {
/**
* 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;
/**
* 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.
* Otherwise, do nothing.
......
......@@ -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) {
TempDir tmpd;
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