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

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

Issue 5622006: Improve filtering for false positive crashes... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 10 years 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
« no previous file with comments | « no previous file | chrome_frame/crash_reporting/vectored_handler_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 7
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "chrome_frame/crash_reporting/vectored_handler.h" 9 #include "chrome_frame/crash_reporting/vectored_handler.h"
10 #include "chrome_frame/crash_reporting/nt_loader.h" 10 #include "chrome_frame/crash_reporting/nt_loader.h"
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 exceptions_seen_++; 76 exceptions_seen_++;
77 77
78 // If the exception code is STATUS_STACK_OVERFLOW then proceed as usual - 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 - 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 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. 81 // seeing the follow-up STATUS_ACCESS_VIOLATION(s). See bug 32441.
82 if (exceptionCode != STATUS_STACK_OVERFLOW && api_->CheckForStackOverflow()) { 82 if (exceptionCode != STATUS_STACK_OVERFLOW && api_->CheckForStackOverflow()) {
83 return ExceptionContinueSearch; 83 return ExceptionContinueSearch;
84 } 84 }
85 85
86 // Check whether exception address is inbetween 86 // Check whether exception will be handled by the module that cuased it.
87 // [IsBadReadPtr, IsBadReadPtr + 0xXX] 87 // This should automatically handle the case of IsBadReadPtr and family.
88 if (api_->ShouldIgnoreException(exceptionInfo)) { 88 const EXCEPTION_REGISTRATION_RECORD* seh = api_->RtlpGetExceptionList();
89 if (api_->ShouldIgnoreException(exceptionInfo, seh)) {
89 return ExceptionContinueSearch; 90 return ExceptionContinueSearch;
90 } 91 }
91 92
92 const DWORD exceptionFlags = exceptionInfo->ExceptionRecord->ExceptionFlags; 93 const DWORD exceptionFlags = exceptionInfo->ExceptionRecord->ExceptionFlags;
93 // I don't think VEH is called on unwind. Just to be safe. 94 // I don't think VEH is called on unwind. Just to be safe.
94 if (IS_DISPATCHING(exceptionFlags)) { 95 if (IS_DISPATCHING(exceptionFlags)) {
95 if (ModuleHasInstalledSEHFilter()) 96 if (ModuleHasInstalledSEHFilter())
96 return ExceptionContinueSearch; 97 return ExceptionContinueSearch;
97 98
98 if (api_->IsOurModule(exceptionInfo->ExceptionRecord->ExceptionAddress)) { 99 if (api_->IsOurModule(exceptionInfo->ExceptionRecord->ExceptionAddress)) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 EXCEPTION_REGISTRATION_RECORD* RtlpGetExceptionList() { 163 EXCEPTION_REGISTRATION_RECORD* RtlpGetExceptionList() {
163 return InternalRtlpGetExceptionList(); 164 return InternalRtlpGetExceptionList();
164 } 165 }
165 166
166 static inline WORD RtlCaptureStackBackTrace(DWORD FramesToSkip, 167 static inline WORD RtlCaptureStackBackTrace(DWORD FramesToSkip,
167 DWORD FramesToCapture, void** BackTrace, DWORD* BackTraceHash) { 168 DWORD FramesToCapture, void** BackTrace, DWORD* BackTraceHash) {
168 return ::RtlCaptureStackBackTrace(FramesToSkip, FramesToCapture, 169 return ::RtlCaptureStackBackTrace(FramesToSkip, FramesToCapture,
169 BackTrace, BackTraceHash); 170 BackTrace, BackTraceHash);
170 } 171 }
171 172
172 static bool ShouldIgnoreException(const EXCEPTION_POINTERS* exceptionInfo) { 173 static bool ShouldIgnoreException(const EXCEPTION_POINTERS* exceptionInfo,
stoyan 2010/12/09 09:58:23 Hm.. if a module had installed SEH filter it does
amit 2010/12/09 17:58:59 True, there's a chance that the module's SEH filte
174 const EXCEPTION_REGISTRATION_RECORD* seh_record) {
173 const void* address = exceptionInfo->ExceptionRecord->ExceptionAddress; 175 const void* address = exceptionInfo->ExceptionRecord->ExceptionAddress;
174 for (int i = 0; i < kIgnoreEntries; i++) { 176 const DWORD flags = GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
175 const CodeBlock& code_block = IgnoreExceptions[i]; 177 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS;
176 DCHECK(code_block.code) << "Win32VEHTraits::CodeBlocks not initialized!"; 178 HMODULE crashing_module = NULL;
177 if ((CodeOffset(code_block.code, code_block.begin_offset) <= address) && 179 ::GetModuleHandleEx(flags, reinterpret_cast<LPCWSTR>(address),
stoyan 2010/12/09 09:58:23 Beware - IIRC GetModuleHandle obtains loader lock.
amit 2010/12/09 17:58:59 Good point, changed it to use VirtualQuery
178 (address < CodeOffset(code_block.code, code_block.end_offset))) { 180 &crashing_module);
179 return true; 181 HMODULE top_seh_module = NULL;
180 } 182 if (EXCEPTION_CHAIN_END != seh_record) {
183 ::GetModuleHandleEx(flags, reinterpret_cast<LPCWSTR>(seh_record->Handler),
stoyan 2010/12/09 09:58:23 if crashing_module == NULL you don't have to call
amit 2010/12/09 17:58:59 Yupp, added the check for crashing_module and chan
184 &top_seh_module);
181 } 185 }
182 186
187 // check if the crash address belongs in a module that's expecting
188 // and handling it. This should address cases like kernel32!IsBadXXX
189 // and urlmon!IsValidInterface
190 if (crashing_module && (crashing_module == top_seh_module))
191 return true;
192
183 // We don't want to report exceptions that occur during DLL loading, 193 // We don't want to report exceptions that occur during DLL loading,
184 // as those are captured and ignored by the NT loader. If this thread 194 // as those are captured and ignored by the NT loader. If this thread
185 // is holding the loader's lock, there's a possiblity that the crash 195 // is holding the loader's lock, there's a possiblity that the crash
186 // is occurring in a loading DLL, in which case we resolve the 196 // is occurring in a loading DLL, in which case we resolve the
187 // crash address to a module and check on the module's status. 197 // crash address to a module and check on the module's status.
188 const DWORD flags = GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | 198 if (crashing_module && nt_loader::OwnsLoaderLock()) {
189 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS;
190 HMODULE crashing_module = NULL;
191 if (nt_loader::OwnsLoaderLock() && ::GetModuleHandleEx(
192 flags, reinterpret_cast<LPCWSTR>(address), &crashing_module)) {
193 nt_loader::LDR_DATA_TABLE_ENTRY* entry = 199 nt_loader::LDR_DATA_TABLE_ENTRY* entry =
194 nt_loader::GetLoaderEntry(crashing_module); 200 nt_loader::GetLoaderEntry(crashing_module);
195 201
196 // If: 202 // If:
197 // 1. we found the entry in question, and 203 // 1. we found the entry in question, and
198 // 2. the entry is a DLL (has the IMAGE_DLL flag set), and 204 // 2. the entry is a DLL (has the IMAGE_DLL flag set), and
199 // 3. the DLL has a non-null entrypoint, and 205 // 3. the DLL has a non-null entrypoint, and
200 // 4. the loader has not tagged it with the process attached called flag 206 // 4. the loader has not tagged it with the process attached called flag
201 // we conclude that the crash is most likely during the loading of the 207 // we conclude that the crash is most likely during the loading of the
202 // module and bail on reporting the crash to avoid false positives 208 // module and bail on reporting the crash to avoid false positives
(...skipping 15 matching lines...) Expand all
218 void* stack_top = GetStackTopLimit() - kPageSize; 224 void* stack_top = GetStackTopLimit() - kPageSize;
219 ::VirtualQuery(stack_top, &mi, sizeof(mi)); 225 ::VirtualQuery(stack_top, &mi, sizeof(mi));
220 // The above call may result in moving the top of the stack. 226 // The above call may result in moving the top of the stack.
221 // Check once more. 227 // Check once more.
222 void* stack_top2 = GetStackTopLimit() - kPageSize; 228 void* stack_top2 = GetStackTopLimit() - kPageSize;
223 if (stack_top2 != stack_top) 229 if (stack_top2 != stack_top)
224 ::VirtualQuery(stack_top2, &mi, sizeof(mi)); 230 ::VirtualQuery(stack_top2, &mi, sizeof(mi));
225 return !(mi.Protect & PAGE_GUARD); 231 return !(mi.Protect & PAGE_GUARD);
226 } 232 }
227 233
228 static void InitializeIgnoredBlocks() {
229 // Initialize ignored exception list
230 for (int i = 0; i < kIgnoreEntries; i++) {
231 CodeBlock& code_block = IgnoreExceptions[i];
232 if (!code_block.code) {
233 HMODULE module = GetModuleHandleA(code_block.module);
234 DCHECK(module) << "GetModuleHandle error: " << GetLastError();
235 code_block.code = GetProcAddress(module, code_block.function);
236 DCHECK(code_block.code) << "GetProcAddress error: "<< GetLastError();
237 }
238 }
239 }
240
241 private: 234 private:
242 static inline const void* CodeOffset(const void* code, int offset) { 235 static inline const void* CodeOffset(const void* code, int offset) {
243 return reinterpret_cast<const char*>(code) + offset; 236 return reinterpret_cast<const char*>(code) + offset;
244 } 237 }
245
246 // Block of code to be ignored for exceptions
247 struct CodeBlock {
248 char* module;
249 char* function;
250 int begin_offset;
251 int end_offset;
252 const void* code;
253 };
254
255 static const int kIgnoreEntries = 4;
256 static CodeBlock IgnoreExceptions[kIgnoreEntries];
257 }; 238 };
258 239
259 DECLSPEC_SELECTANY Win32VEHTraits::CodeBlock
260 Win32VEHTraits::IgnoreExceptions[kIgnoreEntries] = {
261 { "kernel32.dll", "IsBadReadPtr", 0, 100, NULL },
262 { "kernel32.dll", "IsBadWritePtr", 0, 100, NULL },
263 { "kernel32.dll", "IsBadStringPtrA", 0, 100, NULL },
264 { "kernel32.dll", "IsBadStringPtrW", 0, 100, NULL },
265 };
266 240
267 // Use Win32 API; checks for single (current) module. Will call a specified 241 // Use Win32 API; checks for single (current) module. Will call a specified
268 // CrashHandlerTraits::DumpHandler when taking a dump. 242 // CrashHandlerTraits::DumpHandler when taking a dump.
269 class CrashHandlerTraits : public Win32VEHTraits, 243 class CrashHandlerTraits : public Win32VEHTraits,
270 public ModuleOfInterestWithExcludedRegion { 244 public ModuleOfInterestWithExcludedRegion {
271 public: 245 public:
272 246
273 typedef bool (*DumpHandler)(EXCEPTION_POINTERS* p); 247 typedef bool (*DumpHandler)(EXCEPTION_POINTERS* p);
274 248
275 CrashHandlerTraits() : dump_handler_(NULL) {} 249 CrashHandlerTraits() : dump_handler_(NULL) {}
276 250
277 // Note that breakpad_lock must be held when this is called. 251 // Note that breakpad_lock must be held when this is called.
278 void Init(const void* veh_segment_start, const void* veh_segment_end, 252 void Init(const void* veh_segment_start, const void* veh_segment_end,
279 DumpHandler dump_handler) { 253 DumpHandler dump_handler) {
280 DCHECK(dump_handler); 254 DCHECK(dump_handler);
281 dump_handler_ = dump_handler; 255 dump_handler_ = dump_handler;
282 Win32VEHTraits::InitializeIgnoredBlocks();
283 ModuleOfInterestWithExcludedRegion::SetCurrentModule(); 256 ModuleOfInterestWithExcludedRegion::SetCurrentModule();
284 // Pointers to static (non-extern) functions take the address of the 257 // Pointers to static (non-extern) functions take the address of the
285 // function's first byte, as opposed to an entry in the compiler generated 258 // function's first byte, as opposed to an entry in the compiler generated
286 // JMP table. In release builds /OPT:REF wipes away the JMP table, but debug 259 // JMP table. In release builds /OPT:REF wipes away the JMP table, but debug
287 // builds are not so lucky. 260 // builds are not so lucky.
288 ModuleOfInterestWithExcludedRegion::SetExcludedRegion(veh_segment_start, 261 ModuleOfInterestWithExcludedRegion::SetExcludedRegion(veh_segment_start,
289 veh_segment_end); 262 veh_segment_end);
290 } 263 }
291 264
292 void Shutdown() { 265 void Shutdown() {
293 } 266 }
294 267
295 inline bool WriteDump(EXCEPTION_POINTERS* p) { 268 inline bool WriteDump(EXCEPTION_POINTERS* p) {
296 if (dump_handler_) { 269 if (dump_handler_) {
297 return dump_handler_(p); 270 return dump_handler_(p);
298 } else { 271 } else {
299 return false; 272 return false;
300 } 273 }
301 } 274 }
302 275
303 private: 276 private:
304 DumpHandler dump_handler_; 277 DumpHandler dump_handler_;
305 }; 278 };
306 279
307 #endif // CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_IMPL_H_ 280 #endif // CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_IMPL_H_
OLDNEW
« no previous file with comments | « no previous file | chrome_frame/crash_reporting/vectored_handler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698