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 |