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::UintToString(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 |