Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(105)

Unified Diff: third_party/crashpad/crashpad/client/crashpad_client_win_test.cc

Issue 2804713002: Update Crashpad to b4095401639ebe2ad33169e5c1d994065cbff1b8 (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/crashpad/crashpad/client/crashpad_client_win_test.cc
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_win_test.cc b/third_party/crashpad/crashpad/client/crashpad_client_win_test.cc
index 47e7add95f0e04bdec6467a977de5c522e684c48..743e930dce3e91cfe3e997f719cf2e624e7ef91a 100644
--- a/third_party/crashpad/crashpad/client/crashpad_client_win_test.cc
+++ b/third_party/crashpad/crashpad/client/crashpad_client_win_test.cc
@@ -14,25 +14,187 @@
#include "client/crashpad_client.h"
+#include <tlhelp32.h>
+
+#include <vector>
+
#include "base/files/file_path.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/logging.h"
#include "gtest/gtest.h"
-#include "test/paths.h"
+#include "test/errors.h"
#include "test/scoped_temp_dir.h"
+#include "test/test_paths.h"
#include "test/win/win_multiprocess.h"
+#include "util/win/process_info.h"
+#include "util/win/scoped_handle.h"
#include "util/win/termination_codes.h"
namespace crashpad {
namespace test {
namespace {
-void StartAndUseHandler() {
- ScopedTempDir temp_dir;
- base::FilePath handler_path = Paths::Executable().DirName().Append(
+class ScopedEnvironmentVariable {
+ public:
+ explicit ScopedEnvironmentVariable(const wchar_t* name);
+ ~ScopedEnvironmentVariable();
+
+ std::wstring GetValue() const;
+
+ // Sets this environment variable to |new_value|. If |new_value| is nullptr
+ // this environment variable will be undefined.
+ void SetValue(const wchar_t* new_value) const;
+
+ private:
+ std::wstring GetValueImpl(bool* is_defined) const;
+
+ std::wstring original_value_;
+ const wchar_t* name_;
+ bool was_defined_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedEnvironmentVariable);
+};
+
+ScopedEnvironmentVariable::ScopedEnvironmentVariable(const wchar_t* name)
+ : name_(name) {
+ original_value_ = GetValueImpl(&was_defined_);
+}
+
+ScopedEnvironmentVariable::~ScopedEnvironmentVariable() {
+ if (was_defined_)
+ SetValue(original_value_.data());
+ else
+ SetValue(nullptr);
+}
+
+std::wstring ScopedEnvironmentVariable::GetValue() const {
+ bool dummy;
+ return GetValueImpl(&dummy);
+}
+
+std::wstring 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 ScopedEnvironmentVariable::SetValue(const wchar_t* new_value) const {
+ SetEnvironmentVariable(name_, new_value);
+}
+
+// Returns the process IDs of all processes that have |parent_pid| as
+// parent process ID.
+std::vector<pid_t> GetPotentialChildProcessesOf(pid_t parent_pid) {
+ ScopedFileHANDLE snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
+ if (!snapshot.is_valid()) {
+ ADD_FAILURE() << ErrorMessage("CreateToolhelp32Snapshot");
+ return std::vector<pid_t>();
+ }
+
+ PROCESSENTRY32 entry = {sizeof(entry)};
+ if (!Process32First(snapshot.get(), &entry)) {
+ ADD_FAILURE() << ErrorMessage("Process32First");
+ return std::vector<pid_t>();
+ }
+
+ std::vector<pid_t> 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) {
+ pid_t parent_pid = GetProcessId(parent);
+ std::vector<pid_t> child_pids = GetPotentialChildProcessesOf(parent_pid);
+
+ ULARGE_INTEGER parent_creationtime = GetProcessCreationTime(parent);
+ for (pid_t 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;
+ }
+ }
+}
+
+void StartAndUseHandler(const base::FilePath& temp_dir) {
+ base::FilePath handler_path = TestPaths::Executable().DirName().Append(
FILE_PATH_LITERAL("crashpad_handler.com"));
+
CrashpadClient client;
ASSERT_TRUE(client.StartHandler(handler_path,
- temp_dir.path(),
+ temp_dir,
base::FilePath(),
"",
std::map<std::string, std::string>(),
@@ -42,9 +204,35 @@ void StartAndUseHandler() {
ASSERT_TRUE(client.WaitForHandlerStart(INFINITE));
}
-class StartWithInvalidHandles final : public WinMultiprocess {
+// Name of the environment variable used to communicate the name of the
+// temp directory from parent to child process.
+constexpr wchar_t kTempDirEnvName[] = L"CRASHPAD_TEST_TEMP_DIR";
+
+class WinMultiprocessWithTempDir : public WinMultiprocess {
+ public:
+ WinMultiprocessWithTempDir()
+ : WinMultiprocess(), temp_dir_env_(kTempDirEnvName) {}
+
+ void WinMultiprocessParentBeforeChild() override {
+ temp_dir_ = base::WrapUnique(new ScopedTempDir);
+ temp_dir_env_.SetValue(temp_dir_->path().value().c_str());
+ }
+
+ void WinMultiprocessParentAfterChild(HANDLE child) override {
+ WaitForAllChildProcessesOf(child);
+ temp_dir_.reset();
+ }
+
+ protected:
+ std::unique_ptr<ScopedTempDir> temp_dir_;
+ ScopedEnvironmentVariable temp_dir_env_;
+
+ DISALLOW_COPY_AND_ASSIGN(WinMultiprocessWithTempDir);
+};
+
+class StartWithInvalidHandles final : public WinMultiprocessWithTempDir {
public:
- StartWithInvalidHandles() : WinMultiprocess() {}
+ StartWithInvalidHandles() : WinMultiprocessWithTempDir() {}
~StartWithInvalidHandles() {}
private:
@@ -56,7 +244,7 @@ class StartWithInvalidHandles final : public WinMultiprocess {
SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE);
SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE);
- StartAndUseHandler();
+ StartAndUseHandler(base::FilePath(temp_dir_env_.GetValue()));
SetStdHandle(STD_OUTPUT_HANDLE, original_stdout);
SetStdHandle(STD_ERROR_HANDLE, original_stderr);
@@ -67,9 +255,9 @@ TEST(CrashpadClient, StartWithInvalidHandles) {
WinMultiprocess::Run<StartWithInvalidHandles>();
}
-class StartWithSameStdoutStderr final : public WinMultiprocess {
+class StartWithSameStdoutStderr final : public WinMultiprocessWithTempDir {
public:
- StartWithSameStdoutStderr() : WinMultiprocess() {}
+ StartWithSameStdoutStderr() : WinMultiprocessWithTempDir() {}
~StartWithSameStdoutStderr() {}
private:
@@ -80,7 +268,7 @@ class StartWithSameStdoutStderr final : public WinMultiprocess {
HANDLE original_stderr = GetStdHandle(STD_ERROR_HANDLE);
SetStdHandle(STD_OUTPUT_HANDLE, original_stderr);
- StartAndUseHandler();
+ StartAndUseHandler(base::FilePath(temp_dir_env_.GetValue()));
SetStdHandle(STD_OUTPUT_HANDLE, original_stdout);
}
@@ -92,7 +280,7 @@ TEST(CrashpadClient, StartWithSameStdoutStderr) {
void StartAndUseBrokenHandler(CrashpadClient* client) {
ScopedTempDir temp_dir;
- base::FilePath handler_path = Paths::Executable().DirName().Append(
+ base::FilePath handler_path = TestPaths::Executable().DirName().Append(
FILE_PATH_LITERAL("fake_handler_that_crashes_at_startup.exe"));
ASSERT_TRUE(client->StartHandler(handler_path,
temp_dir.path(),

Powered by Google App Engine
This is Rietveld 408576698