diff options
Diffstat (limited to 'chrome_frame/crash_reporting/vectored_handler-impl.h')
-rw-r--r-- | chrome_frame/crash_reporting/vectored_handler-impl.h | 166 |
1 files changed, 142 insertions, 24 deletions
diff --git a/chrome_frame/crash_reporting/vectored_handler-impl.h b/chrome_frame/crash_reporting/vectored_handler-impl.h index c6d7d8e..9c0e97d 100644 --- a/chrome_frame/crash_reporting/vectored_handler-impl.h +++ b/chrome_frame/crash_reporting/vectored_handler-impl.h @@ -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 @@ typedef struct _EXCEPTION_REGISTRATION_RECORD { #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 @@ LONG WINAPI VectoredHandlerT<E>::VectoredHandler( // 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 @@ LONG WINAPI VectoredHandlerT<E>::VectoredHandler( 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_->CheckForStackOverflow()) { + return ExceptionContinueSearch; + } // Check whether exception address is inbetween // [IsBadReadPtr, IsBadReadPtr + 0xXX] - if (E::ShouldIgnoreException(exceptionInfo)) { + if (api_->ShouldIgnoreException(exceptionInfo)) { return ExceptionContinueSearch; } @@ -77,40 +92,143 @@ LONG WINAPI VectoredHandlerT<E>::VectoredHandler( 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> -BOOL VectoredHandlerT<E>::ModuleHasInstalledSEHFilter() { - EXCEPTION_REGISTRATION_RECORD* RegistrationFrame = E::RtlpGetExceptionList(); +template <typename E> +bool VectoredHandlerT<E>::ModuleHasInstalledSEHFilter() { + 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)) { - return TRUE; + if (api_->IsOurModule(RegistrationFrame->Handler)) { + return true; } RegistrationFrame = RegistrationFrame->Next; } - return FALSE; + 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 bool CheckForStackOverflow() { + MEMORY_BASIC_INFORMATION mi; + 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_ |