crashpad/test/win/win_multiprocess_with_temp_dir.cc
Hans Wennborg 032f1aecc2 Include-what-you-use related to logging.h
Add direct includes for things provided transitively by logging.h
(or by other headers including logging.h).

This is in preparation for cleaning up unnecessary includes of
logging.h in header files (so if something depends on logging.h,
it needs include it explicitly), and for when Chromium's logging.h
no longer includes check.h, check_op.h, and notreached.h.

DEPS is also updated to roll mini_chromium to ae14a14ab4 which
includes these new header files.

Bug: chromium:1031540
Change-Id: I36f646d0a93854989dc602d0dc7139dd7a7b8621
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2250251
Commit-Queue: Hans Wennborg <hans@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
2020-06-18 13:51:20 +00:00

190 lines
6.1 KiB
C++

// Copyright 2017 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "test/win/win_multiprocess_with_temp_dir.h"
#include <tlhelp32.h>
#include "base/logging.h"
#include "test/errors.h"
#include "util/process/process_id.h"
#include "util/win/process_info.h"
namespace crashpad {
namespace test {
namespace {
constexpr wchar_t kTempDirEnvName[] = L"CRASHPAD_TEST_TEMP_DIR";
// Returns the process IDs of all processes that have |parent_pid| as
// parent process ID.
std::vector<ProcessID> GetPotentialChildProcessesOf(ProcessID parent_pid) {
ScopedFileHANDLE snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
if (!snapshot.is_valid()) {
ADD_FAILURE() << ErrorMessage("CreateToolhelp32Snapshot");
return std::vector<ProcessID>();
}
PROCESSENTRY32 entry = {sizeof(entry)};
if (!Process32First(snapshot.get(), &entry)) {
ADD_FAILURE() << ErrorMessage("Process32First");
return std::vector<ProcessID>();
}
std::vector<ProcessID> child_pids;
do {
if (entry.th32ParentProcessID == parent_pid)
child_pids.push_back(entry.th32ProcessID);
} while (Process32Next(snapshot.get(), &entry));
return child_pids;
}
ULARGE_INTEGER GetProcessCreationTime(HANDLE process) {
ULARGE_INTEGER ret = {};
FILETIME creation_time;
FILETIME dummy;
if (GetProcessTimes(process, &creation_time, &dummy, &dummy, &dummy)) {
ret.LowPart = creation_time.dwLowDateTime;
ret.HighPart = creation_time.dwHighDateTime;
} else {
ADD_FAILURE() << ErrorMessage("GetProcessTimes");
}
return ret;
}
// Waits for the processes directly created by |parent| - and specifically
// not their offspring. For this to work without race, |parent| has to be
// suspended or have exited.
void WaitForAllChildProcessesOf(HANDLE parent) {
ProcessID parent_pid = GetProcessId(parent);
std::vector<ProcessID> child_pids = GetPotentialChildProcessesOf(parent_pid);
ULARGE_INTEGER parent_creationtime = GetProcessCreationTime(parent);
for (ProcessID child_pid : child_pids) {
// Try and open the process. This may fail for reasons such as:
// 1. The process isn't |parent|'s child process, but rather a
// higher-privilege sub-process of an earlier process that had
// |parent|'s PID.
// 2. The process no longer exists, e.g. it exited after enumeration.
ScopedKernelHANDLE child_process(
OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
false,
child_pid));
if (!child_process.is_valid())
continue;
// Check that the child now has the right parent PID, as its PID may have
// been reused after the enumeration above.
ProcessInfo child_info;
if (!child_info.Initialize(child_process.get())) {
// This can happen if child_process has exited after the handle is opened.
LOG(ERROR) << "ProcessInfo::Initialize, pid: " << child_pid;
continue;
}
if (parent_pid != child_info.ParentProcessID()) {
// The child's process ID was reused after enumeration.
continue;
}
// We successfully opened |child_process| and it has |parent|'s PID for
// parent process ID. However, this could still be a sub-process of another
// process that earlier had |parent|'s PID. To make sure, check that
// |child_process| was created after |parent_process|.
ULARGE_INTEGER process_creationtime =
GetProcessCreationTime(child_process.get());
if (process_creationtime.QuadPart < parent_creationtime.QuadPart)
continue;
DWORD err = WaitForSingleObject(child_process.get(), INFINITE);
if (err == WAIT_FAILED) {
ADD_FAILURE() << ErrorMessage("WaitForSingleObject");
} else if (err != WAIT_OBJECT_0) {
ADD_FAILURE() << "WaitForSingleObject returned " << err;
}
}
}
} // namespace
WinMultiprocessWithTempDir::WinMultiprocessWithTempDir()
: WinMultiprocess(), temp_dir_env_(kTempDirEnvName) {}
void WinMultiprocessWithTempDir::WinMultiprocessParentBeforeChild() {
temp_dir_ = std::make_unique<ScopedTempDir>();
temp_dir_env_.SetValue(temp_dir_->path().value().c_str());
}
void WinMultiprocessWithTempDir::WinMultiprocessParentAfterChild(HANDLE child) {
WaitForAllChildProcessesOf(child);
temp_dir_.reset();
}
base::FilePath WinMultiprocessWithTempDir::GetTempDirPath() const {
return base::FilePath(temp_dir_env_.GetValue());
}
WinMultiprocessWithTempDir::ScopedEnvironmentVariable::
ScopedEnvironmentVariable(const wchar_t* name)
: name_(name) {
original_value_ = GetValueImpl(&was_defined_);
}
WinMultiprocessWithTempDir::ScopedEnvironmentVariable::
~ScopedEnvironmentVariable() {
if (was_defined_)
SetValue(original_value_.data());
else
SetValue(nullptr);
}
std::wstring WinMultiprocessWithTempDir::ScopedEnvironmentVariable::GetValue()
const {
bool dummy;
return GetValueImpl(&dummy);
}
std::wstring
WinMultiprocessWithTempDir::ScopedEnvironmentVariable::GetValueImpl(
bool* is_defined) const {
// The length returned is inclusive of the terminating zero, except
// if the variable doesn't exist, in which case the return value is zero.
DWORD len = GetEnvironmentVariable(name_, nullptr, 0);
if (len == 0) {
*is_defined = false;
return L"";
}
*is_defined = true;
std::wstring ret;
ret.resize(len);
// The length returned on success is exclusive of the terminating zero.
len = GetEnvironmentVariable(name_, &ret[0], len);
ret.resize(len);
return ret;
}
void WinMultiprocessWithTempDir::ScopedEnvironmentVariable::SetValue(
const wchar_t* new_value) const {
SetEnvironmentVariable(name_, new_value);
}
} // namespace test
} // namespace crashpad