diff options
-rw-r--r-- | base/process_util.h | 6 | ||||
-rw-r--r-- | base/process_util_linux.cc | 8 | ||||
-rw-r--r-- | base/process_util_mac.mm | 8 | ||||
-rw-r--r-- | base/process_util_posix.cc | 57 | ||||
-rw-r--r-- | base/process_util_unittest.cc | 18 |
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 |