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