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

Side by Side Diff: chrome_frame/crash_reporting/vectored_handler-impl.h

Issue 557021: Prevent excessive crash reporting due stack overflow (due exception in SEH fi... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 10 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_IMPL_H_ 5 #ifndef CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_IMPL_H_
6 #define CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_IMPL_H_ 6 #define CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_IMPL_H_
7 #include "chrome_frame/crash_reporting/vectored_handler.h" 7 #include "chrome_frame/crash_reporting/vectored_handler.h"
8 8
9 #if defined(_M_IX86) 9 #if defined(_M_IX86)
10 #ifndef EXCEPTION_CHAIN_END
11 #define EXCEPTION_CHAIN_END ((struct _EXCEPTION_REGISTRATION_RECORD*)-1)
10 typedef struct _EXCEPTION_REGISTRATION_RECORD { 12 typedef struct _EXCEPTION_REGISTRATION_RECORD {
11 struct _EXCEPTION_REGISTRATION_RECORD* Next; 13 struct _EXCEPTION_REGISTRATION_RECORD* Next;
12 PVOID Handler; 14 PVOID Handler;
13 } EXCEPTION_REGISTRATION_RECORD; 15 } EXCEPTION_REGISTRATION_RECORD;
14 #define EXCEPTION_CHAIN_END ((struct _EXCEPTION_REGISTRATION_RECORD*)-1) 16 #endif // EXCEPTION_CHAIN_END
15 #else 17 #else
16 #error only x86 is supported for now. 18 #error only x86 is supported for now.
17 #endif 19 #endif
18 20
19
20 // VEH handler flags settings. 21 // VEH handler flags settings.
21 // These are grabbed from winnt.h for PocketPC. 22 // These are grabbed from winnt.h for PocketPC.
22 // Only EXCEPTION_NONCONTINUABLE in defined in "regular" winnt.h 23 // Only EXCEPTION_NONCONTINUABLE in defined in "regular" winnt.h
23 // #define EXCEPTION_NONCONTINUABLE 0x1 // Noncontinuable exception 24 // #define EXCEPTION_NONCONTINUABLE 0x1 // Noncontinuable exception
24 #define EXCEPTION_UNWINDING 0x2 // Unwind is in progress 25 #define EXCEPTION_UNWINDING 0x2 // Unwind is in progress
25 #define EXCEPTION_EXIT_UNWIND 0x4 // Exit unwind is in progress 26 #define EXCEPTION_EXIT_UNWIND 0x4 // Exit unwind is in progress
26 #define EXCEPTION_STACK_INVALID 0x8 // Stack out of limits or unaligned 27 #define EXCEPTION_STACK_INVALID 0x8 // Stack out of limits or unaligned
27 #define EXCEPTION_NESTED_CALL 0x10 // Nested exception handler call 28 #define EXCEPTION_NESTED_CALL 0x10 // Nested exception handler call
28 #define EXCEPTION_TARGET_UNWIND 0x20 // Target unwind in progress 29 #define EXCEPTION_TARGET_UNWIND 0x20 // Target unwind in progress
29 #define EXCEPTION_COLLIDED_UNWIND 0x40 // Collided exception handler call 30 #define EXCEPTION_COLLIDED_UNWIND 0x40 // Collided exception handler call
30 31
31 #define EXCEPTION_UNWIND (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND | \ 32 #define EXCEPTION_UNWIND (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND | \
32 EXCEPTION_TARGET_UNWIND | EXCEPTION_COLLIDED_UNWIND) 33 EXCEPTION_TARGET_UNWIND | EXCEPTION_COLLIDED_UNWIND)
33 34
34 #define IS_UNWINDING(Flag) (((Flag) & EXCEPTION_UNWIND) != 0) 35 #define IS_UNWINDING(Flag) (((Flag) & EXCEPTION_UNWIND) != 0)
35 #define IS_DISPATCHING(Flag) (((Flag) & EXCEPTION_UNWIND) == 0) 36 #define IS_DISPATCHING(Flag) (((Flag) & EXCEPTION_UNWIND) == 0)
36 #define IS_TARGET_UNWIND(Flag) ((Flag) & EXCEPTION_TARGET_UNWIND) 37 #define IS_TARGET_UNWIND(Flag) ((Flag) & EXCEPTION_TARGET_UNWIND)
37 // End of grabbed section 38 // End of grabbed section
38 39
39 template <class E> 40 template <typename E>
40 LONG WINAPI VectoredHandlerT<E>::VectoredHandler( 41 VectoredHandlerT<E>::VectoredHandlerT(E* api) : exceptions_seen_(0), api_(api) {
41 EXCEPTION_POINTERS* exceptionInfo) { 42 }
43
44 template <typename E>
45 VectoredHandlerT<E>::~VectoredHandlerT() {
46 }
47
48 template <typename E>
49 LONG VectoredHandlerT<E>::Handler(EXCEPTION_POINTERS* exceptionInfo) {
42 // TODO(stoyan): Consider reentrancy 50 // TODO(stoyan): Consider reentrancy
43 const DWORD exceptionCode = exceptionInfo->ExceptionRecord->ExceptionCode; 51 const DWORD exceptionCode = exceptionInfo->ExceptionRecord->ExceptionCode;
44 52
45 // Not interested in non-error exceptions. In this category falls exceptions 53 // Not interested in non-error exceptions. In this category falls exceptions
46 // like: 54 // like:
47 // 0x40010006 - OutputDebugStringA. Seen when no debugger is attached 55 // 0x40010006 - OutputDebugStringA. Seen when no debugger is attached
48 // (otherwise debugger swallows the exception and prints 56 // (otherwise debugger swallows the exception and prints
49 // the string). 57 // the string).
50 // 0x406D1388 - DebuggerProbe. Used by debug CRT - for example see source 58 // 0x406D1388 - DebuggerProbe. Used by debug CRT - for example see source
51 // code of isatty(). Used to name a thread as well. 59 // code of isatty(). Used to name a thread as well.
52 // RPC_E_DISCONNECTED and Co. - COM IPC non-fatal warnings 60 // RPC_E_DISCONNECTED and Co. - COM IPC non-fatal warnings
53 // STATUS_BREAKPOINT and Co. - Debugger related breakpoints 61 // STATUS_BREAKPOINT and Co. - Debugger related breakpoints
54
55 if ((exceptionCode & ERROR_SEVERITY_ERROR) != ERROR_SEVERITY_ERROR) { 62 if ((exceptionCode & ERROR_SEVERITY_ERROR) != ERROR_SEVERITY_ERROR) {
56 return ExceptionContinueSearch; 63 return ExceptionContinueSearch;
57 } 64 }
58 65
59 // Ignore custom exception codes. 66 // Ignore custom exception codes.
60 // MSXML likes to raise 0xE0000001 while parsing. 67 // MSXML likes to raise 0xE0000001 while parsing.
61 // Note the C++ SEH (0xE06D7363) also fails in that range. 68 // Note the C++ SEH (0xE06D7363) also fails in that range.
62 if (exceptionCode & APPLICATION_ERROR_MASK) { 69 if (exceptionCode & APPLICATION_ERROR_MASK) {
63 return ExceptionContinueSearch; 70 return ExceptionContinueSearch;
64 } 71 }
65 72
66 ++VectoredHandlerT<E>::g_exceptions_seen; 73 exceptions_seen_++;
74
75 // If the exception code is STATUS_STACK_OVERFLOW then proceed as usual -
76 // we want to report it. Otherwise check whether guard page in stack is gone -
77 // i.e. stack overflow has been already observed and most probably we are
78 // seeing the follow-up STATUS_ACCESS_VIOLATION(s). See bug 32441.
79 if (exceptionCode != STATUS_STACK_OVERFLOW && api_->StackOverflow()) {
80 return ExceptionContinueSearch;
81 }
67 82
68 // Check whether exception address is inbetween 83 // Check whether exception address is inbetween
69 // [IsBadReadPtr, IsBadReadPtr + 0xXX] 84 // [IsBadReadPtr, IsBadReadPtr + 0xXX]
70 if (E::ShouldIgnoreException(exceptionInfo)) { 85 if (api_->ShouldIgnoreException(exceptionInfo)) {
71 return ExceptionContinueSearch; 86 return ExceptionContinueSearch;
72 } 87 }
73 88
74 const DWORD exceptionFlags = exceptionInfo->ExceptionRecord->ExceptionFlags; 89 const DWORD exceptionFlags = exceptionInfo->ExceptionRecord->ExceptionFlags;
75 // I don't think VEH is called on unwind. Just to be safe. 90 // I don't think VEH is called on unwind. Just to be safe.
76 if (IS_DISPATCHING(exceptionFlags)) { 91 if (IS_DISPATCHING(exceptionFlags)) {
77 if (ModuleHasInstalledSEHFilter()) 92 if (ModuleHasInstalledSEHFilter())
78 return ExceptionContinueSearch; 93 return ExceptionContinueSearch;
79 94
80 if (E::IsOurModule(exceptionInfo->ExceptionRecord->ExceptionAddress)) { 95 if (api_->IsOurModule(exceptionInfo->ExceptionRecord->ExceptionAddress)) {
81 E::WriteDump(exceptionInfo); 96 api_->WriteDump(exceptionInfo);
82 return ExceptionContinueSearch; 97 return ExceptionContinueSearch;
83 } 98 }
84 99
85 // See whether our module is somewhere in the call stack. 100 // See whether our module is somewhere in the call stack.
86 void* back_trace[max_back_trace] = {0}; 101 void* back_trace[api_->max_back_trace] = {0};
87 // Skip RtlCaptureStackBackTrace and VectoredHandler itself. 102 DWORD captured = api_->RtlCaptureStackBackTrace(0, api_->max_back_trace,
88 DWORD captured = E::RtlCaptureStackBackTrace(2, max_back_trace - 2, 103 &back_trace[0], NULL);
89 &back_trace[0], NULL);
90 for (DWORD i = 0; i < captured; ++i) { 104 for (DWORD i = 0; i < captured; ++i) {
91 if (E::IsOurModule(back_trace[i])) { 105 if (api_->IsOurModule(back_trace[i])) {
92 E::WriteDump(exceptionInfo); 106 api_->WriteDump(exceptionInfo);
93 return ExceptionContinueSearch; 107 return ExceptionContinueSearch;
94 } 108 }
95 } 109 }
96 } 110 }
97 111
98 return ExceptionContinueSearch; 112 return ExceptionContinueSearch;
99 } 113 }
100 114
101 template <class E> 115 template <typename E>
102 BOOL VectoredHandlerT<E>::ModuleHasInstalledSEHFilter() { 116 BOOL VectoredHandlerT<E>::ModuleHasInstalledSEHFilter() {
103 EXCEPTION_REGISTRATION_RECORD* RegistrationFrame = E::RtlpGetExceptionList(); 117 const EXCEPTION_REGISTRATION_RECORD* RegistrationFrame =
118 api_->RtlpGetExceptionList();
104 // TODO(stoyan): Add the stack limits check and some sanity checks like 119 // TODO(stoyan): Add the stack limits check and some sanity checks like
105 // decreasing addresses of registration records 120 // decreasing addresses of registration records
106 while (RegistrationFrame != EXCEPTION_CHAIN_END) { 121 while (RegistrationFrame != EXCEPTION_CHAIN_END) {
107 if (E::IsOurModule(RegistrationFrame->Handler)) { 122 if (api_->IsOurModule(RegistrationFrame->Handler)) {
108 return TRUE; 123 return TRUE;
109 } 124 }
110 125
111 RegistrationFrame = RegistrationFrame->Next; 126 RegistrationFrame = RegistrationFrame->Next;
112 } 127 }
113 128
114 return FALSE; 129 return FALSE;
115 } 130 }
131
132
133 // Here comes the default Windows 32-bit implementation.
134 namespace {
135 __declspec(naked)
136 static EXCEPTION_REGISTRATION_RECORD* InternalRtlpGetExceptionList() {
137 __asm {
138 mov eax, fs:0
139 ret
140 }
141 }
142 __declspec(naked)
143 static char* GetStackTopLimit() {
144 __asm {
145 mov eax, fs:8
146 ret
147 }
148 }
149 } // end of namespace
150
151 // Class which methods simply forwards to Win32 API.
152 // Used as template (external interface) of VectoredHandlerT<E>.
153 class Win32VEHTraits {
154 public:
155 enum {max_back_trace = 62};
156
157 static inline
158 EXCEPTION_REGISTRATION_RECORD* RtlpGetExceptionList() {
159 return InternalRtlpGetExceptionList();
160 }
161
162 static inline WORD RtlCaptureStackBackTrace(DWORD FramesToSkip,
163 DWORD FramesToCapture, void** BackTrace, DWORD* BackTraceHash) {
164 return ::RtlCaptureStackBackTrace(FramesToSkip, FramesToCapture,
165 BackTrace, BackTraceHash);
166 }
167
168 static bool ShouldIgnoreException(const EXCEPTION_POINTERS* exceptionInfo) {
169 const void* address = exceptionInfo->ExceptionRecord->ExceptionAddress;
170 for (int i = 0; i < kIgnoreEntries; i++) {
171 const CodeBlock& code_block = IgnoreExceptions[i];
172 DCHECK(code_block.code) << "Win32VEHTraits::CodeBlocks not initialized!";
173 if ((CodeOffset(code_block.code, code_block.begin_offset) <= address) &&
174 (address < CodeOffset(code_block.code, code_block.end_offset))) {
175 return true;
176 }
177 }
178
179 return false;
180 }
181
182 static int StackOverflow() {
amit 2010/01/30 00:52:58 static bool StackOverflow()?
183 MEMORY_BASIC_INFORMATION mi;
amit 2010/01/30 00:52:58 nit: = {0}, just to be safe
184 const DWORD kPageSize = 0x1000;
185 void* stack_top = GetStackTopLimit() - kPageSize;
186 ::VirtualQuery(stack_top, &mi, sizeof(mi));
187 // The above call may result in moving the top of the stack.
188 // Check once more.
189 void* stack_top2 = GetStackTopLimit() - kPageSize;
190 if (stack_top2 != stack_top)
191 ::VirtualQuery(stack_top2, &mi, sizeof(mi));
192 return !(mi.Protect & PAGE_GUARD);
193 }
194
195 static void InitializeIgnoredBlocks() {
196 // Initialize ignored exception list
197 for (int i = 0; i < kIgnoreEntries; i++) {
198 CodeBlock& code_block = IgnoreExceptions[i];
199 if (!code_block.code) {
200 HMODULE module = GetModuleHandleA(code_block.module);
201 DCHECK(module) << "GetModuleHandle error: " << GetLastError();
202 code_block.code = GetProcAddress(module, code_block.function);
203 DCHECK(code_block.code) << "GetProcAddress error: "<< GetLastError();
204 }
205 }
206 }
207
208 private:
209 static inline const void* CodeOffset(const void* code, int offset) {
210 return reinterpret_cast<const char*>(code) + offset;
211 }
212
213 // Block of code to be ignored for exceptions
214 struct CodeBlock {
215 char* module;
216 char* function;
217 int begin_offset;
218 int end_offset;
219 const void* code;
220 };
221
222 static const int kIgnoreEntries = 4;
223 static CodeBlock IgnoreExceptions[kIgnoreEntries];
224 };
225
226 DECLSPEC_SELECTANY Win32VEHTraits::CodeBlock
227 Win32VEHTraits::IgnoreExceptions[kIgnoreEntries] = {
228 { "kernel32.dll", "IsBadReadPtr", 0, 100, NULL },
229 { "kernel32.dll", "IsBadWritePtr", 0, 100, NULL },
230 { "kernel32.dll", "IsBadStringPtrA", 0, 100, NULL },
231 { "kernel32.dll", "IsBadStringPtrW", 0, 100, NULL },
232 };
233
116 #endif // CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_IMPL_H_ 234 #endif // CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_IMPL_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698