OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "components/crash/content/app/fallback_crash_handler_launcher_win.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "base/strings/string_number_conversions.h" |
| 9 #include "base/win/win_util.h" |
| 10 |
| 11 namespace crash_reporter { |
| 12 |
| 13 namespace { |
| 14 |
| 15 // The number of characters reserved at the tail of the command line for the |
| 16 // thread ID parameter. |
| 17 const size_t kCommandLineTailSize = 32; |
| 18 |
| 19 } // namespace |
| 20 |
| 21 FallbackCrashHandlerLauncher::FallbackCrashHandlerLauncher() { |
| 22 memset(&exception_pointers_, 0, sizeof(exception_pointers_)); |
| 23 } |
| 24 |
| 25 FallbackCrashHandlerLauncher::~FallbackCrashHandlerLauncher() {} |
| 26 |
| 27 bool FallbackCrashHandlerLauncher::Initialize( |
| 28 const base::CommandLine& program, |
| 29 const base::FilePath& crashpad_database) { |
| 30 // Open an inheritable handle to self. This will be inherited to the handler. |
| 31 const DWORD kAccessMask = |
| 32 PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE; |
| 33 self_process_handle_.Set( |
| 34 OpenProcess(kAccessMask, TRUE, ::GetCurrentProcessId())); |
| 35 if (!self_process_handle_.IsValid()) |
| 36 return false; |
| 37 |
| 38 // Setup the startup info for inheriting the self process handle into the |
| 39 // fallback crash handler. |
| 40 if (!startup_info_.InitializeProcThreadAttributeList(1)) |
| 41 return false; |
| 42 |
| 43 HANDLE raw_self_process_handle = self_process_handle_.Get(); |
| 44 if (!startup_info_.UpdateProcThreadAttribute( |
| 45 PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &raw_self_process_handle, |
| 46 sizeof(raw_self_process_handle))) { |
| 47 return false; |
| 48 } |
| 49 |
| 50 // Build the command line from a copy of the command line passed in. |
| 51 base::CommandLine cmd_line(program); |
| 52 cmd_line.AppendSwitchPath("database", crashpad_database); |
| 53 cmd_line.AppendSwitchASCII( |
| 54 "exception-pointers", |
| 55 base::Uint64ToString(reinterpret_cast<uintptr_t>(&exception_pointers_))); |
| 56 cmd_line.AppendSwitchASCII( |
| 57 "process", base::UintToString( |
| 58 base::win::HandleToUint32(self_process_handle_.Get()))); |
| 59 |
| 60 std::wstring str_cmd_line = cmd_line.GetCommandLineString(); |
| 61 |
| 62 // Append the - for now abortive - thread argument manually. |
| 63 str_cmd_line.append(L" --thread="); |
| 64 // Store the command line string for easy use later. |
| 65 cmd_line_.assign(str_cmd_line.begin(), str_cmd_line.end()); |
| 66 |
| 67 // Resize the vector to reserve space for the thread ID. |
| 68 cmd_line_.resize(cmd_line_.size() + kCommandLineTailSize, '\0'); |
| 69 |
| 70 return true; |
| 71 } |
| 72 |
| 73 DWORD FallbackCrashHandlerLauncher::LaunchAndWaitForHandler( |
| 74 EXCEPTION_POINTERS* exception_pointers) { |
| 75 DCHECK(!cmd_line_.empty()); |
| 76 DCHECK_EQ('=', cmd_line_[cmd_line_.size() - kCommandLineTailSize - 1]); |
| 77 // This program has crashed. Try and not use anything but the stack. |
| 78 |
| 79 // Append the current thread's ID to the command line in-place. |
| 80 int chars_appended = wsprintf(&cmd_line_.back() - kCommandLineTailSize + 1, |
| 81 L"%d", GetCurrentThreadId()); |
| 82 DCHECK_GT(static_cast<int>(kCommandLineTailSize), chars_appended); |
| 83 |
| 84 // Copy the exception pointers to our member variable, whose address is |
| 85 // already baked into the command line. |
| 86 exception_pointers_ = *exception_pointers; |
| 87 |
| 88 // Launch the pre-cooked command line. |
| 89 |
| 90 PROCESS_INFORMATION process_info = {}; |
| 91 if (!CreateProcess(nullptr, // Application name. |
| 92 &cmd_line_[0], // Command line. |
| 93 nullptr, // Process attributes. |
| 94 nullptr, // Thread attributes. |
| 95 true, // Inherit handles. |
| 96 0, // Creation flags. |
| 97 nullptr, // Environment. |
| 98 nullptr, // Current directory. |
| 99 startup_info_.startup_info(), // Startup info. |
| 100 &process_info)) { |
| 101 return GetLastError(); |
| 102 } |
| 103 |
| 104 // Wait on the fallback crash handler process. The expectation is that this |
| 105 // will never return, as the fallback crash handler will terminate this |
| 106 // process. For testing, and full-on belt and suspenders, cover for this |
| 107 // returning. |
| 108 DWORD error = WaitForSingleObject(process_info.hProcess, INFINITE); |
| 109 if (error != WAIT_OBJECT_0) { |
| 110 // This should never happen, barring handle abuse. |
| 111 // TODO(siggi): Record an UMA metric here. |
| 112 NOTREACHED(); |
| 113 error = GetLastError(); |
| 114 } else { |
| 115 // On successful wait, return the exit code of the fallback crash handler |
| 116 // process. |
| 117 if (!GetExitCodeProcess(process_info.hProcess, &error)) { |
| 118 // This should never happen, barring handle abuse. |
| 119 NOTREACHED(); |
| 120 error = GetLastError(); |
| 121 } |
| 122 } |
| 123 |
| 124 // Close the handles returned from CreateProcess. |
| 125 CloseHandle(process_info.hProcess); |
| 126 CloseHandle(process_info.hThread); |
| 127 |
| 128 return error; |
| 129 } |
| 130 |
| 131 } // namespace crash_reporter |
OLD | NEW |