summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-29 17:51:51 +0000
committerjeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-29 17:51:51 +0000
commit05d4b0ae3154d410443f5ac5d6f74c970ce8d700 (patch)
tree32662f7f9bbb25f81123fb7e34b8bd177d39f161
parent3216fbdae4d6887bc87240879530fb9f688d013b (diff)
downloadchromium_src-05d4b0ae3154d410443f5ac5d6f74c970ce8d700.zip
chromium_src-05d4b0ae3154d410443f5ac5d6f74c970ce8d700.tar.gz
chromium_src-05d4b0ae3154d410443f5ac5d6f74c970ce8d700.tar.bz2
Add routine to close file descriptors on exec
for linux and mac. See BUG 6598. Review URL: http://codereview.chromium.org/18801 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8892 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/process_util.h6
-rw-r--r--base/process_util_linux.cc8
-rw-r--r--base/process_util_mac.mm8
-rw-r--r--base/process_util_posix.cc57
-rw-r--r--base/process_util_unittest.cc18
5 files changed, 66 insertions, 31 deletions
diff --git a/base/process_util.h b/base/process_util.h
index f00016e..ec858bd 100644
--- a/base/process_util.h
+++ b/base/process_util.h
@@ -67,9 +67,9 @@ ProcessHandle GetCurrentProcessHandle();
int GetProcId(ProcessHandle process);
#if defined(OS_POSIX)
-// Returns the maximum number of files that a process can have open.
-// Returns 0 on error.
-int GetMaxFilesOpenInProcess();
+// Sets all file descriptors to close on exec except for stdin, stdout
+// and stderr.
+void SetAllFDsToCloseOnExec();
#endif
#if defined(OS_WIN)
diff --git a/base/process_util_linux.cc b/base/process_util_linux.cc
index d53b2c7..8f83212 100644
--- a/base/process_util_linux.cc
+++ b/base/process_util_linux.cc
@@ -44,13 +44,7 @@ bool LaunchApp(const std::vector<std::string>& argv,
// Make sure we don't leak any FDs to the child process by marking all FDs
// as close-on-exec.
- int max_files = GetMaxFilesOpenInProcess();
- for (int i = STDERR_FILENO + 1; i < max_files; i++) {
- int flags = fcntl(i, F_GETFD);
- if (flags != -1) {
- fcntl(i, F_SETFD, flags | FD_CLOEXEC);
- }
- }
+ SetAllFDsToCloseOnExec();
int pid = fork();
if (pid == 0) {
diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm
index 330e8b2..a52f608 100644
--- a/base/process_util_mac.mm
+++ b/base/process_util_mac.mm
@@ -31,13 +31,7 @@ bool LaunchApp(const std::vector<std::string>& argv,
// Make sure we don't leak any FDs to the child process by marking all FDs
// as close-on-exec.
- int max_files = GetMaxFilesOpenInProcess();
- for (int i = STDERR_FILENO + 1; i < max_files; i++) {
- int flags = fcntl(i, F_GETFD);
- if (flags != -1) {
- fcntl(i, F_SETFD, flags | FD_CLOEXEC);
- }
- }
+ SetAllFDsToCloseOnExec();
posix_spawn_file_actions_t file_actions;
if (posix_spawn_file_actions_init(&file_actions) != 0) {
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc
index 87a4e36..d8fefca 100644
--- a/base/process_util_posix.cc
+++ b/base/process_util_posix.cc
@@ -2,19 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/process_util.h"
-
+#include <dirent.h>
#include <errno.h>
+#include <fcntl.h>
#include <signal.h>
+#include <stdlib.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
+
#include <limits>
#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/process_util.h"
#include "base/sys_info.h"
#include "base/time.h"
@@ -58,21 +61,47 @@ bool KillProcess(int process_id, int exit_code, bool wait) {
return result;
}
-int GetMaxFilesOpenInProcess() {
- struct rlimit rlimit;
- if (getrlimit(RLIMIT_NOFILE, &rlimit) != 0) {
- return 0;
+// A class to handle auto-closing of DIR*'s.
+class ScopedDIRClose {
+ public:
+ inline void operator()(DIR* x) const {
+ if (x) {
+ closedir(x);
+ }
}
-
- // rlim_t is a uint64 - clip to maxint.
- // We do this since we use the value of this function to close FD #s in a loop
- // if we didn't clamp the value, doing this would be too time consuming.
- rlim_t max_int = static_cast<rlim_t>(std::numeric_limits<int32>::max());
- if (rlimit.rlim_cur > max_int) {
- return max_int;
+};
+typedef scoped_ptr_malloc<DIR, ScopedDIRClose> ScopedDIR;
+
+// Sets all file descriptors to close on exec except for stdin, stdout
+// and stderr.
+void SetAllFDsToCloseOnExec() {
+#if defined(OS_LINUX)
+ const char fd_dir[] = "/proc/self/fd";
+#elif defined(OS_MACOSX)
+ const char fd_dir[] = "/dev/fd";
+#endif
+ ScopedDIR dir_closer(opendir(fd_dir));
+ DIR *dir = dir_closer.get();
+ if (NULL == dir) {
+ DLOG(ERROR) << "Unable to open " << fd_dir;
+ return;
}
- return rlimit.rlim_cur;
+ struct dirent *ent;
+ while ((ent = readdir(dir))) {
+ // Skip . and .. entries.
+ if (ent->d_name[0] == '.')
+ continue;
+ int i = atoi(ent->d_name);
+ // We don't close stdin, stdout or stderr.
+ if (i <= STDERR_FILENO)
+ continue;
+
+ int flags = fcntl(i, F_GETFD);
+ if ((flags == -1) || (fcntl(i, F_SETFD, flags | FD_CLOEXEC) == -1)) {
+ DLOG(ERROR) << "fcntl failure.";
+ }
+ }
}
ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process),
diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc
index a6eb8a7..0b3bc21 100644
--- a/base/process_util_unittest.cc
+++ b/base/process_util_unittest.cc
@@ -142,6 +142,24 @@ TEST_F(ProcessUtilTest, CalcFreeMemory) {
#endif // defined(OS_WIN)
#if defined(OS_POSIX)
+// Returns the maximum number of files that a process can have open.
+// Returns 0 on error.
+int GetMaxFilesOpenInProcess() {
+ struct rlimit rlim;
+ if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
+ return 0;
+ }
+
+ // rlim_t is a uint64 - clip to maxint. We do this since FD #s are ints
+ // which are all 32 bits on the supported platforms.
+ rlim_t max_int = static_cast<rlim_t>(std::numeric_limits<int32>::max());
+ if (rlim.rlim_cur > max_int) {
+ return max_int;
+ }
+
+ return rlim.rlim_cur;
+}
+
const int kChildPipe = 20; // FD # for write end of pipe in child process.
MULTIPROCESS_TEST_MAIN(ProcessUtilsLeakFDChildProcess) {
// This child process counts the number of open FDs, it then writes that