summaryrefslogtreecommitdiffstats
path: root/chrome_frame/crash_reporting
diff options
context:
space:
mode:
authormad@chromium.org <mad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-20 18:55:39 +0000
committermad@chromium.org <mad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-20 18:55:39 +0000
commite32e1792b61a0183fc48d4ee1cc79b7d8e89f0af (patch)
tree0e3bbc6171045171d505b503ed718e27d863e2c9 /chrome_frame/crash_reporting
parentb5ffe4e348bab92834e34c99451f21cffc24a1e1 (diff)
downloadchromium_src-e32e1792b61a0183fc48d4ee1cc79b7d8e89f0af.zip
chromium_src-e32e1792b61a0183fc48d4ee1cc79b7d8e89f0af.tar.gz
chromium_src-e32e1792b61a0183fc48d4ee1cc79b7d8e89f0af.tar.bz2
For Steven Truong (stevet@)
Reviewed in: http://codereview.chromium.org/276068 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29543 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame/crash_reporting')
-rw-r--r--chrome_frame/crash_reporting/crash_reporting.gyp14
-rw-r--r--chrome_frame/crash_reporting/vectored_handler_unittest.cc192
2 files changed, 206 insertions, 0 deletions
diff --git a/chrome_frame/crash_reporting/crash_reporting.gyp b/chrome_frame/crash_reporting/crash_reporting.gyp
index 14c0156..7d75184 100644
--- a/chrome_frame/crash_reporting/crash_reporting.gyp
+++ b/chrome_frame/crash_reporting/crash_reporting.gyp
@@ -30,6 +30,20 @@
}],
],
},
+ {
+ 'target_name': 'vectored_handler_tests',
+ 'type': 'executable',
+ 'sources': [
+ 'vectored_handler_unittest.cc',
+ ],
+ 'dependencies': [
+ 'crash_report',
+ '../../base/base.gyp:base',
+ '../../testing/gmock.gyp:gmock',
+ '../../testing/gtest.gyp:gtest',
+ '../../testing/gtest.gyp:gtestmain',
+ ],
+ },
],
}
diff --git a/chrome_frame/crash_reporting/vectored_handler_unittest.cc b/chrome_frame/crash_reporting/vectored_handler_unittest.cc
new file mode 100644
index 0000000..52c730a
--- /dev/null
+++ b/chrome_frame/crash_reporting/vectored_handler_unittest.cc
@@ -0,0 +1,192 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <atlbase.h>
+
+#include "base/logging.h"
+#include "chrome_frame/crash_reporting/vectored_handler-impl.h"
+#include "gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Class that mocks external call from VectoredHandlerT for testing purposes.
+class EMock : public VEHTraitsBase {
+ public:
+ static inline bool WriteDump(EXCEPTION_POINTERS* p) {
+ g_dump_made = true;
+ return true;
+ }
+
+ static inline void* Register(PVECTORED_EXCEPTION_HANDLER func,
+ const void* module_start,
+ const void* module_end) {
+ VEHTraitsBase::SetModule(module_start, module_end);
+ // Return some arbitrary number, expecting to get the same on Unregister()
+ return reinterpret_cast<void*>(4);
+ }
+
+ static inline ULONG Unregister(void* handle) {
+ EXPECT_EQ(handle, reinterpret_cast<void*>(4));
+ return 1;
+ }
+
+ 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;
+ }
+
+ static inline EXCEPTION_REGISTRATION_RECORD* RtlpGetExceptionList() {
+ return g_seh_chain;
+ }
+
+ // 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);
+ }
+
+ static void SetNoSEHFilter() {
+ SetSEHChain(reinterpret_cast<const char*>(g_module_start) - 0x1000,
+ reinterpret_cast<const char*>(g_module_end) + 0x7127,
+ NULL);
+ }
+
+ // 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);
+ }
+
+ 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);
+ }
+
+ // 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*);
+ }
+ }
+
+ 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*);
+ }
+
+ g_seh_chain[i].Next = EXCEPTION_CHAIN_END;
+ }
+
+ 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_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;
+
+typedef VectoredHandlerT<EMock> VectoredHandlerMock;
+
+class ExPtrsHelper : public _EXCEPTION_POINTERS {
+ public:
+ ExPtrsHelper() {
+ ExceptionRecord = &er_;
+ ContextRecord = &ctx_;
+ ZeroMemory(&er_, sizeof(er_));
+ ZeroMemory(&ctx_, sizeof(ctx_));
+ }
+
+ void Set(DWORD code, void* address, DWORD flags) {
+ er_.ExceptionCode = code;
+ er_.ExceptionAddress = address;
+ er_.ExceptionFlags = flags;
+ }
+
+ EXCEPTION_RECORD er_;
+ CONTEXT ctx_;
+};
+
+
+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);
+
+ // 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);
+
+
+ // 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);
+
+ // 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;
+
+
+ // 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;
+
+ VectoredHandlerMock::Unregister();
+}