OLD | NEW |
---|---|
1 // Copyright 2015 The Crashpad Authors. All rights reserved. | 1 // Copyright 2015 The Crashpad Authors. All rights reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
13 // limitations under the License. | 13 // limitations under the License. |
14 | 14 |
15 #include "client/crashpad_client.h" | 15 #include "client/crashpad_client.h" |
16 | 16 |
17 #include <string.h> | 17 #include <string.h> |
18 #include <windows.h> | 18 #include <windows.h> |
19 | 19 |
20 #include "base/atomicops.h" | 20 #include "base/atomicops.h" |
21 #include "base/logging.h" | 21 #include "base/logging.h" |
22 #include "base/memory/scoped_ptr.h" | |
23 #include "base/scoped_generic.h" | |
22 #include "base/strings/string16.h" | 24 #include "base/strings/string16.h" |
23 #include "base/strings/stringprintf.h" | 25 #include "base/strings/stringprintf.h" |
24 #include "base/strings/utf_string_conversions.h" | 26 #include "base/strings/utf_string_conversions.h" |
25 #include "base/synchronization/lock.h" | 27 #include "base/synchronization/lock.h" |
26 #include "util/file/file_io.h" | 28 #include "util/file/file_io.h" |
27 #include "util/win/command_line.h" | 29 #include "util/win/command_line.h" |
28 #include "util/win/critical_section_with_debug_info.h" | 30 #include "util/win/critical_section_with_debug_info.h" |
31 #include "util/win/get_function.h" | |
29 #include "util/win/handle.h" | 32 #include "util/win/handle.h" |
30 #include "util/win/registration_protocol_win.h" | 33 #include "util/win/registration_protocol_win.h" |
31 #include "util/win/scoped_handle.h" | 34 #include "util/win/scoped_handle.h" |
32 | 35 |
33 namespace { | 36 namespace { |
34 | 37 |
35 // This handle is never closed. This is used to signal to the server that a dump | 38 // This handle is never closed. This is used to signal to the server that a dump |
36 // should be taken in the event of a crash. | 39 // should be taken in the event of a crash. |
37 HANDLE g_signal_exception = INVALID_HANDLE_VALUE; | 40 HANDLE g_signal_exception = INVALID_HANDLE_VALUE; |
38 | 41 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
103 TerminateProcess(GetCurrentProcess(), kCrashExitCodeNoDump); | 106 TerminateProcess(GetCurrentProcess(), kCrashExitCodeNoDump); |
104 | 107 |
105 return EXCEPTION_CONTINUE_SEARCH; | 108 return EXCEPTION_CONTINUE_SEARCH; |
106 } | 109 } |
107 | 110 |
108 std::wstring FormatArgumentString(const std::string& name, | 111 std::wstring FormatArgumentString(const std::string& name, |
109 const std::wstring& value) { | 112 const std::wstring& value) { |
110 return std::wstring(L"--") + base::UTF8ToUTF16(name) + L"=" + value; | 113 return std::wstring(L"--") + base::UTF8ToUTF16(name) + L"=" + value; |
111 } | 114 } |
112 | 115 |
116 struct ScopedProcThreadAttributeListTraits { | |
117 static PPROC_THREAD_ATTRIBUTE_LIST InvalidValue() { | |
118 return nullptr; | |
119 } | |
120 | |
121 static void Free(PPROC_THREAD_ATTRIBUTE_LIST proc_thread_attribute_list) { | |
122 // This is able to use GET_FUNCTION_REQUIRED() instead of GET_FUNCTION() | |
123 // because it will only be called if InitializeProcThreadAttributeList() and | |
124 // UpdateProcThreadAttribute() are present. | |
125 static const auto delete_proc_thread_attribute_list = | |
126 GET_FUNCTION_REQUIRED(L"kernel32.dll", ::DeleteProcThreadAttributeList); | |
127 delete_proc_thread_attribute_list(proc_thread_attribute_list); | |
128 } | |
129 }; | |
130 | |
131 using ScopedProcThreadAttributeList = | |
132 base::ScopedGeneric<PPROC_THREAD_ATTRIBUTE_LIST, | |
133 ScopedProcThreadAttributeListTraits>; | |
134 | |
135 // Adds |handle| to |handle_list| if it appears valid. | |
136 // | |
137 // Invalid handles (including INVALID_HANDLE_VALUE and null handles) cannot be | |
138 // added to a PPROC_THREAD_ATTRIBUTE_LIST’s PROC_THREAD_ATTRIBUTE_HANDLE_LIST. | |
139 // If INVALID_HANDLE_VALUE appears, CreateProcess() will fail with | |
140 // ERROR_INVALID_PARAMETER. If a null handle appears, the child process will | |
141 // silently not inherit any handles. | |
142 // | |
143 // Use this function to add handles with uncertain validities. | |
144 void AddHandleToListIfValid(std::vector<HANDLE>* handle_list, HANDLE handle) { | |
145 if (handle && handle != INVALID_HANDLE_VALUE) { | |
146 handle_list->push_back(handle); | |
147 } | |
148 } | |
149 | |
113 } // namespace | 150 } // namespace |
114 | 151 |
115 namespace crashpad { | 152 namespace crashpad { |
116 | 153 |
117 CrashpadClient::CrashpadClient() | 154 CrashpadClient::CrashpadClient() |
118 : ipc_pipe_() { | 155 : ipc_pipe_() { |
119 } | 156 } |
120 | 157 |
121 CrashpadClient::~CrashpadClient() { | 158 CrashpadClient::~CrashpadClient() { |
122 } | 159 } |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
165 AppendCommandLineArgument( | 202 AppendCommandLineArgument( |
166 FormatArgumentString("annotation", | 203 FormatArgumentString("annotation", |
167 base::UTF8ToUTF16(kv.first + '=' + kv.second)), | 204 base::UTF8ToUTF16(kv.first + '=' + kv.second)), |
168 &command_line); | 205 &command_line); |
169 } | 206 } |
170 AppendCommandLineArgument( | 207 AppendCommandLineArgument( |
171 base::UTF8ToUTF16(base::StringPrintf("--handshake-handle=0x%x", | 208 base::UTF8ToUTF16(base::StringPrintf("--handshake-handle=0x%x", |
172 HandleToInt(pipe_write))), | 209 HandleToInt(pipe_write))), |
173 &command_line); | 210 &command_line); |
174 | 211 |
175 STARTUPINFO startup_info = {}; | 212 DWORD creation_flags; |
176 startup_info.cb = sizeof(startup_info); | 213 STARTUPINFOEX startup_info = {}; |
177 startup_info.dwFlags = STARTF_USESTDHANDLES; | 214 startup_info.StartupInfo.dwFlags = STARTF_USESTDHANDLES; |
178 startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); | 215 startup_info.StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); |
179 startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); | 216 startup_info.StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); |
180 startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); | 217 startup_info.StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); |
218 | |
219 std::vector<HANDLE> handle_list; | |
220 scoped_ptr<uint8_t[]> proc_thread_attribute_list_storage; | |
221 ScopedProcThreadAttributeList proc_thread_attribute_list_owner; | |
222 | |
223 static const auto initialize_proc_thread_attribute_list = | |
224 GET_FUNCTION(L"kernel32.dll", ::InitializeProcThreadAttributeList); | |
scottmg
2015/11/06 20:15:02
Probably don't need :: on these?
Mark Mentovai
2015/11/06 21:49:09
scottmg wrote:
scottmg
2015/11/06 21:53:34
OK, that's fine then too.
| |
225 static const auto update_proc_thread_attribute = | |
226 initialize_proc_thread_attribute_list | |
227 ? GET_FUNCTION(L"kernel32.dll", ::UpdateProcThreadAttribute) | |
228 : nullptr; | |
229 if (!initialize_proc_thread_attribute_list || !update_proc_thread_attribute) { | |
230 // The OS doesn’t allow handle inheritance to be restricted, so the handler | |
231 // will inherit every inheritable handle. | |
232 creation_flags = 0; | |
233 startup_info.StartupInfo.cb = sizeof(startup_info.StartupInfo); | |
234 } else { | |
235 // Restrict handle inheritance to just those needed in the handler. | |
236 | |
237 creation_flags = EXTENDED_STARTUPINFO_PRESENT; | |
238 startup_info.StartupInfo.cb = sizeof(startup_info); | |
239 SIZE_T size; | |
240 rv = initialize_proc_thread_attribute_list(nullptr, 1, 0, &size); | |
241 if (rv) { | |
242 LOG(ERROR) << "InitializeProcThreadAttributeList (size) succeeded, " | |
243 "expected failure"; | |
244 return false; | |
245 } else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { | |
246 PLOG(ERROR) << "InitializeProcThreadAttributeList (size)"; | |
247 return false; | |
248 } | |
249 | |
250 proc_thread_attribute_list_storage.reset(new uint8_t[size]); | |
251 startup_info.lpAttributeList = | |
252 reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>( | |
253 proc_thread_attribute_list_storage.get()); | |
254 rv = initialize_proc_thread_attribute_list( | |
255 startup_info.lpAttributeList, 1, 0, &size); | |
256 if (!rv) { | |
257 PLOG(ERROR) << "InitializeProcThreadAttributeList"; | |
258 return false; | |
259 } | |
260 proc_thread_attribute_list_owner.reset(startup_info.lpAttributeList); | |
261 | |
262 handle_list.reserve(4); | |
263 handle_list.push_back(pipe_write); | |
264 AddHandleToListIfValid(&handle_list, startup_info.StartupInfo.hStdInput); | |
265 AddHandleToListIfValid(&handle_list, startup_info.StartupInfo.hStdOutput); | |
266 AddHandleToListIfValid(&handle_list, startup_info.StartupInfo.hStdError); | |
267 rv = update_proc_thread_attribute( | |
268 startup_info.lpAttributeList, | |
269 0, | |
270 PROC_THREAD_ATTRIBUTE_HANDLE_LIST, | |
271 &handle_list[0], | |
272 handle_list.size() * sizeof(handle_list[0]), | |
273 nullptr, | |
274 nullptr); | |
275 if (!rv) { | |
276 PLOG(ERROR) << "UpdateProcThreadAttribute"; | |
277 return false; | |
278 } | |
279 } | |
280 | |
181 PROCESS_INFORMATION process_info; | 281 PROCESS_INFORMATION process_info; |
182 rv = CreateProcess(handler.value().c_str(), | 282 rv = CreateProcess(handler.value().c_str(), |
183 &command_line[0], | 283 &command_line[0], |
184 nullptr, | 284 nullptr, |
185 nullptr, | 285 nullptr, |
186 true, | 286 true, |
187 0, | 287 creation_flags, |
188 nullptr, | 288 nullptr, |
189 nullptr, | 289 nullptr, |
190 &startup_info, | 290 &startup_info.StartupInfo, |
191 &process_info); | 291 &process_info); |
192 if (!rv) { | 292 if (!rv) { |
193 PLOG(ERROR) << "CreateProcess"; | 293 PLOG(ERROR) << "CreateProcess"; |
194 return false; | 294 return false; |
195 } | 295 } |
196 | 296 |
197 rv = CloseHandle(process_info.hThread); | 297 rv = CloseHandle(process_info.hThread); |
198 PLOG_IF(WARNING, !rv) << "CloseHandle thread"; | 298 PLOG_IF(WARNING, !rv) << "CloseHandle thread"; |
199 | 299 |
200 rv = CloseHandle(process_info.hProcess); | 300 rv = CloseHandle(process_info.hProcess); |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
329 reinterpret_cast<crashpad::WinVMAddress>(&exception_pointers); | 429 reinterpret_cast<crashpad::WinVMAddress>(&exception_pointers); |
330 | 430 |
331 bool set_event_result = !!SetEvent(g_signal_non_crash_dump); | 431 bool set_event_result = !!SetEvent(g_signal_non_crash_dump); |
332 PLOG_IF(ERROR, !set_event_result) << "SetEvent"; | 432 PLOG_IF(ERROR, !set_event_result) << "SetEvent"; |
333 | 433 |
334 DWORD wfso_result = WaitForSingleObject(g_non_crash_dump_done, INFINITE); | 434 DWORD wfso_result = WaitForSingleObject(g_non_crash_dump_done, INFINITE); |
335 PLOG_IF(ERROR, wfso_result != WAIT_OBJECT_0) << "WaitForSingleObject"; | 435 PLOG_IF(ERROR, wfso_result != WAIT_OBJECT_0) << "WaitForSingleObject"; |
336 } | 436 } |
337 | 437 |
338 } // namespace crashpad | 438 } // namespace crashpad |
OLD | NEW |