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

Side by Side 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, 10 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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/logging.h" 7 #include "base/logging.h"
8 #include "chrome_frame/crash_reporting/vectored_handler-impl.h" 8 #include "chrome_frame/crash_reporting/vectored_handler-impl.h"
9 #include "chrome_frame/crash_reporting/crash_report.h" 9 #include "chrome_frame/crash_reporting/veh_test.h"
10 #include "gmock/gmock.h" 10 #include "testing/gmock/include/gmock/gmock.h"
11 #include "testing/gtest/include/gtest/gtest.h" 11 #include "testing/gtest/include/gtest/gtest.h"
12 12
13 // Class that mocks external call from VectoredHandlerT for testing purposes. 13 using testing::_;
14 class EMock : public Win32VEHTraits { 14
15 ACTION_P(StackTraceDump, s) {
16 memcpy(arg2, s->stack_, s->count_ * sizeof(s->stack_[0]));
17 return s->count_;
18 }
19 namespace {
20 class MockApi : public Win32VEHTraits, public ModuleOfInterest {
15 public: 21 public:
16 static inline bool WriteDump(EXCEPTION_POINTERS* p) { 22 MockApi() {
17 g_dump_made = true; 23 Win32VEHTraits::InitializeIgnoredBlocks();
18 return true;
19 } 24 }
20 25
21 static inline void* Register(PVECTORED_EXCEPTION_HANDLER func, 26 MOCK_METHOD1(WriteDump, void(const EXCEPTION_POINTERS*));
22 const void* module_start, 27 MOCK_METHOD0(RtlpGetExceptionList, const EXCEPTION_REGISTRATION_RECORD*());
23 const void* module_end) { 28 MOCK_METHOD4(RtlCaptureStackBackTrace, WORD(DWORD FramesToSkip,
24 InitializeIgnoredBlocks(); 29 DWORD FramesToCapture, void** BackTrace, DWORD* BackTraceHash));
25 VEHTraitsBase::SetModule(module_start, module_end); 30
26 // Return some arbitrary number, expecting to get the same on Unregister() 31 // Helpers
27 return reinterpret_cast<void*>(4); 32 void SetSEH(const SEHChain& sehchain) {
33 EXPECT_CALL(*this, RtlpGetExceptionList())
34 .Times(testing::AnyNumber())
35 .WillRepeatedly(testing::Return(sehchain.chain_));
28 } 36 }
29 37
30 static inline ULONG Unregister(void* handle) { 38 void SetStack(const StackHelper& s) {
31 EXPECT_EQ(handle, reinterpret_cast<void*>(4)); 39 EXPECT_CALL(*this, RtlCaptureStackBackTrace(_, _, _, _))
32 return 1; 40 .Times(testing::AnyNumber())
41 .WillRepeatedly(StackTraceDump(&s));
33 } 42 }
34 43
35 static inline WORD RtlCaptureStackBackTrace(DWORD FramesToSkip, 44 enum {max_back_trace = 15};
36 DWORD FramesToCapture, void** BackTrace, DWORD* BackTraceHash) {
37 EXPECT_EQ(2, FramesToSkip);
38 EXPECT_LE(FramesToSkip + FramesToCapture,
39 VectoredHandlerBase::max_back_trace);
40 memcpy(BackTrace, g_stack, g_stack_entries * sizeof(BackTrace[0]));
41 return g_stack_entries;
42 }
43
44 static inline EXCEPTION_REGISTRATION_RECORD* RtlpGetExceptionList() {
45 return g_seh_chain;
46 }
47
48 // Test helpers
49
50 // Create fake SEH chain of random filters - with and without our module.
51 static void SetHaveSEHFilter() {
52 SetSEHChain(reinterpret_cast<const char*>(g_module_start) - 0x1000,
53 reinterpret_cast<const char*>(g_module_start) + 0x1000,
54 reinterpret_cast<const char*>(g_module_end) + 0x7127,
55 NULL);
56 }
57
58 static void SetNoSEHFilter() {
59 SetSEHChain(reinterpret_cast<const char*>(g_module_start) - 0x1000,
60 reinterpret_cast<const char*>(g_module_end) + 0x7127,
61 NULL);
62 }
63
64 // Create fake stack - with and without our module.
65 static void SetOnStack() {
66 SetStack(reinterpret_cast<const char*>(g_module_start) - 0x11283,
67 reinterpret_cast<const char*>(g_module_start) - 0x278361,
68 reinterpret_cast<const char*>(g_module_start) + 0x9171,
69 reinterpret_cast<const char*>(g_module_end) + 1231,
70 NULL);
71 }
72
73 static void SetNotOnStack() {
74 SetStack(reinterpret_cast<const char*>(g_module_start) - 0x11283,
75 reinterpret_cast<const char*>(g_module_start) - 0x278361,
76 reinterpret_cast<const char*>(g_module_end) + 1231,
77 NULL);
78 }
79
80 // Populate stack array
81 static void SetStack(const void* p, ...) {
82 va_list vl;
83 va_start(vl, p);
84 g_stack_entries = 0;
85 for (; p; ++g_stack_entries) {
86 CHECK(g_stack_entries < arraysize(g_stack));
87 g_stack[g_stack_entries] = p;
88 p = va_arg(vl, const void*);
89 }
90 }
91
92 static void SetSEHChain(const void* p, ...) {
93 va_list vl;
94 va_start(vl, p);
95 int i = 0;
96 for (; p; ++i) {
97 CHECK(i + 1 < arraysize(g_seh_chain));
98 g_seh_chain[i].Handler = const_cast<void*>(p);
99 g_seh_chain[i].Next = &g_seh_chain[i + 1];
100 p = va_arg(vl, const void*);
101 }
102
103 g_seh_chain[i].Next = EXCEPTION_CHAIN_END;
104 }
105
106 static EXCEPTION_REGISTRATION_RECORD g_seh_chain[25];
107 static const void* g_stack[VectoredHandlerBase::max_back_trace];
108 static WORD g_stack_entries;
109 static bool g_dump_made;
110 }; 45 };
111 46 }; // namespace
112 EXCEPTION_REGISTRATION_RECORD EMock::g_seh_chain[25];
113 const void* EMock::g_stack[VectoredHandlerBase::max_back_trace];
114 WORD EMock::g_stack_entries;
115 bool EMock::g_dump_made;
116
117 typedef VectoredHandlerT<EMock> VectoredHandlerMock;
118
119 class ExPtrsHelper : public _EXCEPTION_POINTERS {
120 public:
121 ExPtrsHelper() {
122 ExceptionRecord = &er_;
123 ContextRecord = &ctx_;
124 ZeroMemory(&er_, sizeof(er_));
125 ZeroMemory(&ctx_, sizeof(ctx_));
126 }
127
128 void Set(DWORD code, void* address, DWORD flags) {
129 er_.ExceptionCode = code;
130 er_.ExceptionAddress = address;
131 er_.ExceptionFlags = flags;
132 }
133
134 EXCEPTION_RECORD er_;
135 CONTEXT ctx_;
136 };
137 47
138 48
49 typedef VectoredHandlerT<MockApi> VectoredHandlerMock;
139 TEST(ChromeFrame, ExceptionReport) { 50 TEST(ChromeFrame, ExceptionReport) {
51 MockApi api;
52 VectoredHandlerMock veh(&api);
53
54 // Start address of our module.
140 char* s = reinterpret_cast<char*>(0x30000000); 55 char* s = reinterpret_cast<char*>(0x30000000);
141 char* e = s + 0x10000; 56 char *e = s + 0x10000;
142 void* handler = VectoredHandlerMock::Register(s, e); 57 api.SetModule(s, e);
58
59 SEHChain have_seh(s - 0x1000, s + 0x1000, e + 0x7127, NULL);
60 SEHChain no_seh(s - 0x1000, e + 0x7127, NULL);
61 StackHelper on_stack(s - 0x11283, s - 0x278361, s + 0x9171, e + 1231, NULL);
62 StackHelper not_on_stack(s - 0x11283, s - 0x278361, e + 1231, NULL);
63
143 char* our_code = s + 0x1111; 64 char* our_code = s + 0x1111;
144 char* not_our_code = s - 0x5555; 65 char* not_our_code = s - 0x5555;
145 char* not_our_code2 = e + 0x5555; 66 char* not_our_code2 = e + 0x5555;
146 67
147 ExPtrsHelper ex; 68 // Exception in our code, but we have SEH filter => no dump.
148 // Exception in our code, but we have SEH filter 69 api.SetSEH(have_seh);
149 ex.Set(STATUS_ACCESS_VIOLATION, our_code, 0); 70 api.SetStack(on_stack);
150 EMock::SetHaveSEHFilter(); 71 EXPECT_CALL(api, WriteDump(_)).Times(0);
151 EMock::SetOnStack(); 72 EXPECT_EQ(ExceptionContinueSearch,
152 EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex)); 73 veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, our_code)));
153 EXPECT_EQ(1, VectoredHandlerMock::g_exceptions_seen); 74 testing::Mock::VerifyAndClearExpectations(&api);
154 EXPECT_FALSE(EMock::g_dump_made);
155 75
156 // RPC_E_DISCONNECTED (0x80010108) is "The object invoked has disconnected 76 // RPC_E_DISCONNECTED (0x80010108) is "The object invoked has disconnected
157 // from its clients", shall not be caught since it's a warning only. 77 // from its clients", shall not be caught since it's a warning only.
158 ex.Set(RPC_E_DISCONNECTED, our_code, 0); 78 EXPECT_CALL(api, WriteDump(_)).Times(0);
159 EMock::SetHaveSEHFilter(); 79 EXPECT_EQ(ExceptionContinueSearch,
160 EMock::SetOnStack(); 80 veh.Handler(&ExceptionInfo(RPC_E_DISCONNECTED, our_code)));
161 EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex)); 81 testing::Mock::VerifyAndClearExpectations(&api);
162 EXPECT_EQ(1, VectoredHandlerMock::g_exceptions_seen);
163 EXPECT_FALSE(EMock::g_dump_made);
164
165 82
166 // Exception, not in our code, we do not have SEH and we are not in stack. 83 // Exception, not in our code, we do not have SEH and we are not in stack.
167 ex.Set(STATUS_INTEGER_DIVIDE_BY_ZERO, not_our_code, 0); 84 api.SetSEH(no_seh);
168 EMock::SetNoSEHFilter(); 85 api.SetStack(not_on_stack);
169 EMock::SetNotOnStack(); 86 EXPECT_CALL(api, WriteDump(_)).Times(0);
170 EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex)); 87 EXPECT_EQ(ExceptionContinueSearch,
171 EXPECT_EQ(2, VectoredHandlerMock::g_exceptions_seen); 88 veh.Handler(&ExceptionInfo(STATUS_INTEGER_DIVIDE_BY_ZERO, not_our_code)));
172 EXPECT_FALSE(EMock::g_dump_made); 89 testing::Mock::VerifyAndClearExpectations(&api);
173 90
174 // Exception, not in our code, no SEH, but we are on the stack. 91 // Exception, not in our code, no SEH, but we are on the stack.
175 ex.Set(STATUS_INTEGER_DIVIDE_BY_ZERO, not_our_code2, 0); 92 api.SetSEH(no_seh);
176 EMock::SetNoSEHFilter(); 93 api.SetStack(on_stack);
177 EMock::SetOnStack(); 94 EXPECT_CALL(api, WriteDump(_)).Times(1);
178 EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex)); 95 EXPECT_EQ(ExceptionContinueSearch,
179 EXPECT_EQ(3, VectoredHandlerMock::g_exceptions_seen); 96 veh.Handler(&ExceptionInfo(STATUS_INTEGER_DIVIDE_BY_ZERO,
180 EXPECT_TRUE(EMock::g_dump_made); 97 not_our_code2)));
181 EMock::g_dump_made = false; 98 testing::Mock::VerifyAndClearExpectations(&api);
182
183 99
184 // Exception, in our code, no SEH, not on stack (assume FPO screwed us) 100 // Exception, in our code, no SEH, not on stack (assume FPO screwed us)
185 ex.Set(STATUS_INTEGER_DIVIDE_BY_ZERO, our_code, 0); 101 api.SetSEH(no_seh);
186 EMock::SetNoSEHFilter(); 102 api.SetStack(not_on_stack);
187 EMock::SetNotOnStack(); 103 EXPECT_CALL(api, WriteDump(_)).Times(1);
188 EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex)); 104 EXPECT_EQ(ExceptionContinueSearch,
189 EXPECT_EQ(4, VectoredHandlerMock::g_exceptions_seen); 105 veh.Handler(&ExceptionInfo(STATUS_PRIVILEGED_INSTRUCTION, our_code)));
190 EXPECT_TRUE(EMock::g_dump_made); 106 testing::Mock::VerifyAndClearExpectations(&api);
191 EMock::g_dump_made = false;
192 107
193 // Exception, in IsBadStringPtrA, we are on the stack. 108 // Exception, in IsBadStringPtrA, we are on the stack.
109 api.SetSEH(no_seh);
110 api.SetStack(on_stack);
111 EXPECT_CALL(api, WriteDump(_)).Times(0);
194 char* ignore_address = reinterpret_cast<char*>(GetProcAddress( 112 char* ignore_address = reinterpret_cast<char*>(GetProcAddress(
195 GetModuleHandleA("kernel32.dll"), "IsBadStringPtrA")) + 10; 113 GetModuleHandleA("kernel32.dll"), "IsBadStringPtrA")) + 10;
196 ex.Set(STATUS_ACCESS_VIOLATION, ignore_address + 10, 0); 114 EXPECT_EQ(ExceptionContinueSearch,
197 EMock::SetNoSEHFilter(); 115 veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, ignore_address)));
198 EMock::SetOnStack(); 116 testing::Mock::VerifyAndClearExpectations(&api);
199 EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex));
200 EXPECT_EQ(5, VectoredHandlerMock::g_exceptions_seen);
201 EXPECT_FALSE(EMock::g_dump_made);
202 EMock::g_dump_made = false;
203 117
204 // Exception, in IsBadStringPtrA, we are not in stack. 118 // Exception, in IsBadStringPtrA, we are not on the stack.
205 ex.Set(STATUS_ACCESS_VIOLATION, ignore_address + 10, 0); 119 api.SetSEH(no_seh);
206 EMock::SetNoSEHFilter(); 120 api.SetStack(not_on_stack);
207 EMock::SetNotOnStack(); 121 EXPECT_CALL(api, WriteDump(_)).Times(0);
208 EXPECT_EQ(ExceptionContinueSearch, VectoredHandlerMock::VectoredHandler(&ex)); 122 EXPECT_EQ(ExceptionContinueSearch,
209 EXPECT_EQ(6, VectoredHandlerMock::g_exceptions_seen); 123 veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, ignore_address)));
210 EXPECT_FALSE(EMock::g_dump_made); 124 testing::Mock::VerifyAndClearExpectations(&api);
211 EMock::g_dump_made = false; 125 }
212 126
213 VectoredHandlerMock::Unregister(); 127 MATCHER_P(ExceptionCodeIs, code, "") {
128 return (arg->ExceptionRecord->ExceptionCode == code);
214 } 129 }
130
131 void OverflowStack() {
132 char tmp[1024 * 2048];
133 ZeroMemory(tmp, sizeof(tmp));
amit 2010/01/30 00:52:58 call OverflowStack here again, just to be sure? :)
134 }
135
136 DWORD WINAPI CrashingThread(PVOID tmp) {
137 __try {
138 OverflowStack();
139 } __except(EXCEPTION_EXECUTE_HANDLER) {
140
141 }
142
143 // This will cause STATUS_ACCESS_VIOLATION
144 __try {
145 OverflowStack();
146 } __except(EXCEPTION_EXECUTE_HANDLER) {
147
148 }
149
150 return 0;
151 }
152
153 static VectoredHandlerMock* g_mock_veh = NULL;
154 static LONG WINAPI VEH(EXCEPTION_POINTERS* exptrs) {
155 return g_mock_veh->Handler(exptrs);
156 }
157
158 TEST(ChromeFrame, TrickyStackOverflow) {
159 MockApi api;
160 VectoredHandlerMock veh(&api);
161
162 // Start address of our module.
163 char* s = reinterpret_cast<char*>(0x30000000);
164 char *e = s + 0x10000;
165 api.SetModule(s, e);
166
167 SEHChain no_seh(s - 0x1000, e + 0x7127, NULL);
168 StackHelper on_stack(s - 0x11283, s - 0x278361, s + 0x9171, e + 1231, NULL);
169 api.SetSEH(no_seh);
170 api.SetStack(on_stack);
171
172 EXPECT_CALL(api, WriteDump(ExceptionCodeIs(STATUS_STACK_OVERFLOW))).Times(1);
173
174 g_mock_veh = &veh;
175 void* id = ::AddVectoredExceptionHandler(FALSE, VEH);
176
177 DWORD tid;
178 HANDLE h = ::CreateThread(0, 0, CrashingThread, 0, 0, &tid);
179 ::WaitForSingleObject(h, INFINITE);
180 ::CloseHandle(h);
181
182 EXPECT_EQ(2, veh.get_exceptions_seen());
183 ::RemoveVectoredExceptionHandler(id);
184 g_mock_veh = NULL;
185 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698