Chromium Code Reviews| 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 |