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

Unified Diff: chrome_frame/crash_reporting/vectored_handler_unittest.cc

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, 11 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 side-by-side diff with in-line comments
Download patch
Index: chrome_frame/crash_reporting/vectored_handler_unittest.cc
===================================================================
--- chrome_frame/crash_reporting/vectored_handler_unittest.cc (revision 37418)
+++ chrome_frame/crash_reporting/vectored_handler_unittest.cc (working copy)
@@ -6,209 +6,180 @@
#include "base/logging.h"
#include "chrome_frame/crash_reporting/vectored_handler-impl.h"
-#include "chrome_frame/crash_reporting/crash_report.h"
-#include "gmock/gmock.h"
+#include "chrome_frame/crash_reporting/veh_test.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-// Class that mocks external call from VectoredHandlerT for testing purposes.
-class EMock : public Win32VEHTraits {
+using testing::_;
+
+ACTION_P(StackTraceDump, s) {
+ memcpy(arg2, s->stack_, s->count_ * sizeof(s->stack_[0]));
+ return s->count_;
+}
+namespace {
+class MockApi : public Win32VEHTraits, public ModuleOfInterest {
public:
- static inline bool WriteDump(EXCEPTION_POINTERS* p) {
- g_dump_made = true;
- return true;
+ MockApi() {
+ Win32VEHTraits::InitializeIgnoredBlocks();
}
- static inline void* Register(PVECTORED_EXCEPTION_HANDLER func,
- const void* module_start,
- const void* module_end) {
- InitializeIgnoredBlocks();
- VEHTraitsBase::SetModule(module_start, module_end);
- // Return some arbitrary number, expecting to get the same on Unregister()
- return reinterpret_cast<void*>(4);
- }
+ MOCK_METHOD1(WriteDump, void(const EXCEPTION_POINTERS*));
+ MOCK_METHOD0(RtlpGetExceptionList, const EXCEPTION_REGISTRATION_RECORD*());
+ MOCK_METHOD4(RtlCaptureStackBackTrace, WORD(DWORD FramesToSkip,
+ DWORD FramesToCapture, void** BackTrace, DWORD* BackTraceHash));
- static inline ULONG Unregister(void* handle) {
- EXPECT_EQ(handle, reinterpret_cast<void*>(4));
- return 1;
+ // Helpers
+ void SetSEH(const SEHChain& sehchain) {
+ EXPECT_CALL(*this, RtlpGetExceptionList())
+ .Times(testing::AnyNumber())
+ .WillRepeatedly(testing::Return(sehchain.chain_));
}
- static inline WORD RtlCaptureStackBackTrace(DWORD FramesToSkip,
- DWORD FramesToCapture, void** BackTrace, DWORD* BackTraceHash) {
- EXPECT_EQ(2, FramesToSkip);
- EXPECT_LE(FramesToSkip + FramesToCapture,
- VectoredHandlerBase::max_back_trace);
- memcpy(BackTrace, g_stack, g_stack_entries * sizeof(BackTrace[0]));
- return g_stack_entries;
+ void SetStack(const StackHelper& s) {
+ EXPECT_CALL(*this, RtlCaptureStackBackTrace(_, _, _, _))
+ .Times(testing::AnyNumber())
+ .WillRepeatedly(StackTraceDump(&s));
}
- static inline EXCEPTION_REGISTRATION_RECORD* RtlpGetExceptionList() {
- return g_seh_chain;
- }
+ enum {max_back_trace = 15};
+};
+}; // namespace
- // Test helpers
- // Create fake SEH chain of random filters - with and without our module.
- static void SetHaveSEHFilter() {
- SetSEHChain(reinterpret_cast<const char*>(g_module_start) - 0x1000,
- reinterpret_cast<const char*>(g_module_start) + 0x1000,
- reinterpret_cast<const char*>(g_module_end) + 0x7127,
- NULL);
- }
+typedef VectoredHandlerT<MockApi> VectoredHandlerMock;
+TEST(ChromeFrame, ExceptionReport) {
+ MockApi api;
+ VectoredHandlerMock veh(&api);
- static void SetNoSEHFilter() {
- SetSEHChain(reinterpret_cast<const char*>(g_module_start) - 0x1000,
- reinterpret_cast<const char*>(g_module_end) + 0x7127,
- NULL);
- }
+ // Start address of our module.
+ char* s = reinterpret_cast<char*>(0x30000000);
+ char *e = s + 0x10000;
+ api.SetModule(s, e);
- // Create fake stack - with and without our module.
- static void SetOnStack() {
- SetStack(reinterpret_cast<const char*>(g_module_start) - 0x11283,
- reinterpret_cast<const char*>(g_module_start) - 0x278361,
- reinterpret_cast<const char*>(g_module_start) + 0x9171,
- reinterpret_cast<const char*>(g_module_end) + 1231,
- NULL);
- }
+ SEHChain have_seh(s - 0x1000, s + 0x1000, e + 0x7127, NULL);
+ SEHChain no_seh(s - 0x1000, e + 0x7127, NULL);
+ StackHelper on_stack(s - 0x11283, s - 0x278361, s + 0x9171, e + 1231, NULL);
+ StackHelper not_on_stack(s - 0x11283, s - 0x278361, e + 1231, NULL);
- static void SetNotOnStack() {
- SetStack(reinterpret_cast<const char*>(g_module_start) - 0x11283,
- reinterpret_cast<const char*>(g_module_start) - 0x278361,
- reinterpret_cast<const char*>(g_module_end) + 1231,
- NULL);
- }
+ char* our_code = s + 0x1111;
+ char* not_our_code = s - 0x5555;
+ char* not_our_code2 = e + 0x5555;
- // Populate stack array
- static void SetStack(const void* p, ...) {
- va_list vl;
- va_start(vl, p);
- g_stack_entries = 0;
- for (; p; ++g_stack_entries) {
- CHECK(g_stack_entries < arraysize(g_stack));
- g_stack[g_stack_entries] = p;
- p = va_arg(vl, const void*);
- }
- }
+ // Exception in our code, but we have SEH filter => no dump.
+ api.SetSEH(have_seh);
+ api.SetStack(on_stack);
+ EXPECT_CALL(api, WriteDump(_)).Times(0);
+ EXPECT_EQ(ExceptionContinueSearch,
+ veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, our_code)));
+ testing::Mock::VerifyAndClearExpectations(&api);
- static void SetSEHChain(const void* p, ...) {
- va_list vl;
- va_start(vl, p);
- int i = 0;
- for (; p; ++i) {
- CHECK(i + 1 < arraysize(g_seh_chain));
- g_seh_chain[i].Handler = const_cast<void*>(p);
- g_seh_chain[i].Next = &g_seh_chain[i + 1];
- p = va_arg(vl, const void*);
- }
+ // RPC_E_DISCONNECTED (0x80010108) is "The object invoked has disconnected
+ // from its clients", shall not be caught since it's a warning only.
+ EXPECT_CALL(api, WriteDump(_)).Times(0);
+ EXPECT_EQ(ExceptionContinueSearch,
+ veh.Handler(&ExceptionInfo(RPC_E_DISCONNECTED, our_code)));
+ testing::Mock::VerifyAndClearExpectations(&api);
- g_seh_chain[i].Next = EXCEPTION_CHAIN_END;
- }
+ // Exception, not in our code, we do not have SEH and we are not in stack.
+ api.SetSEH(no_seh);
+ api.SetStack(not_on_stack);
+ EXPECT_CALL(api, WriteDump(_)).Times(0);
+ EXPECT_EQ(ExceptionContinueSearch,
+ veh.Handler(&ExceptionInfo(STATUS_INTEGER_DIVIDE_BY_ZERO, not_our_code)));
+ testing::Mock::VerifyAndClearExpectations(&api);
- static EXCEPTION_REGISTRATION_RECORD g_seh_chain[25];
- static const void* g_stack[VectoredHandlerBase::max_back_trace];
- static WORD g_stack_entries;
- static bool g_dump_made;
-};
+ // Exception, not in our code, no SEH, but we are on the stack.
+ api.SetSEH(no_seh);
+ api.SetStack(on_stack);
+ EXPECT_CALL(api, WriteDump(_)).Times(1);
+ EXPECT_EQ(ExceptionContinueSearch,
+ veh.Handler(&ExceptionInfo(STATUS_INTEGER_DIVIDE_BY_ZERO,
+ not_our_code2)));
+ testing::Mock::VerifyAndClearExpectations(&api);
-EXCEPTION_REGISTRATION_RECORD EMock::g_seh_chain[25];
-const void* EMock::g_stack[VectoredHandlerBase::max_back_trace];
-WORD EMock::g_stack_entries;
-bool EMock::g_dump_made;
+ // Exception, in our code, no SEH, not on stack (assume FPO screwed us)
+ api.SetSEH(no_seh);
+ api.SetStack(not_on_stack);
+ EXPECT_CALL(api, WriteDump(_)).Times(1);
+ EXPECT_EQ(ExceptionContinueSearch,
+ veh.Handler(&ExceptionInfo(STATUS_PRIVILEGED_INSTRUCTION, our_code)));
+ testing::Mock::VerifyAndClearExpectations(&api);
-typedef VectoredHandlerT<EMock> VectoredHandlerMock;
+ // Exception, in IsBadStringPtrA, we are on the stack.
+ api.SetSEH(no_seh);
+ api.SetStack(on_stack);
+ EXPECT_CALL(api, WriteDump(_)).Times(0);
+ char* ignore_address = reinterpret_cast<char*>(GetProcAddress(
+ GetModuleHandleA("kernel32.dll"), "IsBadStringPtrA")) + 10;
+ EXPECT_EQ(ExceptionContinueSearch,
+ veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, ignore_address)));
+ testing::Mock::VerifyAndClearExpectations(&api);
-class ExPtrsHelper : public _EXCEPTION_POINTERS {
- public:
- ExPtrsHelper() {
- ExceptionRecord = &er_;
- ContextRecord = &ctx_;
- ZeroMemory(&er_, sizeof(er_));
- ZeroMemory(&ctx_, sizeof(ctx_));
- }
+ // Exception, in IsBadStringPtrA, we are not on the stack.
+ api.SetSEH(no_seh);
+ api.SetStack(not_on_stack);
+ EXPECT_CALL(api, WriteDump(_)).Times(0);
+ EXPECT_EQ(ExceptionContinueSearch,
+ veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, ignore_address)));
+ testing::Mock::VerifyAndClearExpectations(&api);
+}
- void Set(DWORD code, void* address, DWORD flags) {
- er_.ExceptionCode = code;
- er_.ExceptionAddress = address;
- er_.ExceptionFlags = flags;
- }
+MATCHER_P(ExceptionCodeIs, code, "") {
+ return (arg->ExceptionRecord->ExceptionCode == code);
+}
- EXCEPTION_RECORD er_;
- CONTEXT ctx_;
-};
+void OverflowStack() {
+ char tmp[1024 * 2048];
+ ZeroMemory(tmp, sizeof(tmp));
amit 2010/01/30 00:52:58 call OverflowStack here again, just to be sure? :)
+}
+DWORD WINAPI CrashingThread(PVOID tmp) {
+ __try {
+ OverflowStack();
+ } __except(EXCEPTION_EXECUTE_HANDLER) {
-TEST(ChromeFrame, ExceptionReport) {
- char* s = reinterpret_cast<char*>(0x30000000);
- char* e = s + 0x10000;
- void* handler = VectoredHandlerMock::Register(s, e);
- char* our_code = s + 0x1111;
- char* not_our_code = s - 0x5555;
- char* not_our_code2 = e + 0x5555;
+ }
- ExPtrsHelper ex;
- // Exception in our code, but we have SEH filter
- ex.Set(STATUS_ACCESS_VIOLATION, our_code, 0);
- EMock::SetHaveSEHFilter();
- EMock::SetOnStack();
- EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex));
- EXPECT_EQ(1, VectoredHandlerMock::g_exceptions_seen);
- EXPECT_FALSE(EMock::g_dump_made);
+ // This will cause STATUS_ACCESS_VIOLATION
+ __try {
+ OverflowStack();
+ } __except(EXCEPTION_EXECUTE_HANDLER) {
- // RPC_E_DISCONNECTED (0x80010108) is "The object invoked has disconnected
- // from its clients", shall not be caught since it's a warning only.
- ex.Set(RPC_E_DISCONNECTED, our_code, 0);
- EMock::SetHaveSEHFilter();
- EMock::SetOnStack();
- EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex));
- EXPECT_EQ(1, VectoredHandlerMock::g_exceptions_seen);
- EXPECT_FALSE(EMock::g_dump_made);
+ }
+ return 0;
+}
- // Exception, not in our code, we do not have SEH and we are not in stack.
- ex.Set(STATUS_INTEGER_DIVIDE_BY_ZERO, not_our_code, 0);
- EMock::SetNoSEHFilter();
- EMock::SetNotOnStack();
- EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex));
- EXPECT_EQ(2, VectoredHandlerMock::g_exceptions_seen);
- EXPECT_FALSE(EMock::g_dump_made);
+static VectoredHandlerMock* g_mock_veh = NULL;
+static LONG WINAPI VEH(EXCEPTION_POINTERS* exptrs) {
+ return g_mock_veh->Handler(exptrs);
+}
- // Exception, not in our code, no SEH, but we are on the stack.
- ex.Set(STATUS_INTEGER_DIVIDE_BY_ZERO, not_our_code2, 0);
- EMock::SetNoSEHFilter();
- EMock::SetOnStack();
- EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex));
- EXPECT_EQ(3, VectoredHandlerMock::g_exceptions_seen);
- EXPECT_TRUE(EMock::g_dump_made);
- EMock::g_dump_made = false;
+TEST(ChromeFrame, TrickyStackOverflow) {
+ MockApi api;
+ VectoredHandlerMock veh(&api);
+ // Start address of our module.
+ char* s = reinterpret_cast<char*>(0x30000000);
+ char *e = s + 0x10000;
+ api.SetModule(s, e);
- // Exception, in our code, no SEH, not on stack (assume FPO screwed us)
- ex.Set(STATUS_INTEGER_DIVIDE_BY_ZERO, our_code, 0);
- EMock::SetNoSEHFilter();
- EMock::SetNotOnStack();
- EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex));
- EXPECT_EQ(4, VectoredHandlerMock::g_exceptions_seen);
- EXPECT_TRUE(EMock::g_dump_made);
- EMock::g_dump_made = false;
+ SEHChain no_seh(s - 0x1000, e + 0x7127, NULL);
+ StackHelper on_stack(s - 0x11283, s - 0x278361, s + 0x9171, e + 1231, NULL);
+ api.SetSEH(no_seh);
+ api.SetStack(on_stack);
- // Exception, in IsBadStringPtrA, we are on the stack.
- char* ignore_address = reinterpret_cast<char*>(GetProcAddress(
- GetModuleHandleA("kernel32.dll"), "IsBadStringPtrA")) + 10;
- ex.Set(STATUS_ACCESS_VIOLATION, ignore_address + 10, 0);
- EMock::SetNoSEHFilter();
- EMock::SetOnStack();
- EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex));
- EXPECT_EQ(5, VectoredHandlerMock::g_exceptions_seen);
- EXPECT_FALSE(EMock::g_dump_made);
- EMock::g_dump_made = false;
+ EXPECT_CALL(api, WriteDump(ExceptionCodeIs(STATUS_STACK_OVERFLOW))).Times(1);
- // Exception, in IsBadStringPtrA, we are not in stack.
- ex.Set(STATUS_ACCESS_VIOLATION, ignore_address + 10, 0);
- EMock::SetNoSEHFilter();
- EMock::SetNotOnStack();
- EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex));
- EXPECT_EQ(6, VectoredHandlerMock::g_exceptions_seen);
- EXPECT_FALSE(EMock::g_dump_made);
- EMock::g_dump_made = false;
+ g_mock_veh = &veh;
+ void* id = ::AddVectoredExceptionHandler(FALSE, VEH);
- VectoredHandlerMock::Unregister();
+ DWORD tid;
+ HANDLE h = ::CreateThread(0, 0, CrashingThread, 0, 0, &tid);
+ ::WaitForSingleObject(h, INFINITE);
+ ::CloseHandle(h);
+
+ EXPECT_EQ(2, veh.get_exceptions_seen());
+ ::RemoveVectoredExceptionHandler(id);
+ g_mock_veh = NULL;
}

Powered by Google App Engine
This is Rietveld 408576698