Don't override system malloc when built with MemorySanitizer.
[chromium-blink-merge.git] / chrome_frame / crash_reporting / vectored_handler_unittest.cc
blob6f7e597d5243a330872131635d872eb49a771204
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <atlbase.h>
7 #include "base/environment.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/utf_string_conversions.h"
10 #include "chrome_frame/crash_reporting/crash_dll.h"
11 #include "chrome_frame/crash_reporting/nt_loader.h"
12 #include "chrome_frame/crash_reporting/vectored_handler-impl.h"
13 #include "chrome_frame/crash_reporting/veh_test.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
17 using testing::_;
19 ACTION_P(StackTraceDump, s) {
20 memcpy(arg2, s->stack_, s->count_ * sizeof(s->stack_[0]));
21 return s->count_;
23 namespace {
24 class MockApi : public Win32VEHTraits, public ModuleOfInterest {
25 public:
26 MockApi() {}
28 MOCK_METHOD1(WriteDump, void(const EXCEPTION_POINTERS*));
29 MOCK_METHOD0(RtlpGetExceptionList, const EXCEPTION_REGISTRATION_RECORD*());
30 MOCK_METHOD4(RtlCaptureStackBackTrace, WORD(DWORD FramesToSkip,
31 DWORD FramesToCapture, void** BackTrace, DWORD* BackTraceHash));
33 // Helpers
34 void SetSEH(const SEHChain& sehchain) {
35 EXPECT_CALL(*this, RtlpGetExceptionList())
36 .Times(testing::AnyNumber())
37 .WillRepeatedly(testing::Return(sehchain.chain_));
40 void SetStack(const StackHelper& s) {
41 EXPECT_CALL(*this, RtlCaptureStackBackTrace(_, _, _, _))
42 .Times(testing::AnyNumber())
43 .WillRepeatedly(StackTraceDump(&s));
46 enum {max_back_trace = 15};
48 }; // namespace
50 typedef VectoredHandlerT<MockApi> VectoredHandlerMock;
51 static VectoredHandlerMock* g_mock_veh = NULL;
52 static LONG WINAPI VEH(EXCEPTION_POINTERS* exptrs) {
53 return g_mock_veh->Handler(exptrs);
56 TEST(ChromeFrame, ExceptionReport) {
57 MockApi api;
58 VectoredHandlerMock veh(&api);
60 // Start address of our module.
61 char* s = reinterpret_cast<char*>(&__ImageBase);
62 char *e = s + 0x10000;
63 api.SetModule(s, e);
65 SEHChain have_seh(s - 0x1000, s + 0x1000, e + 0x7127, NULL);
66 SEHChain no_seh(s - 0x1000, e + 0x7127, NULL);
67 StackHelper on_stack(s - 0x11283, s - 0x278361, s + 0x9171, e + 1231, NULL);
68 StackHelper not_on_stack(s - 0x11283, s - 0x278361, e + 1231, NULL);
70 char* our_code = s + 0x1111;
71 char* not_our_code = s - 0x5555;
72 char* not_our_code2 = e + 0x5555;
74 // Exception in our code, but we have SEH filter => no dump.
75 api.SetSEH(have_seh);
76 api.SetStack(on_stack);
77 EXPECT_CALL(api, WriteDump(_)).Times(0);
78 EXPECT_EQ(ExceptionContinueSearch,
79 veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, our_code)));
80 testing::Mock::VerifyAndClearExpectations(&api);
82 // RPC_E_DISCONNECTED (0x80010108) is "The object invoked has disconnected
83 // from its clients", shall not be caught since it's a warning only.
84 EXPECT_CALL(api, WriteDump(_)).Times(0);
85 EXPECT_CALL(api, RtlpGetExceptionList()).Times(0);
86 EXPECT_EQ(ExceptionContinueSearch,
87 veh.Handler(&ExceptionInfo(RPC_E_DISCONNECTED, our_code)));
88 testing::Mock::VerifyAndClearExpectations(&api);
90 // Exception, not in our code, we do not have SEH and we are not in stack.
91 api.SetSEH(no_seh);
92 api.SetStack(not_on_stack);
93 EXPECT_CALL(api, WriteDump(_)).Times(0);
94 EXPECT_EQ(ExceptionContinueSearch,
95 veh.Handler(&ExceptionInfo(STATUS_INTEGER_DIVIDE_BY_ZERO, not_our_code)));
96 testing::Mock::VerifyAndClearExpectations(&api);
98 // Exception, not in our code, no SEH, but we are on the stack.
99 api.SetSEH(no_seh);
100 api.SetStack(on_stack);
101 EXPECT_CALL(api, WriteDump(_)).Times(1);
102 EXPECT_EQ(ExceptionContinueSearch,
103 veh.Handler(&ExceptionInfo(STATUS_INTEGER_DIVIDE_BY_ZERO,
104 not_our_code2)));
105 testing::Mock::VerifyAndClearExpectations(&api);
107 // Exception, in our code, no SEH, not on stack (assume FPO screwed us)
108 api.SetSEH(no_seh);
109 api.SetStack(not_on_stack);
110 EXPECT_CALL(api, WriteDump(_)).Times(1);
111 EXPECT_EQ(ExceptionContinueSearch,
112 veh.Handler(&ExceptionInfo(STATUS_PRIVILEGED_INSTRUCTION, our_code)));
113 testing::Mock::VerifyAndClearExpectations(&api);
115 // Exception, in IsBadStringPtrA, we are on the stack.
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);
120 api.SetStack(on_stack);
121 EXPECT_CALL(api, WriteDump(_)).Times(0);
122 EXPECT_EQ(ExceptionContinueSearch,
123 veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, is_bad_ptr)));
124 testing::Mock::VerifyAndClearExpectations(&api);
126 // Exception, in IsBadStringPtrA, we are not on the stack.
127 api.SetSEH(kernel32_seh);
128 api.SetStack(not_on_stack);
129 EXPECT_CALL(api, WriteDump(_)).Times(0);
130 EXPECT_EQ(ExceptionContinueSearch,
131 veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, is_bad_ptr)));
132 testing::Mock::VerifyAndClearExpectations(&api);
134 // Exception in a loading module, we are on the stack.
135 // Make sure we don't report it.
136 api.SetSEH(no_seh);
137 api.SetStack(on_stack);
138 EXPECT_CALL(api, WriteDump(_)).Times(0);
140 g_mock_veh = &veh;
141 void* id = ::AddVectoredExceptionHandler(FALSE, VEH);
143 scoped_ptr<base::Environment> env(base::Environment::Create());
144 EXPECT_TRUE(env->SetVar(WideToUTF8(kCrashOnLoadMode).c_str(), "1"));
145 long exceptions_seen = veh.get_exceptions_seen();
146 HMODULE module = ::LoadLibrary(kCrashDllName);
147 EXPECT_EQ(NULL, module);
149 testing::Mock::VerifyAndClearExpectations(&api);
150 EXPECT_EQ(exceptions_seen + 1, veh.get_exceptions_seen());
151 EXPECT_TRUE(env->UnSetVar(WideToUTF8(kCrashOnLoadMode).c_str()));
153 // Exception in an unloading module, we are on the stack/
154 // Make sure we report it.
155 EXPECT_TRUE(env->SetVar(WideToUTF8(kCrashOnUnloadMode).c_str(), "1"));
157 module = ::LoadLibrary(kCrashDllName);
159 api.SetSEH(no_seh);
160 api.SetStack(on_stack);
161 EXPECT_CALL(api, WriteDump(_)).Times(1);
162 EXPECT_TRUE(module != NULL);
163 exceptions_seen = veh.get_exceptions_seen();
165 // Crash on unloading.
166 ::FreeLibrary(module);
168 EXPECT_EQ(exceptions_seen + 1, veh.get_exceptions_seen());
169 testing::Mock::VerifyAndClearExpectations(&api);
171 ::RemoveVectoredExceptionHandler(id);
172 g_mock_veh = NULL;
175 MATCHER_P(ExceptionCodeIs, code, "") {
176 return (arg->ExceptionRecord->ExceptionCode == code);
179 DECLSPEC_NOINLINE static void OverflowStack() {
180 char tmp[1024 * 2048] = {0};
181 GetSystemInfo(reinterpret_cast<SYSTEM_INFO*>(&tmp));
184 DWORD WINAPI CrashingThread(PVOID tmp) {
185 __try {
186 OverflowStack();
187 } __except(EXCEPTION_EXECUTE_HANDLER) {
191 // This will cause STATUS_ACCESS_VIOLATION
192 __try {
193 OverflowStack();
194 } __except(EXCEPTION_EXECUTE_HANDLER) {
198 return 0;
201 TEST(ChromeFrame, TrickyStackOverflow) {
202 MockApi api;
203 VectoredHandlerMock veh(&api);
205 // Start address of our module.
206 char* s = reinterpret_cast<char*>(0x30000000);
207 char *e = s + 0x10000;
208 api.SetModule(s, e);
210 SEHChain no_seh(s - 0x1000, e + 0x7127, NULL);
211 StackHelper on_stack(s - 0x11283, s - 0x278361, s + 0x9171, e + 1231, NULL);
212 api.SetSEH(no_seh);
213 api.SetStack(on_stack);
215 EXPECT_CALL(api, WriteDump(ExceptionCodeIs(STATUS_STACK_OVERFLOW))).Times(1);
217 g_mock_veh = &veh;
218 void* id = ::AddVectoredExceptionHandler(FALSE, VEH);
220 DWORD tid;
221 HANDLE h = ::CreateThread(0, 0, CrashingThread, 0, 0, &tid);
222 ::WaitForSingleObject(h, INFINITE);
223 ::CloseHandle(h);
225 EXPECT_EQ(2, veh.get_exceptions_seen());
226 ::RemoveVectoredExceptionHandler(id);
227 g_mock_veh = NULL;