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

Unified Diff: components/crash/content/app/fallback_crash_handler_launcher_win.cc

Issue 2596463002: A simple, practically zero cost fallback crash handler for Crashpad handler process. (Closed)
Patch Set: On 64 bit systems, pointers are large - doofus. Created 3 years, 11 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: components/crash/content/app/fallback_crash_handler_launcher_win.cc
diff --git a/components/crash/content/app/fallback_crash_handler_launcher_win.cc b/components/crash/content/app/fallback_crash_handler_launcher_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1fa06036682401560cbbc727aa6b57fde7a84905
--- /dev/null
+++ b/components/crash/content/app/fallback_crash_handler_launcher_win.cc
@@ -0,0 +1,131 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/crash/content/app/fallback_crash_handler_launcher_win.h"
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/win/win_util.h"
+
+namespace crash_reporter {
+
+namespace {
+
+// The number of characters reserved at the tail of the command line for the
+// thread ID parameter.
+const size_t kCommandLineTailSize = 32;
+
+} // namespace
+
+FallbackCrashHandlerLauncher::FallbackCrashHandlerLauncher() {
+ memset(&exception_pointers_, 0, sizeof(exception_pointers_));
+}
+
+FallbackCrashHandlerLauncher::~FallbackCrashHandlerLauncher() {}
+
+bool FallbackCrashHandlerLauncher::Initialize(
+ const base::CommandLine& program,
+ const base::FilePath& crashpad_database) {
+ // Open an inheritable handle to self. This will be inherited to the handler.
+ const DWORD kAccessMask =
+ PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE;
+ self_process_handle_.Set(
+ OpenProcess(kAccessMask, TRUE, ::GetCurrentProcessId()));
+ if (!self_process_handle_.IsValid())
+ return false;
+
+ // Setup the startup info for inheriting the self process handle into the
+ // fallback crash handler.
+ if (!startup_info_.InitializeProcThreadAttributeList(1))
+ return false;
+
+ HANDLE raw_self_process_handle = self_process_handle_.Get();
+ if (!startup_info_.UpdateProcThreadAttribute(
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &raw_self_process_handle,
+ sizeof(raw_self_process_handle))) {
+ return false;
+ }
+
+ // Build the command line from a copy of the command line passed in.
+ base::CommandLine cmd_line(program);
+ cmd_line.AppendSwitchPath("database", crashpad_database);
+ cmd_line.AppendSwitchASCII(
+ "exception-pointers",
+ base::Uint64ToString(reinterpret_cast<uintptr_t>(&exception_pointers_)));
+ cmd_line.AppendSwitchASCII(
+ "process", base::UintToString(
+ base::win::HandleToUint32(self_process_handle_.Get())));
+
+ std::wstring str_cmd_line = cmd_line.GetCommandLineString();
+
+ // Append the - for now abortive - thread argument manually.
+ str_cmd_line.append(L" --thread=");
+ // Store the command line string for easy use later.
+ cmd_line_.assign(str_cmd_line.begin(), str_cmd_line.end());
+
+ // Resize the vector to reserve space for the thread ID.
+ cmd_line_.resize(cmd_line_.size() + kCommandLineTailSize, '\0');
+
+ return true;
+}
+
+DWORD FallbackCrashHandlerLauncher::LaunchAndWaitForHandler(
+ EXCEPTION_POINTERS* exception_pointers) {
+ DCHECK(!cmd_line_.empty());
+ DCHECK_EQ('=', cmd_line_[cmd_line_.size() - kCommandLineTailSize - 1]);
+ // This program has crashed. Try and not use anything but the stack.
+
+ // Append the current thread's ID to the command line in-place.
+ int chars_appended = wsprintf(&cmd_line_.back() - kCommandLineTailSize + 1,
+ L"%d", GetCurrentThreadId());
+ DCHECK_GT(static_cast<int>(kCommandLineTailSize), chars_appended);
+
+ // Copy the exception pointers to our member variable, whose address is
+ // already baked into the command line.
+ exception_pointers_ = *exception_pointers;
+
+ // Launch the pre-cooked command line.
+
+ PROCESS_INFORMATION process_info = {};
+ if (!CreateProcess(nullptr, // Application name.
+ &cmd_line_[0], // Command line.
+ nullptr, // Process attributes.
+ nullptr, // Thread attributes.
+ true, // Inherit handles.
+ 0, // Creation flags.
+ nullptr, // Environment.
+ nullptr, // Current directory.
+ startup_info_.startup_info(), // Startup info.
+ &process_info)) {
+ return GetLastError();
+ }
+
+ // Wait on the fallback crash handler process. The expectation is that this
+ // will never return, as the fallback crash handler will terminate this
+ // process. For testing, and full-on belt and suspenders, cover for this
+ // returning.
+ DWORD error = WaitForSingleObject(process_info.hProcess, INFINITE);
+ if (error != WAIT_OBJECT_0) {
+ // This should never happen, barring handle abuse.
+ // TODO(siggi): Record an UMA metric here.
+ NOTREACHED();
+ error = GetLastError();
+ } else {
+ // On successful wait, return the exit code of the fallback crash handler
+ // process.
+ if (!GetExitCodeProcess(process_info.hProcess, &error)) {
+ // This should never happen, barring handle abuse.
+ NOTREACHED();
+ error = GetLastError();
+ }
+ }
+
+ // Close the handles returned from CreateProcess.
+ CloseHandle(process_info.hProcess);
+ CloseHandle(process_info.hThread);
+
+ return error;
+}
+
+} // namespace crash_reporter

Powered by Google App Engine
This is Rietveld 408576698