Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(493)

Side by Side Diff: client/crashpad_client_win.cc

Issue 1301853002: win: Crash handler server (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: fixes and move some things around Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 <windows.h> 17 #include <windows.h>
18 18
19 #include "base/atomicops.h" 19 #include "base/atomicops.h"
20 #include "base/logging.h" 20 #include "base/logging.h"
21 #include "base/strings/string16.h" 21 #include "base/strings/string16.h"
22 #include "base/strings/utf_string_conversions.h" 22 #include "base/strings/utf_string_conversions.h"
23 #include "client/crashpad_info.h" 23 #include "client/crashpad_info.h"
Mark Mentovai 2015/08/26 21:40:27 Unused now.
scottmg 2015/08/27 01:04:37 Done.
24 #include "client/registration_protocol_win.h"
25 #include "util/file/file_io.h" 24 #include "util/file/file_io.h"
25 #include "util/win/registration_protocol_win.h"
26 #include "util/win/scoped_handle.h" 26 #include "util/win/scoped_handle.h"
27 27
28 namespace { 28 namespace {
29 // Time to wait for the handler to create a dump. This is tricky to figure out.
30 const DWORD kMillisecondsUntilTerminate = 5000;
31 29
32 // This is the exit code that the process will return to the system once the 30 // This handle is never closed.
33 // crash has been handled by Crashpad. We don't want to clash with the 31 HANDLE g_signal_exception = nullptr;
Mark Mentovai 2015/08/26 21:40:28 INVALID_HANDLE_VALUE (and revise line 122 too)?
scottmg 2015/08/27 01:04:37 Done.
34 // application-defined exit codes but we don't know them so we use one that is
35 // unlikely to be used.
36 const UINT kCrashExitCode = 0xffff7001;
37 32
38 // These two handles to events are leaked. 33 // Where we store the exception information that the crash handler reads.
39 HANDLE g_signal_exception = nullptr; 34 crashpad::ExceptionInformation g_exception_information;
40 HANDLE g_wait_termination = nullptr;
41
42 // Tracks whether a thread has already entered UnhandledExceptionHandler.
43 base::subtle::AtomicWord g_have_crashed;
44 35
45 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { 36 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) {
37 // Tracks whether a thread has already entered UnhandledExceptionHandler.
38 static base::subtle::AtomicWord have_crashed;
39
46 // This is a per-process handler. While this handler is being invoked, other 40 // This is a per-process handler. While this handler is being invoked, other
47 // threads are still executing as usual, so multiple threads could enter at 41 // threads are still executing as usual, so multiple threads could enter at
48 // the same time. Because we're in a crashing state, we shouldn't be doing 42 // the same time. Because we're in a crashing state, we shouldn't be doing
49 // anything that might cause allocations, call into kernel mode, etc. So, we 43 // anything that might cause allocations, call into kernel mode, etc. So, we
50 // don't want to take a critical section here to avoid simultaneous access to 44 // don't want to take a critical section here to avoid simultaneous access to
51 // the global exception pointers in CrashpadInfo. Because the crash handler 45 // the global exception pointers in ExceptionInformation. Because the crash
52 // will record all threads, it's fine to simply have the second and subsequent 46 // handler will record all threads, it's fine to simply have the second and
53 // entrants block here. They will soon be suspended by the crash handler, and 47 // subsequent entrants block here. They will soon be suspended by the crash
54 // then the entire process will be terminated below. This means that we won't 48 // handler, and then the entire process will be terminated below. This means
55 // save the exception pointers from the second and further crashes, but 49 // that we won't save the exception pointers from the second and further
56 // contention here is very unlikely, and we'll still have a stack that's 50 // crashes, but contention here is very unlikely, and we'll still have a stack
57 // blocked at this location. 51 // that's blocked at this location.
58 if (base::subtle::Barrier_AtomicIncrement(&g_have_crashed, 1) > 1) { 52 if (base::subtle::Barrier_AtomicIncrement(&have_crashed, 1) > 1) {
59 SleepEx(INFINITE, false); 53 SleepEx(INFINITE, false);
60 } 54 }
61 55
62 // Otherwise, we're the first thread, so record the exception pointer and 56 // Otherwise, we're the first thread, so record the exception pointer and
63 // signal the crash handler. 57 // signal the crash handler.
64 crashpad::CrashpadInfo::GetCrashpadInfo()->set_thread_id( 58 g_exception_information.thread_id = GetCurrentThreadId();
65 GetCurrentThreadId()); 59 g_exception_information.exception_pointers =
66 crashpad::CrashpadInfo::GetCrashpadInfo()->set_exception_pointers( 60 reinterpret_cast<crashpad::WinVMAddress>(exception_pointers);
67 exception_pointers);
68 DWORD rv = SignalObjectAndWait(g_signal_exception,
69 g_wait_termination,
70 kMillisecondsUntilTerminate,
71 false);
72 if (rv != WAIT_OBJECT_0) {
73 // Something went wrong. It is likely that a dump has not been created.
74 if (rv == WAIT_TIMEOUT) {
75 LOG(WARNING) << "SignalObjectAndWait timed out";
76 } else {
77 PLOG(WARNING) << "SignalObjectAndWait error";
78 }
79 }
80 // We don't want to generate more exceptions, so we take the fast route.
81 TerminateProcess(GetCurrentProcess(), kCrashExitCode);
82 return 0L;
83 }
84 61
85 // Returns a pipe handle connected to the RegistrationServer. 62 // Now signal the crash server, which will take a dump and then terminate us
86 crashpad::ScopedFileHANDLE Connect(const base::string16& pipe_name) { 63 // when it's complete.
87 crashpad::ScopedFileHANDLE pipe; 64 SetEvent(g_signal_exception);
88 const int kMaxTries = 5;
89 for (int tries = 0; tries < kMaxTries; ++tries) {
90 pipe.reset(CreateFile(pipe_name.c_str(),
91 GENERIC_READ | GENERIC_WRITE,
92 0,
93 nullptr,
94 OPEN_EXISTING,
95 SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
96 nullptr));
97 if (pipe.is_valid())
98 break;
99 65
100 // If busy, wait 60s before retrying. 66 // Time to wait for the handler to create a dump.
101 if (GetLastError() != ERROR_PIPE_BUSY) { 67 const DWORD kMillisecondsUntilTerminate = 60 * 1000;
102 PLOG(ERROR) << "CreateFile pipe connection";
103 return crashpad::ScopedFileHANDLE();
104 } else if (!WaitNamedPipe(pipe_name.c_str(), 60000)) {
105 PLOG(ERROR) << "WaitNamedPipe";
106 }
107 }
108 68
109 if (!pipe.is_valid()) 69 // Sleep for a while to allow it to process us. Eventually, we terminate
110 return crashpad::ScopedFileHANDLE(); 70 // ourselves in case the crash server is gone, so that we don't leave zombies
71 // around. This would ideally never happen.
72 // TODO(scottmg): Re-add the "reply" event here, for implementing
73 // DumpWithoutCrashing.
74 Sleep(kMillisecondsUntilTerminate);
111 75
112 DWORD mode = PIPE_READMODE_MESSAGE; 76 LOG(ERROR) << "crash server did not respond, self-terminating";
113 if (!SetNamedPipeHandleState(pipe.get(),
114 &mode,
115 nullptr, // Don't set maximum bytes.
116 nullptr)) { // Don't set maximum time.
117 PLOG(ERROR) << "SetNamedPipeHandleState";
118 return crashpad::ScopedFileHANDLE();
119 }
120 77
121 return pipe.Pass(); 78 const UINT kCrashExitCodeNoDump = 0xffff7001;
79 TerminateProcess(GetCurrentProcess(), kCrashExitCodeNoDump);
80
81 return EXCEPTION_CONTINUE_SEARCH;
122 } 82 }
123 83
124 } // namespace 84 } // namespace
125 85
126 namespace crashpad { 86 namespace crashpad {
127 87
128 CrashpadClient::CrashpadClient() { 88 CrashpadClient::CrashpadClient() {
129 } 89 }
130 90
131 CrashpadClient::~CrashpadClient() { 91 CrashpadClient::~CrashpadClient() {
132 } 92 }
133 93
134 bool CrashpadClient::StartHandler( 94 bool CrashpadClient::StartHandler(
135 const base::FilePath& handler, 95 const base::FilePath& handler,
136 const base::FilePath& database, 96 const base::FilePath& database,
137 const std::string& url, 97 const std::string& url,
138 const std::map<std::string, std::string>& annotations, 98 const std::map<std::string, std::string>& annotations,
139 const std::vector<std::string>& arguments) { 99 const std::vector<std::string>& arguments) {
100 LOG(FATAL) << "SetHandler should be used on Windows";
140 return false; 101 return false;
141 } 102 }
142 103
143 bool CrashpadClient::SetHandler(const std::string& ipc_port) { 104 bool CrashpadClient::SetHandler(const std::string& ipc_port) {
144 RegistrationRequest request = {0}; 105 RegistrationRequest request = {0};
145 request.client_process_id = GetCurrentProcessId(); 106 request.client_process_id = GetCurrentProcessId();
146 request.crashpad_info_address = 107 request.exception_information =
147 reinterpret_cast<WinVMAddress>(CrashpadInfo::GetCrashpadInfo()); 108 reinterpret_cast<WinVMAddress>(&g_exception_information);
148 109
149 RegistrationResponse response = {0}; 110 RegistrationResponse response = {0};
150 111
151 ScopedFileHANDLE pipe = Connect(base::UTF8ToUTF16(ipc_port)); 112 if (!internal::RegisterWithCrashHandlerServer(
Mark Mentovai 2015/08/26 21:40:28 I don’t think you should reach far across the code
scottmg 2015/08/27 01:04:37 Done.
152 if (!pipe.is_valid()) 113 base::UTF8ToUTF16(ipc_port), request, &response))
153 return false; 114 return false;
154 bool result = LoggingWriteFile(pipe.get(), &request, sizeof(request)) &&
155 LoggingReadFile(pipe.get(), &response, sizeof(response));
156 if (!result)
157 return result;
158 115
159 // The server returns these already duplicated to be valid in this process. 116 // The server returns these already duplicated to be valid in this process.
160 g_signal_exception = reinterpret_cast<HANDLE>(response.request_report_event); 117 g_signal_exception = reinterpret_cast<HANDLE>(response.request_report_event);
161 g_wait_termination =
162 reinterpret_cast<HANDLE>(response.report_complete_event);
163 return true; 118 return true;
164 } 119 }
165 120
166 bool CrashpadClient::UseHandler() { 121 bool CrashpadClient::UseHandler() {
167 if (!g_signal_exception) 122 if (!g_signal_exception)
168 return false; 123 return false;
169 if (!g_wait_termination)
170 return false;
171 // In theory we could store the previous handler but it is not clear what 124 // In theory we could store the previous handler but it is not clear what
172 // use we have for it. 125 // use we have for it.
173 SetUnhandledExceptionFilter(&UnhandledExceptionHandler); 126 SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
174 return true; 127 return true;
175 } 128 }
176 129
177 } // namespace crashpad 130 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698