| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 #include <atlbase.h> | 5 #include <atlbase.h> |
| 6 | 6 |
| 7 #include "base/environment.h" | 7 #include "base/environment.h" |
| 8 #include "base/scoped_ptr.h" | 8 #include "base/scoped_ptr.h" |
| 9 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
| 10 #include "chrome_frame/crash_reporting/crash_dll.h" | 10 #include "chrome_frame/crash_reporting/crash_dll.h" |
| 11 #include "chrome_frame/crash_reporting/nt_loader.h" | 11 #include "chrome_frame/crash_reporting/nt_loader.h" |
| 12 #include "chrome_frame/crash_reporting/vectored_handler-impl.h" | 12 #include "chrome_frame/crash_reporting/vectored_handler-impl.h" |
| 13 #include "chrome_frame/crash_reporting/veh_test.h" | 13 #include "chrome_frame/crash_reporting/veh_test.h" |
| 14 #include "testing/gmock/include/gmock/gmock.h" | 14 #include "testing/gmock/include/gmock/gmock.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
| 16 | 16 |
| 17 using testing::_; | 17 using testing::_; |
| 18 | 18 |
| 19 ACTION_P(StackTraceDump, s) { | 19 ACTION_P(StackTraceDump, s) { |
| 20 memcpy(arg2, s->stack_, s->count_ * sizeof(s->stack_[0])); | 20 memcpy(arg2, s->stack_, s->count_ * sizeof(s->stack_[0])); |
| 21 return s->count_; | 21 return s->count_; |
| 22 } | 22 } |
| 23 namespace { | 23 namespace { |
| 24 class MockApi : public Win32VEHTraits, public ModuleOfInterest { | 24 class MockApi : public Win32VEHTraits, public ModuleOfInterest { |
| 25 public: | 25 public: |
| 26 MockApi() { | 26 MockApi() {} |
| 27 Win32VEHTraits::InitializeIgnoredBlocks(); | |
| 28 } | |
| 29 | 27 |
| 30 MOCK_METHOD1(WriteDump, void(const EXCEPTION_POINTERS*)); | 28 MOCK_METHOD1(WriteDump, void(const EXCEPTION_POINTERS*)); |
| 31 MOCK_METHOD0(RtlpGetExceptionList, const EXCEPTION_REGISTRATION_RECORD*()); | 29 MOCK_METHOD0(RtlpGetExceptionList, const EXCEPTION_REGISTRATION_RECORD*()); |
| 32 MOCK_METHOD4(RtlCaptureStackBackTrace, WORD(DWORD FramesToSkip, | 30 MOCK_METHOD4(RtlCaptureStackBackTrace, WORD(DWORD FramesToSkip, |
| 33 DWORD FramesToCapture, void** BackTrace, DWORD* BackTraceHash)); | 31 DWORD FramesToCapture, void** BackTrace, DWORD* BackTraceHash)); |
| 34 | 32 |
| 35 // Helpers | 33 // Helpers |
| 36 void SetSEH(const SEHChain& sehchain) { | 34 void SetSEH(const SEHChain& sehchain) { |
| 37 EXPECT_CALL(*this, RtlpGetExceptionList()) | 35 EXPECT_CALL(*this, RtlpGetExceptionList()) |
| 38 .Times(testing::AnyNumber()) | 36 .Times(testing::AnyNumber()) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 53 static VectoredHandlerMock* g_mock_veh = NULL; | 51 static VectoredHandlerMock* g_mock_veh = NULL; |
| 54 static LONG WINAPI VEH(EXCEPTION_POINTERS* exptrs) { | 52 static LONG WINAPI VEH(EXCEPTION_POINTERS* exptrs) { |
| 55 return g_mock_veh->Handler(exptrs); | 53 return g_mock_veh->Handler(exptrs); |
| 56 } | 54 } |
| 57 | 55 |
| 58 TEST(ChromeFrame, ExceptionReport) { | 56 TEST(ChromeFrame, ExceptionReport) { |
| 59 MockApi api; | 57 MockApi api; |
| 60 VectoredHandlerMock veh(&api); | 58 VectoredHandlerMock veh(&api); |
| 61 | 59 |
| 62 // Start address of our module. | 60 // Start address of our module. |
| 63 char* s = reinterpret_cast<char*>(0x30000000); | 61 char* s = reinterpret_cast<char*>(&__ImageBase); |
| 64 char *e = s + 0x10000; | 62 char *e = s + 0x10000; |
| 65 api.SetModule(s, e); | 63 api.SetModule(s, e); |
| 66 | 64 |
| 67 SEHChain have_seh(s - 0x1000, s + 0x1000, e + 0x7127, NULL); | 65 SEHChain have_seh(s - 0x1000, s + 0x1000, e + 0x7127, NULL); |
| 68 SEHChain no_seh(s - 0x1000, e + 0x7127, NULL); | 66 SEHChain no_seh(s - 0x1000, e + 0x7127, NULL); |
| 69 StackHelper on_stack(s - 0x11283, s - 0x278361, s + 0x9171, e + 1231, NULL); | 67 StackHelper on_stack(s - 0x11283, s - 0x278361, s + 0x9171, e + 1231, NULL); |
| 70 StackHelper not_on_stack(s - 0x11283, s - 0x278361, e + 1231, NULL); | 68 StackHelper not_on_stack(s - 0x11283, s - 0x278361, e + 1231, NULL); |
| 71 | 69 |
| 72 char* our_code = s + 0x1111; | 70 char* our_code = s + 0x1111; |
| 73 char* not_our_code = s - 0x5555; | 71 char* not_our_code = s - 0x5555; |
| 74 char* not_our_code2 = e + 0x5555; | 72 char* not_our_code2 = e + 0x5555; |
| 75 | 73 |
| 76 // Exception in our code, but we have SEH filter => no dump. | 74 // Exception in our code, but we have SEH filter => no dump. |
| 77 api.SetSEH(have_seh); | 75 api.SetSEH(have_seh); |
| 78 api.SetStack(on_stack); | 76 api.SetStack(on_stack); |
| 79 EXPECT_CALL(api, WriteDump(_)).Times(0); | 77 EXPECT_CALL(api, WriteDump(_)).Times(0); |
| 80 EXPECT_EQ(ExceptionContinueSearch, | 78 EXPECT_EQ(ExceptionContinueSearch, |
| 81 veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, our_code))); | 79 veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, our_code))); |
| 82 testing::Mock::VerifyAndClearExpectations(&api); | 80 testing::Mock::VerifyAndClearExpectations(&api); |
| 83 | 81 |
| 84 // RPC_E_DISCONNECTED (0x80010108) is "The object invoked has disconnected | 82 // RPC_E_DISCONNECTED (0x80010108) is "The object invoked has disconnected |
| 85 // from its clients", shall not be caught since it's a warning only. | 83 // from its clients", shall not be caught since it's a warning only. |
| 86 EXPECT_CALL(api, WriteDump(_)).Times(0); | 84 EXPECT_CALL(api, WriteDump(_)).Times(0); |
| 85 EXPECT_CALL(api, RtlpGetExceptionList()).Times(0); |
| 87 EXPECT_EQ(ExceptionContinueSearch, | 86 EXPECT_EQ(ExceptionContinueSearch, |
| 88 veh.Handler(&ExceptionInfo(RPC_E_DISCONNECTED, our_code))); | 87 veh.Handler(&ExceptionInfo(RPC_E_DISCONNECTED, our_code))); |
| 89 testing::Mock::VerifyAndClearExpectations(&api); | 88 testing::Mock::VerifyAndClearExpectations(&api); |
| 90 | 89 |
| 91 // Exception, not in our code, we do not have SEH and we are not in stack. | 90 // Exception, not in our code, we do not have SEH and we are not in stack. |
| 92 api.SetSEH(no_seh); | 91 api.SetSEH(no_seh); |
| 93 api.SetStack(not_on_stack); | 92 api.SetStack(not_on_stack); |
| 94 EXPECT_CALL(api, WriteDump(_)).Times(0); | 93 EXPECT_CALL(api, WriteDump(_)).Times(0); |
| 95 EXPECT_EQ(ExceptionContinueSearch, | 94 EXPECT_EQ(ExceptionContinueSearch, |
| 96 veh.Handler(&ExceptionInfo(STATUS_INTEGER_DIVIDE_BY_ZERO, not_our_code))); | 95 veh.Handler(&ExceptionInfo(STATUS_INTEGER_DIVIDE_BY_ZERO, not_our_code))); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 107 | 106 |
| 108 // Exception, in our code, no SEH, not on stack (assume FPO screwed us) | 107 // Exception, in our code, no SEH, not on stack (assume FPO screwed us) |
| 109 api.SetSEH(no_seh); | 108 api.SetSEH(no_seh); |
| 110 api.SetStack(not_on_stack); | 109 api.SetStack(not_on_stack); |
| 111 EXPECT_CALL(api, WriteDump(_)).Times(1); | 110 EXPECT_CALL(api, WriteDump(_)).Times(1); |
| 112 EXPECT_EQ(ExceptionContinueSearch, | 111 EXPECT_EQ(ExceptionContinueSearch, |
| 113 veh.Handler(&ExceptionInfo(STATUS_PRIVILEGED_INSTRUCTION, our_code))); | 112 veh.Handler(&ExceptionInfo(STATUS_PRIVILEGED_INSTRUCTION, our_code))); |
| 114 testing::Mock::VerifyAndClearExpectations(&api); | 113 testing::Mock::VerifyAndClearExpectations(&api); |
| 115 | 114 |
| 116 // Exception, in IsBadStringPtrA, we are on the stack. | 115 // Exception, in IsBadStringPtrA, we are on the stack. |
| 117 api.SetSEH(no_seh); | 116 char* is_bad_ptr = reinterpret_cast<char*>(GetProcAddress( |
| 117 GetModuleHandleA("kernel32.dll"), "IsBadStringPtrA")); |
| 118 SEHChain kernel32_seh(is_bad_ptr, is_bad_ptr + 0x100, NULL); |
| 119 api.SetSEH(kernel32_seh); |
| 118 api.SetStack(on_stack); | 120 api.SetStack(on_stack); |
| 119 EXPECT_CALL(api, WriteDump(_)).Times(0); | 121 EXPECT_CALL(api, WriteDump(_)).Times(0); |
| 120 char* ignore_address = reinterpret_cast<char*>(GetProcAddress( | |
| 121 GetModuleHandleA("kernel32.dll"), "IsBadStringPtrA")) + 10; | |
| 122 EXPECT_EQ(ExceptionContinueSearch, | 122 EXPECT_EQ(ExceptionContinueSearch, |
| 123 veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, ignore_address))); | 123 veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, is_bad_ptr))); |
| 124 testing::Mock::VerifyAndClearExpectations(&api); | 124 testing::Mock::VerifyAndClearExpectations(&api); |
| 125 | 125 |
| 126 // Exception, in IsBadStringPtrA, we are not on the stack. | 126 // Exception, in IsBadStringPtrA, we are not on the stack. |
| 127 api.SetSEH(no_seh); | 127 api.SetSEH(kernel32_seh); |
| 128 api.SetStack(not_on_stack); | 128 api.SetStack(not_on_stack); |
| 129 EXPECT_CALL(api, WriteDump(_)).Times(0); | 129 EXPECT_CALL(api, WriteDump(_)).Times(0); |
| 130 EXPECT_EQ(ExceptionContinueSearch, | 130 EXPECT_EQ(ExceptionContinueSearch, |
| 131 veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, ignore_address))); | 131 veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, is_bad_ptr))); |
| 132 testing::Mock::VerifyAndClearExpectations(&api); | 132 testing::Mock::VerifyAndClearExpectations(&api); |
| 133 | 133 |
| 134 // Exception in a loading module, we are on the stack. | 134 // Exception in a loading module, we are on the stack. |
| 135 // Make sure we don't report it. | 135 // Make sure we don't report it. |
| 136 api.SetSEH(no_seh); | 136 api.SetSEH(no_seh); |
| 137 api.SetStack(on_stack); | 137 api.SetStack(on_stack); |
| 138 EXPECT_CALL(api, WriteDump(_)).Times(0); | 138 EXPECT_CALL(api, WriteDump(_)).Times(0); |
| 139 | 139 |
| 140 g_mock_veh = &veh; | 140 g_mock_veh = &veh; |
| 141 void* id = ::AddVectoredExceptionHandler(FALSE, VEH); | 141 void* id = ::AddVectoredExceptionHandler(FALSE, VEH); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 | 219 |
| 220 DWORD tid; | 220 DWORD tid; |
| 221 HANDLE h = ::CreateThread(0, 0, CrashingThread, 0, 0, &tid); | 221 HANDLE h = ::CreateThread(0, 0, CrashingThread, 0, 0, &tid); |
| 222 ::WaitForSingleObject(h, INFINITE); | 222 ::WaitForSingleObject(h, INFINITE); |
| 223 ::CloseHandle(h); | 223 ::CloseHandle(h); |
| 224 | 224 |
| 225 EXPECT_EQ(2, veh.get_exceptions_seen()); | 225 EXPECT_EQ(2, veh.get_exceptions_seen()); |
| 226 ::RemoveVectoredExceptionHandler(id); | 226 ::RemoveVectoredExceptionHandler(id); |
| 227 g_mock_veh = NULL; | 227 g_mock_veh = NULL; |
| 228 } | 228 } |
| OLD | NEW |