Loosen up heuristics for detecting account creation forms.
[chromium-blink-merge.git] / chrome_frame / crash_reporting / vectored_handler-impl.h
blobeb317a8c78cb365eb5d9e2ea55e4e68c64b1ca34
1 // Copyright (c) 2009 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.
5 #ifndef CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_IMPL_H_
6 #define CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_IMPL_H_
8 #include "base/logging.h"
9 #include "chrome_frame/crash_reporting/vectored_handler.h"
10 #include "chrome_frame/crash_reporting/nt_loader.h"
12 #if !defined(_M_IX86)
13 #error only x86 is supported for now.
14 #endif
16 #ifndef EXCEPTION_CHAIN_END
17 #define EXCEPTION_CHAIN_END ((struct _EXCEPTION_REGISTRATION_RECORD*)-1)
18 #if !defined(_WIN32_WINNT_WIN8)
19 typedef struct _EXCEPTION_REGISTRATION_RECORD {
20 struct _EXCEPTION_REGISTRATION_RECORD* Next;
21 PVOID Handler;
22 } EXCEPTION_REGISTRATION_RECORD;
23 // VEH handler flags settings.
24 // These are grabbed from winnt.h for PocketPC.
25 // Only EXCEPTION_NONCONTINUABLE in defined in "regular" winnt.h
26 // #define EXCEPTION_NONCONTINUABLE 0x1 // Noncontinuable exception
27 #define EXCEPTION_UNWINDING 0x2 // Unwind is in progress
28 #define EXCEPTION_EXIT_UNWIND 0x4 // Exit unwind is in progress
29 #define EXCEPTION_STACK_INVALID 0x8 // Stack out of limits or unaligned
30 #define EXCEPTION_NESTED_CALL 0x10 // Nested exception handler call
31 #define EXCEPTION_TARGET_UNWIND 0x20 // Target unwind in progress
32 #define EXCEPTION_COLLIDED_UNWIND 0x40 // Collided exception handler call
34 #define EXCEPTION_UNWIND (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND | \
35 EXCEPTION_TARGET_UNWIND | EXCEPTION_COLLIDED_UNWIND)
37 #define IS_UNWINDING(Flag) (((Flag) & EXCEPTION_UNWIND) != 0)
38 #define IS_DISPATCHING(Flag) (((Flag) & EXCEPTION_UNWIND) == 0)
39 #define IS_TARGET_UNWIND(Flag) ((Flag) & EXCEPTION_TARGET_UNWIND)
40 #endif // !defined(_WIN32_WINNT_WIN8)
41 #endif // EXCEPTION_CHAIN_END
43 template <typename E>
44 VectoredHandlerT<E>::VectoredHandlerT(E* api) : exceptions_seen_(0), api_(api) {
47 template <typename E>
48 VectoredHandlerT<E>::~VectoredHandlerT() {
51 template <typename E>
52 LONG VectoredHandlerT<E>::Handler(EXCEPTION_POINTERS* exceptionInfo) {
53 // TODO(stoyan): Consider reentrancy
54 const DWORD exceptionCode = exceptionInfo->ExceptionRecord->ExceptionCode;
56 // Not interested in non-error exceptions. In this category falls exceptions
57 // like:
58 // 0x40010006 - OutputDebugStringA. Seen when no debugger is attached
59 // (otherwise debugger swallows the exception and prints
60 // the string).
61 // 0x406D1388 - DebuggerProbe. Used by debug CRT - for example see source
62 // code of isatty(). Used to name a thread as well.
63 // RPC_E_DISCONNECTED and Co. - COM IPC non-fatal warnings
64 // STATUS_BREAKPOINT and Co. - Debugger related breakpoints
65 if ((exceptionCode & ERROR_SEVERITY_ERROR) != ERROR_SEVERITY_ERROR) {
66 return ExceptionContinueSearch;
69 // Ignore custom exception codes.
70 // MSXML likes to raise 0xE0000001 while parsing.
71 // Note the C++ SEH (0xE06D7363) also fails in that range.
72 if (exceptionCode & APPLICATION_ERROR_MASK) {
73 return ExceptionContinueSearch;
76 exceptions_seen_++;
78 // If the exception code is STATUS_STACK_OVERFLOW then proceed as usual -
79 // we want to report it. Otherwise check whether guard page in stack is gone -
80 // i.e. stack overflow has been already observed and most probably we are
81 // seeing the follow-up STATUS_ACCESS_VIOLATION(s). See bug 32441.
82 if (exceptionCode != STATUS_STACK_OVERFLOW && api_->CheckForStackOverflow()) {
83 return ExceptionContinueSearch;
86 // Check whether exception will be handled by the module that cuased it.
87 // This should automatically handle the case of IsBadReadPtr and family.
88 const EXCEPTION_REGISTRATION_RECORD* seh = api_->RtlpGetExceptionList();
89 if (api_->ShouldIgnoreException(exceptionInfo, seh)) {
90 return ExceptionContinueSearch;
93 const DWORD exceptionFlags = exceptionInfo->ExceptionRecord->ExceptionFlags;
94 // I don't think VEH is called on unwind. Just to be safe.
95 if (IS_DISPATCHING(exceptionFlags)) {
96 if (ModuleHasInstalledSEHFilter())
97 return ExceptionContinueSearch;
99 if (api_->IsOurModule(exceptionInfo->ExceptionRecord->ExceptionAddress)) {
100 api_->WriteDump(exceptionInfo);
101 return ExceptionContinueSearch;
104 // See whether our module is somewhere in the call stack.
105 void* back_trace[E::max_back_trace] = {0};
106 DWORD captured = api_->RtlCaptureStackBackTrace(0, api_->max_back_trace,
107 &back_trace[0], NULL);
108 for (DWORD i = 0; i < captured; ++i) {
109 if (api_->IsOurModule(back_trace[i])) {
110 api_->WriteDump(exceptionInfo);
111 return ExceptionContinueSearch;
116 return ExceptionContinueSearch;
119 template <typename E>
120 bool VectoredHandlerT<E>::ModuleHasInstalledSEHFilter() {
121 const EXCEPTION_REGISTRATION_RECORD* RegistrationFrame =
122 api_->RtlpGetExceptionList();
123 // TODO(stoyan): Add the stack limits check and some sanity checks like
124 // decreasing addresses of registration records
125 while (RegistrationFrame != EXCEPTION_CHAIN_END) {
126 if (api_->IsOurModule(RegistrationFrame->Handler)) {
127 return true;
130 RegistrationFrame = RegistrationFrame->Next;
133 return false;
137 // Here comes the default Windows 32-bit implementation.
138 namespace {
139 __declspec(naked)
140 static EXCEPTION_REGISTRATION_RECORD* InternalRtlpGetExceptionList() {
141 __asm {
142 mov eax, fs:0
147 __declspec(naked)
148 static char* GetStackTopLimit() {
149 __asm {
150 mov eax, fs:8
154 } // end of namespace
156 // Class which methods simply forwards to Win32 API.
157 // Used as template (external interface) of VectoredHandlerT<E>.
158 class Win32VEHTraits {
159 public:
160 enum {max_back_trace = 62};
162 static inline
163 EXCEPTION_REGISTRATION_RECORD* RtlpGetExceptionList() {
164 return InternalRtlpGetExceptionList();
167 static inline WORD RtlCaptureStackBackTrace(DWORD FramesToSkip,
168 DWORD FramesToCapture, void** BackTrace, DWORD* BackTraceHash) {
169 return ::RtlCaptureStackBackTrace(FramesToSkip, FramesToCapture,
170 BackTrace, BackTraceHash);
173 static bool ShouldIgnoreException(const EXCEPTION_POINTERS* exceptionInfo,
174 const EXCEPTION_REGISTRATION_RECORD* seh_record) {
175 const void* address = exceptionInfo->ExceptionRecord->ExceptionAddress;
176 const DWORD flags = GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
177 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS;
178 HMODULE crashing_module = GetModuleHandleFromAddress(address);
179 if (!crashing_module)
180 return false;
182 HMODULE top_seh_module = NULL;
183 if (EXCEPTION_CHAIN_END != seh_record)
184 top_seh_module = GetModuleHandleFromAddress(seh_record->Handler);
186 // check if the crash address belongs in a module that's expecting
187 // and handling it. This should address cases like kernel32!IsBadXXX
188 // and urlmon!IsValidInterface
189 if (crashing_module == top_seh_module)
190 return true;
192 // We don't want to report exceptions that occur during DLL loading,
193 // as those are captured and ignored by the NT loader. If this thread
194 // is holding the loader's lock, there's a possiblity that the crash
195 // is occurring in a loading DLL, in which case we resolve the
196 // crash address to a module and check on the module's status.
197 if (nt_loader::OwnsLoaderLock()) {
198 nt_loader::LDR_DATA_TABLE_ENTRY* entry =
199 nt_loader::GetLoaderEntry(crashing_module);
201 // If:
202 // 1. we found the entry in question, and
203 // 2. the entry is a DLL (has the IMAGE_DLL flag set), and
204 // 3. the DLL has a non-null entrypoint, and
205 // 4. the loader has not tagged it with the process attached called flag
206 // we conclude that the crash is most likely during the loading of the
207 // module and bail on reporting the crash to avoid false positives
208 // during crashes that occur during module loads, such as e.g. when
209 // the hook manager attempts to load buggy window hook DLLs.
210 if (entry &&
211 (entry->Flags & LDRP_IMAGE_DLL) != 0 &&
212 (entry->EntryPoint != NULL) &&
213 (entry->Flags & LDRP_PROCESS_ATTACH_CALLED) == 0)
214 return true;
217 return false;
220 static bool CheckForStackOverflow() {
221 MEMORY_BASIC_INFORMATION mi = {0};
222 const DWORD kPageSize = 0x1000;
223 void* stack_top = GetStackTopLimit() - kPageSize;
224 ::VirtualQuery(stack_top, &mi, sizeof(mi));
225 // The above call may result in moving the top of the stack.
226 // Check once more.
227 void* stack_top2 = GetStackTopLimit() - kPageSize;
228 if (stack_top2 != stack_top)
229 ::VirtualQuery(stack_top2, &mi, sizeof(mi));
230 return !(mi.Protect & PAGE_GUARD);
233 private:
234 static inline const void* CodeOffset(const void* code, int offset) {
235 return reinterpret_cast<const char*>(code) + offset;
238 static HMODULE GetModuleHandleFromAddress(const void* p) {
239 HMODULE module_at_address = NULL;
240 MEMORY_BASIC_INFORMATION mi = {0};
241 if (::VirtualQuery(p, &mi, sizeof(mi)) && (mi.Type & MEM_IMAGE)) {
242 module_at_address = reinterpret_cast<HMODULE>(mi.AllocationBase);
245 return module_at_address;
250 // Use Win32 API; checks for single (current) module. Will call a specified
251 // CrashHandlerTraits::DumpHandler when taking a dump.
252 class CrashHandlerTraits : public Win32VEHTraits,
253 public ModuleOfInterestWithExcludedRegion {
254 public:
256 typedef bool (*DumpHandler)(EXCEPTION_POINTERS* p);
258 CrashHandlerTraits() : dump_handler_(NULL) {}
260 // Note that breakpad_lock must be held when this is called.
261 void Init(const void* veh_segment_start, const void* veh_segment_end,
262 DumpHandler dump_handler) {
263 DCHECK(dump_handler);
264 dump_handler_ = dump_handler;
265 ModuleOfInterestWithExcludedRegion::SetCurrentModule();
266 // Pointers to static (non-extern) functions take the address of the
267 // function's first byte, as opposed to an entry in the compiler generated
268 // JMP table. In release builds /OPT:REF wipes away the JMP table, but debug
269 // builds are not so lucky.
270 ModuleOfInterestWithExcludedRegion::SetExcludedRegion(veh_segment_start,
271 veh_segment_end);
274 void Shutdown() {
277 inline bool WriteDump(EXCEPTION_POINTERS* p) {
278 if (dump_handler_) {
279 return dump_handler_(p);
280 } else {
281 return false;
285 private:
286 DumpHandler dump_handler_;
289 #endif // CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_IMPL_H_