Skip to content

Commit

Permalink
Upgrade the windows specific version of LaunchProcess to avoid raw ha…
Browse files Browse the repository at this point in the history
…ndles.

This change implies that extensions::LaunchNativeProcess also changes to
return base::Process, and that requires base::EnsureProcessTerminated to
deal with base:Process (as it basically claims ownership of the process).

This CL fixes some leaks all around.

BUG=417532

Review URL: https://codereview.chromium.org/759903002

Cr-Commit-Position: refs/heads/master@{#306687}
  • Loading branch information
rvargas authored and Commit bot committed Dec 3, 2014
1 parent e77e1c6 commit 6b687a5
Show file tree
Hide file tree
Showing 26 changed files with 107 additions and 100 deletions.
7 changes: 4 additions & 3 deletions base/process/kill.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#define BASE_PROCESS_KILL_H_

#include "base/files/file_path.h"
#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "base/time/time.h"

Expand Down Expand Up @@ -146,10 +147,10 @@ BASE_EXPORT bool CleanupProcesses(const FilePath::StringType& executable_name,
// On Linux this method does not block the calling thread.
// On OS X this method may block for up to 2 seconds.
//
// NOTE: The process handle must have been opened with the PROCESS_TERMINATE
// and SYNCHRONIZE permissions.
// NOTE: The process must have been opened with the PROCESS_TERMINATE and
// SYNCHRONIZE permissions.
//
BASE_EXPORT void EnsureProcessTerminated(ProcessHandle process_handle);
BASE_EXPORT void EnsureProcessTerminated(Process process);

#if defined(OS_POSIX) && !defined(OS_MACOSX)
// The nicer version of EnsureProcessTerminated() that is patient and will
Expand Down
4 changes: 2 additions & 2 deletions base/process/kill_mac.cc
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,8 @@ void WaitForChildToDie(pid_t child, int timeout) {

} // namespace

void EnsureProcessTerminated(ProcessHandle process) {
WaitForChildToDie(process, kWaitBeforeKillSeconds);
void EnsureProcessTerminated(Process process) {
WaitForChildToDie(process.pid(), kWaitBeforeKillSeconds);
}

} // namespace base
6 changes: 3 additions & 3 deletions base/process/kill_posix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -463,13 +463,13 @@ class BackgroundReaper : public PlatformThread::Delegate {

} // namespace

void EnsureProcessTerminated(ProcessHandle process) {
void EnsureProcessTerminated(Process process) {
// If the child is already dead, then there's nothing to do.
if (IsChildDead(process))
if (IsChildDead(process.pid()))
return;

const unsigned timeout = 2; // seconds
BackgroundReaper* reaper = new BackgroundReaper(process, timeout);
BackgroundReaper* reaper = new BackgroundReaper(process.pid(), timeout);
PlatformThread::CreateNonJoinable(0, reaper);
}

Expand Down
27 changes: 12 additions & 15 deletions base/process/kill_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ static const int kWaitInterval = 2000;

class TimerExpiredTask : public win::ObjectWatcher::Delegate {
public:
explicit TimerExpiredTask(ProcessHandle process);
explicit TimerExpiredTask(Process process);
~TimerExpiredTask();

void TimedOut();
Expand All @@ -50,24 +50,23 @@ class TimerExpiredTask : public win::ObjectWatcher::Delegate {
void KillProcess();

// The process that we are watching.
ProcessHandle process_;
Process process_;

win::ObjectWatcher watcher_;

DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask);
};

TimerExpiredTask::TimerExpiredTask(ProcessHandle process) : process_(process) {
watcher_.StartWatching(process_, this);
TimerExpiredTask::TimerExpiredTask(Process process) : process_(process.Pass()) {
watcher_.StartWatching(process_.Handle(), this);
}

TimerExpiredTask::~TimerExpiredTask() {
TimedOut();
DCHECK(!process_) << "Make sure to close the handle.";
}

void TimerExpiredTask::TimedOut() {
if (process_)
if (process_.IsValid())
KillProcess();
}

Expand All @@ -76,8 +75,7 @@ void TimerExpiredTask::OnObjectSignaled(HANDLE object) {
tracked_objects::ScopedTracker tracking_profile(
FROM_HERE_WITH_EXPLICIT_FUNCTION("TimerExpiredTask_OnObjectSignaled"));

CloseHandle(process_);
process_ = NULL;
process_.Close();
}

void TimerExpiredTask::KillProcess() {
Expand All @@ -88,10 +86,10 @@ void TimerExpiredTask::KillProcess() {
// terminates. We just care that it eventually terminates, and that's what
// TerminateProcess should do for us. Don't check for the result code since
// it fails quite often. This should be investigated eventually.
base::KillProcess(process_, kProcessKilledExitCode, false);
base::KillProcess(process_.Handle(), kProcessKilledExitCode, false);

// Now, just cleanup as if the process exited normally.
OnObjectSignaled(process_);
OnObjectSignaled(process_.Handle());
}

} // namespace
Expand Down Expand Up @@ -241,19 +239,18 @@ bool CleanupProcesses(const FilePath::StringType& executable_name,
return false;
}

void EnsureProcessTerminated(ProcessHandle process) {
DCHECK(process != GetCurrentProcess());
void EnsureProcessTerminated(Process process) {
DCHECK(!process.is_current());

// If already signaled, then we are done!
if (WaitForSingleObject(process, 0) == WAIT_OBJECT_0) {
CloseHandle(process);
if (WaitForSingleObject(process.Handle(), 0) == WAIT_OBJECT_0) {
return;
}

MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&TimerExpiredTask::TimedOut,
base::Owned(new TimerExpiredTask(process))),
base::Owned(new TimerExpiredTask(process.Pass()))),
base::TimeDelta::FromMilliseconds(kWaitInterval));
}

Expand Down
6 changes: 2 additions & 4 deletions base/process/launch.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include "base/posix/file_descriptor_shuffle.h"
#elif defined(OS_WIN)
#include <windows.h>
#include "base/win/scoped_handle.h"
#endif

namespace base {
Expand Down Expand Up @@ -174,9 +173,8 @@ BASE_EXPORT bool LaunchProcess(const CommandLine& cmdline,
//
// Example (including literal quotes)
// cmdline = "c:\windows\explorer.exe" -foo "c:\bar\"
BASE_EXPORT bool LaunchProcess(const string16& cmdline,
const LaunchOptions& options,
win::ScopedHandle* process_handle);
BASE_EXPORT Process LaunchProcess(const string16& cmdline,
const LaunchOptions& options);

// Launches a process with elevated privileges. This does not behave exactly
// like LaunchProcess as it uses ShellExecuteEx instead of CreateProcess to
Expand Down
11 changes: 11 additions & 0 deletions base/process/launch_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,17 @@ bool LaunchProcess(const string16& cmdline,
return true;
}

// TODO(rvargas) crbug.com/416721: Remove this stub after LaunchProcess is
// fully migrated to use Process.
Process LaunchProcess(const string16& cmdline,
const LaunchOptions& options) {
win::ScopedHandle process_handle;
if (LaunchProcess(cmdline, options, &process_handle))
return Process(process_handle.Take());

return Process();
}

bool LaunchProcess(const CommandLine& cmdline,
const LaunchOptions& options,
ProcessHandle* process_handle) {
Expand Down
22 changes: 10 additions & 12 deletions base/process/process_util_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -888,14 +888,14 @@ bool IsProcessDead(base::ProcessHandle child) {
}

TEST_F(ProcessUtilTest, DelayedTermination) {
base::ProcessHandle child_process = SpawnChild("process_util_test_never_die");
ASSERT_TRUE(child_process);
base::EnsureProcessTerminated(child_process);
base::WaitForSingleProcess(child_process, base::TimeDelta::FromSeconds(5));
base::Process child_process(SpawnChild("process_util_test_never_die"));
ASSERT_TRUE(child_process.IsValid());
base::EnsureProcessTerminated(child_process.Duplicate());
base::WaitForSingleProcess(child_process.Handle(),
base::TimeDelta::FromSeconds(5));

// Check that process was really killed.
EXPECT_TRUE(IsProcessDead(child_process));
base::CloseProcessHandle(child_process);
EXPECT_TRUE(IsProcessDead(child_process.Handle()));
}

MULTIPROCESS_TEST_MAIN(process_util_test_never_die) {
Expand All @@ -906,16 +906,14 @@ MULTIPROCESS_TEST_MAIN(process_util_test_never_die) {
}

TEST_F(ProcessUtilTest, ImmediateTermination) {
base::ProcessHandle child_process =
SpawnChild("process_util_test_die_immediately");
ASSERT_TRUE(child_process);
base::Process child_process(SpawnChild("process_util_test_die_immediately"));
ASSERT_TRUE(child_process.IsValid());
// Give it time to die.
sleep(2);
base::EnsureProcessTerminated(child_process);
base::EnsureProcessTerminated(child_process.Duplicate());

// Check that process was really killed.
EXPECT_TRUE(IsProcessDead(child_process));
base::CloseProcessHandle(child_process);
EXPECT_TRUE(IsProcessDead(child_process.Handle()));
}

MULTIPROCESS_TEST_MAIN(process_util_test_die_immediately) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ NativeMessageProcessHost::NativeMessageProcessHost(
native_host_name_(native_host_name),
launcher_(launcher.Pass()),
closed_(false),
process_handle_(base::kNullProcessHandle),
#if defined(OS_POSIX)
read_file_(-1),
#endif
Expand Down Expand Up @@ -103,7 +102,7 @@ void NativeMessageProcessHost::LaunchHostProcess() {

void NativeMessageProcessHost::OnHostProcessLaunched(
NativeProcessLauncher::LaunchResult result,
base::ProcessHandle process_handle,
base::Process process,
base::File read_file,
base::File write_file) {
DCHECK(task_runner_->BelongsToCurrentThread());
Expand All @@ -125,7 +124,7 @@ void NativeMessageProcessHost::OnHostProcessLaunched(
break;
}

process_handle_ = process_handle;
process_ = process.Pass();
#if defined(OS_POSIX)
// This object is not the owner of the file so it should not keep an fd.
read_file_ = read_file.GetPlatformFile();
Expand Down Expand Up @@ -349,17 +348,17 @@ void NativeMessageProcessHost::Close(const std::string& error_message) {
client_->CloseChannel(error_message);
}

if (process_handle_ != base::kNullProcessHandle) {
if (process_.IsValid()) {
// Kill the host process if necessary to make sure we don't leave zombies.
// On OSX base::EnsureProcessTerminated() may block, so we have to post a
// task on the blocking pool.
#if defined(OS_MACOSX)
content::BrowserThread::PostBlockingPoolTask(
FROM_HERE, base::Bind(&base::EnsureProcessTerminated, process_handle_));
FROM_HERE,
base::Bind(&base::EnsureProcessTerminated, Passed(&process_)));
#else
base::EnsureProcessTerminated(process_handle_);
base::EnsureProcessTerminated(process_.Pass());
#endif
process_handle_ = base::kNullProcessHandle;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class NativeMessageProcessHost :

// Callback for NativeProcessLauncher::Launch().
void OnHostProcessLaunched(NativeProcessLauncher::LaunchResult result,
base::ProcessHandle process_handle,
base::Process process,
base::File read_file,
base::File write_file);

Expand Down Expand Up @@ -108,7 +108,7 @@ class NativeMessageProcessHost :
// due to an error.
bool closed_;

base::ProcessHandle process_handle_;
base::Process process_;

// Input stream reader.
scoped_ptr<net::FileStream> read_stream_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,7 @@ class FakeLauncher : public NativeProcessLauncher {
const std::string& native_host_name,
LaunchedCallback callback) const override {
callback.Run(NativeProcessLauncher::RESULT_SUCCESS,
base::kNullProcessHandle,
read_file_.Pass(), write_file_.Pass());
base::Process(), read_file_.Pass(), write_file_.Pass());
}

private:
Expand Down
22 changes: 11 additions & 11 deletions chrome/browser/extensions/api/messaging/native_process_launcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ class NativeProcessLauncherImpl : public NativeProcessLauncher {
LaunchedCallback callback);
void PostErrorResult(const LaunchedCallback& callback, LaunchResult error);
void PostResult(const LaunchedCallback& callback,
base::ProcessHandle process_handle,
base::Process process,
base::File read_file,
base::File write_file);
void CallCallbackOnIOThread(LaunchedCallback callback,
LaunchResult result,
base::ProcessHandle process_handle,
base::Process process,
base::File read_file,
base::File write_file);

Expand Down Expand Up @@ -192,12 +192,12 @@ void NativeProcessLauncherImpl::Core::DoLaunchOnThreadPool(
base::Int64ToString(window_handle_));
#endif // !defined(OS_WIN)

base::ProcessHandle process_handle;
base::Process process;
base::File read_file;
base::File write_file;
if (NativeProcessLauncher::LaunchNativeProcess(
command_line, &process_handle, &read_file, &write_file)) {
PostResult(callback, process_handle, read_file.Pass(), write_file.Pass());
command_line, &process, &read_file, &write_file)) {
PostResult(callback, process.Pass(), read_file.Pass(), write_file.Pass());
} else {
PostErrorResult(callback, RESULT_FAILED_TO_START);
}
Expand All @@ -206,14 +206,14 @@ void NativeProcessLauncherImpl::Core::DoLaunchOnThreadPool(
void NativeProcessLauncherImpl::Core::CallCallbackOnIOThread(
LaunchedCallback callback,
LaunchResult result,
base::ProcessHandle process_handle,
base::Process process,
base::File read_file,
base::File write_file) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (detached_)
return;

callback.Run(result, process_handle, read_file.Pass(), write_file.Pass());
callback.Run(result, process.Pass(), read_file.Pass(), write_file.Pass());
}

void NativeProcessLauncherImpl::Core::PostErrorResult(
Expand All @@ -222,20 +222,20 @@ void NativeProcessLauncherImpl::Core::PostErrorResult(
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&NativeProcessLauncherImpl::Core::CallCallbackOnIOThread, this,
callback, error, base::kNullProcessHandle,
callback, error, Passed(base::Process()),
Passed(base::File()), Passed(base::File())));
}

void NativeProcessLauncherImpl::Core::PostResult(
const LaunchedCallback& callback,
base::ProcessHandle process_handle,
base::Process process,
base::File read_file,
base::File write_file) {
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&NativeProcessLauncherImpl::Core::CallCallbackOnIOThread, this,
callback, RESULT_SUCCESS, process_handle,
Passed(read_file.Pass()), Passed(write_file.Pass())));
callback, RESULT_SUCCESS, Passed(&process),
Passed(&read_file), Passed(&write_file)));
}

NativeProcessLauncherImpl::NativeProcessLauncherImpl(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class NativeProcessLauncher {
// to false in case of a failure. Handler must take ownership of the IO
// handles.
typedef base::Callback<void(LaunchResult result,
base::ProcessHandle process_handle,
base::Process process,
base::File read_file,
base::File write_file)> LaunchedCallback;

Expand Down Expand Up @@ -68,7 +68,7 @@ class NativeProcessLauncher {

// Launches native messaging process.
static bool LaunchNativeProcess(const base::CommandLine& command_line,
base::ProcessHandle* process_handle,
base::Process* process,
base::File* read_file,
base::File* write_file);

Expand Down
Loading

0 comments on commit 6b687a5

Please sign in to comment.