Chromium Code Reviews| Index: chrome_frame/crash_reporting/vectored_handler-impl.h |
| =================================================================== |
| --- chrome_frame/crash_reporting/vectored_handler-impl.h (revision 37418) |
| +++ chrome_frame/crash_reporting/vectored_handler-impl.h (working copy) |
| @@ -7,16 +7,17 @@ |
| #include "chrome_frame/crash_reporting/vectored_handler.h" |
| #if defined(_M_IX86) |
| +#ifndef EXCEPTION_CHAIN_END |
| +#define EXCEPTION_CHAIN_END ((struct _EXCEPTION_REGISTRATION_RECORD*)-1) |
| typedef struct _EXCEPTION_REGISTRATION_RECORD { |
| struct _EXCEPTION_REGISTRATION_RECORD* Next; |
| PVOID Handler; |
| } EXCEPTION_REGISTRATION_RECORD; |
| -#define EXCEPTION_CHAIN_END ((struct _EXCEPTION_REGISTRATION_RECORD*)-1) |
| +#endif // EXCEPTION_CHAIN_END |
| #else |
| #error only x86 is supported for now. |
| #endif |
| - |
| // VEH handler flags settings. |
| // These are grabbed from winnt.h for PocketPC. |
| // Only EXCEPTION_NONCONTINUABLE in defined in "regular" winnt.h |
| @@ -36,9 +37,16 @@ |
| #define IS_TARGET_UNWIND(Flag) ((Flag) & EXCEPTION_TARGET_UNWIND) |
| // End of grabbed section |
| -template <class E> |
| -LONG WINAPI VectoredHandlerT<E>::VectoredHandler( |
| - EXCEPTION_POINTERS* exceptionInfo) { |
| +template <typename E> |
| +VectoredHandlerT<E>::VectoredHandlerT(E* api) : exceptions_seen_(0), api_(api) { |
| +} |
| + |
| +template <typename E> |
| +VectoredHandlerT<E>::~VectoredHandlerT() { |
| +} |
| + |
| +template <typename E> |
| +LONG VectoredHandlerT<E>::Handler(EXCEPTION_POINTERS* exceptionInfo) { |
| // TODO(stoyan): Consider reentrancy |
| const DWORD exceptionCode = exceptionInfo->ExceptionRecord->ExceptionCode; |
| @@ -51,7 +59,6 @@ |
| // code of isatty(). Used to name a thread as well. |
| // RPC_E_DISCONNECTED and Co. - COM IPC non-fatal warnings |
| // STATUS_BREAKPOINT and Co. - Debugger related breakpoints |
| - |
| if ((exceptionCode & ERROR_SEVERITY_ERROR) != ERROR_SEVERITY_ERROR) { |
| return ExceptionContinueSearch; |
| } |
| @@ -63,11 +70,19 @@ |
| return ExceptionContinueSearch; |
| } |
| - ++VectoredHandlerT<E>::g_exceptions_seen; |
| + exceptions_seen_++; |
| + // If the exception code is STATUS_STACK_OVERFLOW then proceed as usual - |
| + // we want to report it. Otherwise check whether guard page in stack is gone - |
| + // i.e. stack overflow has been already observed and most probably we are |
| + // seeing the follow-up STATUS_ACCESS_VIOLATION(s). See bug 32441. |
| + if (exceptionCode != STATUS_STACK_OVERFLOW && api_->StackOverflow()) { |
| + return ExceptionContinueSearch; |
| + } |
| + |
| // Check whether exception address is inbetween |
| // [IsBadReadPtr, IsBadReadPtr + 0xXX] |
| - if (E::ShouldIgnoreException(exceptionInfo)) { |
| + if (api_->ShouldIgnoreException(exceptionInfo)) { |
| return ExceptionContinueSearch; |
| } |
| @@ -77,34 +92,34 @@ |
| if (ModuleHasInstalledSEHFilter()) |
| return ExceptionContinueSearch; |
| - if (E::IsOurModule(exceptionInfo->ExceptionRecord->ExceptionAddress)) { |
| - E::WriteDump(exceptionInfo); |
| + if (api_->IsOurModule(exceptionInfo->ExceptionRecord->ExceptionAddress)) { |
| + api_->WriteDump(exceptionInfo); |
| return ExceptionContinueSearch; |
| } |
| // See whether our module is somewhere in the call stack. |
| - void* back_trace[max_back_trace] = {0}; |
| - // Skip RtlCaptureStackBackTrace and VectoredHandler itself. |
| - DWORD captured = E::RtlCaptureStackBackTrace(2, max_back_trace - 2, |
| - &back_trace[0], NULL); |
| + void* back_trace[api_->max_back_trace] = {0}; |
| + DWORD captured = api_->RtlCaptureStackBackTrace(0, api_->max_back_trace, |
| + &back_trace[0], NULL); |
| for (DWORD i = 0; i < captured; ++i) { |
| - if (E::IsOurModule(back_trace[i])) { |
| - E::WriteDump(exceptionInfo); |
| - return ExceptionContinueSearch; |
| - } |
| + if (api_->IsOurModule(back_trace[i])) { |
| + api_->WriteDump(exceptionInfo); |
| + return ExceptionContinueSearch; |
| + } |
| } |
| } |
| return ExceptionContinueSearch; |
| } |
| -template <class E> |
| +template <typename E> |
| BOOL VectoredHandlerT<E>::ModuleHasInstalledSEHFilter() { |
| - EXCEPTION_REGISTRATION_RECORD* RegistrationFrame = E::RtlpGetExceptionList(); |
| + const EXCEPTION_REGISTRATION_RECORD* RegistrationFrame = |
| + api_->RtlpGetExceptionList(); |
| // TODO(stoyan): Add the stack limits check and some sanity checks like |
| // decreasing addresses of registration records |
| while (RegistrationFrame != EXCEPTION_CHAIN_END) { |
| - if (E::IsOurModule(RegistrationFrame->Handler)) { |
| + if (api_->IsOurModule(RegistrationFrame->Handler)) { |
| return TRUE; |
| } |
| @@ -113,4 +128,107 @@ |
| return FALSE; |
| } |
| + |
| + |
| +// Here comes the default Windows 32-bit implementation. |
| +namespace { |
| + __declspec(naked) |
| + static EXCEPTION_REGISTRATION_RECORD* InternalRtlpGetExceptionList() { |
| + __asm { |
| + mov eax, fs:0 |
| + ret |
| + } |
| + } |
| + __declspec(naked) |
| + static char* GetStackTopLimit() { |
| + __asm { |
| + mov eax, fs:8 |
| + ret |
| + } |
| + } |
| +} // end of namespace |
| + |
| +// Class which methods simply forwards to Win32 API. |
| +// Used as template (external interface) of VectoredHandlerT<E>. |
| +class Win32VEHTraits { |
| + public: |
| + enum {max_back_trace = 62}; |
| + |
| + static inline |
| + EXCEPTION_REGISTRATION_RECORD* RtlpGetExceptionList() { |
| + return InternalRtlpGetExceptionList(); |
| + } |
| + |
| + static inline WORD RtlCaptureStackBackTrace(DWORD FramesToSkip, |
| + DWORD FramesToCapture, void** BackTrace, DWORD* BackTraceHash) { |
| + return ::RtlCaptureStackBackTrace(FramesToSkip, FramesToCapture, |
| + BackTrace, BackTraceHash); |
| + } |
| + |
| + static bool ShouldIgnoreException(const EXCEPTION_POINTERS* exceptionInfo) { |
| + const void* address = exceptionInfo->ExceptionRecord->ExceptionAddress; |
| + for (int i = 0; i < kIgnoreEntries; i++) { |
| + const CodeBlock& code_block = IgnoreExceptions[i]; |
| + DCHECK(code_block.code) << "Win32VEHTraits::CodeBlocks not initialized!"; |
| + if ((CodeOffset(code_block.code, code_block.begin_offset) <= address) && |
| + (address < CodeOffset(code_block.code, code_block.end_offset))) { |
| + return true; |
| + } |
| + } |
| + |
| + return false; |
| + } |
| + |
| + static int StackOverflow() { |
|
amit
2010/01/30 00:52:58
static bool StackOverflow()?
|
| + MEMORY_BASIC_INFORMATION mi; |
|
amit
2010/01/30 00:52:58
nit: = {0}, just to be safe
|
| + const DWORD kPageSize = 0x1000; |
| + void* stack_top = GetStackTopLimit() - kPageSize; |
| + ::VirtualQuery(stack_top, &mi, sizeof(mi)); |
| + // The above call may result in moving the top of the stack. |
| + // Check once more. |
| + void* stack_top2 = GetStackTopLimit() - kPageSize; |
| + if (stack_top2 != stack_top) |
| + ::VirtualQuery(stack_top2, &mi, sizeof(mi)); |
| + return !(mi.Protect & PAGE_GUARD); |
| + } |
| + |
| + static void InitializeIgnoredBlocks() { |
| + // Initialize ignored exception list |
| + for (int i = 0; i < kIgnoreEntries; i++) { |
| + CodeBlock& code_block = IgnoreExceptions[i]; |
| + if (!code_block.code) { |
| + HMODULE module = GetModuleHandleA(code_block.module); |
| + DCHECK(module) << "GetModuleHandle error: " << GetLastError(); |
| + code_block.code = GetProcAddress(module, code_block.function); |
| + DCHECK(code_block.code) << "GetProcAddress error: "<< GetLastError(); |
| + } |
| + } |
| + } |
| + |
| + private: |
| + static inline const void* CodeOffset(const void* code, int offset) { |
| + return reinterpret_cast<const char*>(code) + offset; |
| + } |
| + |
| + // Block of code to be ignored for exceptions |
| + struct CodeBlock { |
| + char* module; |
| + char* function; |
| + int begin_offset; |
| + int end_offset; |
| + const void* code; |
| + }; |
| + |
| + static const int kIgnoreEntries = 4; |
| + static CodeBlock IgnoreExceptions[kIgnoreEntries]; |
| +}; |
| + |
| +DECLSPEC_SELECTANY Win32VEHTraits::CodeBlock |
| +Win32VEHTraits::IgnoreExceptions[kIgnoreEntries] = { |
| + { "kernel32.dll", "IsBadReadPtr", 0, 100, NULL }, |
| + { "kernel32.dll", "IsBadWritePtr", 0, 100, NULL }, |
| + { "kernel32.dll", "IsBadStringPtrA", 0, 100, NULL }, |
| + { "kernel32.dll", "IsBadStringPtrW", 0, 100, NULL }, |
| +}; |
| + |
| #endif // CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_IMPL_H_ |