| OLD | NEW |
| 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/crash_dll.h" |
| 9 #include "chrome_frame/crash_reporting/nt_loader.h" |
| 8 #include "chrome_frame/crash_reporting/vectored_handler-impl.h" | 10 #include "chrome_frame/crash_reporting/vectored_handler-impl.h" |
| 9 #include "chrome_frame/crash_reporting/veh_test.h" | 11 #include "chrome_frame/crash_reporting/veh_test.h" |
| 10 #include "testing/gmock/include/gmock/gmock.h" | 12 #include "testing/gmock/include/gmock/gmock.h" |
| 11 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
| 12 | 14 |
| 13 using testing::_; | 15 using testing::_; |
| 14 | 16 |
| 15 ACTION_P(StackTraceDump, s) { | 17 ACTION_P(StackTraceDump, s) { |
| 16 memcpy(arg2, s->stack_, s->count_ * sizeof(s->stack_[0])); | 18 memcpy(arg2, s->stack_, s->count_ * sizeof(s->stack_[0])); |
| 17 return s->count_; | 19 return s->count_; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 38 void SetStack(const StackHelper& s) { | 40 void SetStack(const StackHelper& s) { |
| 39 EXPECT_CALL(*this, RtlCaptureStackBackTrace(_, _, _, _)) | 41 EXPECT_CALL(*this, RtlCaptureStackBackTrace(_, _, _, _)) |
| 40 .Times(testing::AnyNumber()) | 42 .Times(testing::AnyNumber()) |
| 41 .WillRepeatedly(StackTraceDump(&s)); | 43 .WillRepeatedly(StackTraceDump(&s)); |
| 42 } | 44 } |
| 43 | 45 |
| 44 enum {max_back_trace = 15}; | 46 enum {max_back_trace = 15}; |
| 45 }; | 47 }; |
| 46 }; // namespace | 48 }; // namespace |
| 47 | 49 |
| 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); |
| 54 } |
| 48 | 55 |
| 49 typedef VectoredHandlerT<MockApi> VectoredHandlerMock; | |
| 50 TEST(ChromeFrame, ExceptionReport) { | 56 TEST(ChromeFrame, ExceptionReport) { |
| 51 MockApi api; | 57 MockApi api; |
| 52 VectoredHandlerMock veh(&api); | 58 VectoredHandlerMock veh(&api); |
| 53 | 59 |
| 54 // Start address of our module. | 60 // Start address of our module. |
| 55 char* s = reinterpret_cast<char*>(0x30000000); | 61 char* s = reinterpret_cast<char*>(0x30000000); |
| 56 char *e = s + 0x10000; | 62 char *e = s + 0x10000; |
| 57 api.SetModule(s, e); | 63 api.SetModule(s, e); |
| 58 | 64 |
| 59 SEHChain have_seh(s - 0x1000, s + 0x1000, e + 0x7127, NULL); | 65 SEHChain have_seh(s - 0x1000, s + 0x1000, e + 0x7127, NULL); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 115 veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, ignore_address))); | 121 veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, ignore_address))); |
| 116 testing::Mock::VerifyAndClearExpectations(&api); | 122 testing::Mock::VerifyAndClearExpectations(&api); |
| 117 | 123 |
| 118 // Exception, in IsBadStringPtrA, we are not on the stack. | 124 // Exception, in IsBadStringPtrA, we are not on the stack. |
| 119 api.SetSEH(no_seh); | 125 api.SetSEH(no_seh); |
| 120 api.SetStack(not_on_stack); | 126 api.SetStack(not_on_stack); |
| 121 EXPECT_CALL(api, WriteDump(_)).Times(0); | 127 EXPECT_CALL(api, WriteDump(_)).Times(0); |
| 122 EXPECT_EQ(ExceptionContinueSearch, | 128 EXPECT_EQ(ExceptionContinueSearch, |
| 123 veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, ignore_address))); | 129 veh.Handler(&ExceptionInfo(STATUS_ACCESS_VIOLATION, ignore_address))); |
| 124 testing::Mock::VerifyAndClearExpectations(&api); | 130 testing::Mock::VerifyAndClearExpectations(&api); |
| 131 |
| 132 // Exception in a loading module, we are on the stack. |
| 133 // Make sure we don't report it. |
| 134 api.SetSEH(no_seh); |
| 135 api.SetStack(on_stack); |
| 136 EXPECT_CALL(api, WriteDump(_)).Times(0); |
| 137 |
| 138 g_mock_veh = &veh; |
| 139 void* id = ::AddVectoredExceptionHandler(FALSE, VEH); |
| 140 |
| 141 EXPECT_TRUE(::SetEnvironmentVariable(kCrashOnLoadMode, L"1")); |
| 142 long exceptions_seen = veh.get_exceptions_seen(); |
| 143 HMODULE module = ::LoadLibrary(kCrashDllName); |
| 144 EXPECT_EQ(NULL, module); |
| 145 |
| 146 testing::Mock::VerifyAndClearExpectations(&api); |
| 147 EXPECT_EQ(exceptions_seen + 1, veh.get_exceptions_seen()); |
| 148 EXPECT_TRUE(::SetEnvironmentVariable(kCrashOnLoadMode, NULL)); |
| 149 |
| 150 // Exception in an unloading module, we are on the stack/ |
| 151 // Make sure we report it. |
| 152 EXPECT_TRUE(::SetEnvironmentVariable(kCrashOnUnloadMode, L"1")); |
| 153 |
| 154 module = ::LoadLibrary(kCrashDllName); |
| 155 |
| 156 api.SetSEH(no_seh); |
| 157 api.SetStack(on_stack); |
| 158 EXPECT_CALL(api, WriteDump(_)).Times(1); |
| 159 EXPECT_TRUE(module != NULL); |
| 160 exceptions_seen = veh.get_exceptions_seen(); |
| 161 |
| 162 // Crash on unloading. |
| 163 ::FreeLibrary(module); |
| 164 |
| 165 EXPECT_EQ(exceptions_seen + 1, veh.get_exceptions_seen()); |
| 166 testing::Mock::VerifyAndClearExpectations(&api); |
| 167 |
| 168 ::RemoveVectoredExceptionHandler(id); |
| 169 g_mock_veh = NULL; |
| 125 } | 170 } |
| 126 | 171 |
| 127 MATCHER_P(ExceptionCodeIs, code, "") { | 172 MATCHER_P(ExceptionCodeIs, code, "") { |
| 128 return (arg->ExceptionRecord->ExceptionCode == code); | 173 return (arg->ExceptionRecord->ExceptionCode == code); |
| 129 } | 174 } |
| 130 | 175 |
| 131 DECLSPEC_NOINLINE static void OverflowStack() { | 176 DECLSPEC_NOINLINE static void OverflowStack() { |
| 132 char tmp[1024 * 2048] = {0}; | 177 char tmp[1024 * 2048] = {0}; |
| 133 GetSystemInfo(reinterpret_cast<SYSTEM_INFO*>(&tmp)); | 178 GetSystemInfo(reinterpret_cast<SYSTEM_INFO*>(&tmp)); |
| 134 } | 179 } |
| 135 | 180 |
| 136 DWORD WINAPI CrashingThread(PVOID tmp) { | 181 DWORD WINAPI CrashingThread(PVOID tmp) { |
| 137 __try { | 182 __try { |
| 138 OverflowStack(); | 183 OverflowStack(); |
| 139 } __except(EXCEPTION_EXECUTE_HANDLER) { | 184 } __except(EXCEPTION_EXECUTE_HANDLER) { |
| 140 | 185 |
| 141 } | 186 } |
| 142 | 187 |
| 143 // This will cause STATUS_ACCESS_VIOLATION | 188 // This will cause STATUS_ACCESS_VIOLATION |
| 144 __try { | 189 __try { |
| 145 OverflowStack(); | 190 OverflowStack(); |
| 146 } __except(EXCEPTION_EXECUTE_HANDLER) { | 191 } __except(EXCEPTION_EXECUTE_HANDLER) { |
| 147 | 192 |
| 148 } | 193 } |
| 149 | 194 |
| 150 return 0; | 195 return 0; |
| 151 } | 196 } |
| 152 | 197 |
| 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) { | 198 TEST(ChromeFrame, TrickyStackOverflow) { |
| 159 MockApi api; | 199 MockApi api; |
| 160 VectoredHandlerMock veh(&api); | 200 VectoredHandlerMock veh(&api); |
| 161 | 201 |
| 162 // Start address of our module. | 202 // Start address of our module. |
| 163 char* s = reinterpret_cast<char*>(0x30000000); | 203 char* s = reinterpret_cast<char*>(0x30000000); |
| 164 char *e = s + 0x10000; | 204 char *e = s + 0x10000; |
| 165 api.SetModule(s, e); | 205 api.SetModule(s, e); |
| 166 | 206 |
| 167 SEHChain no_seh(s - 0x1000, e + 0x7127, NULL); | 207 SEHChain no_seh(s - 0x1000, e + 0x7127, NULL); |
| 168 StackHelper on_stack(s - 0x11283, s - 0x278361, s + 0x9171, e + 1231, NULL); | 208 StackHelper on_stack(s - 0x11283, s - 0x278361, s + 0x9171, e + 1231, NULL); |
| 169 api.SetSEH(no_seh); | 209 api.SetSEH(no_seh); |
| 170 api.SetStack(on_stack); | 210 api.SetStack(on_stack); |
| 171 | 211 |
| 172 EXPECT_CALL(api, WriteDump(ExceptionCodeIs(STATUS_STACK_OVERFLOW))).Times(1); | 212 EXPECT_CALL(api, WriteDump(ExceptionCodeIs(STATUS_STACK_OVERFLOW))).Times(1); |
| 173 | 213 |
| 174 g_mock_veh = &veh; | 214 g_mock_veh = &veh; |
| 175 void* id = ::AddVectoredExceptionHandler(FALSE, VEH); | 215 void* id = ::AddVectoredExceptionHandler(FALSE, VEH); |
| 176 | 216 |
| 177 DWORD tid; | 217 DWORD tid; |
| 178 HANDLE h = ::CreateThread(0, 0, CrashingThread, 0, 0, &tid); | 218 HANDLE h = ::CreateThread(0, 0, CrashingThread, 0, 0, &tid); |
| 179 ::WaitForSingleObject(h, INFINITE); | 219 ::WaitForSingleObject(h, INFINITE); |
| 180 ::CloseHandle(h); | 220 ::CloseHandle(h); |
| 181 | 221 |
| 182 EXPECT_EQ(2, veh.get_exceptions_seen()); | 222 EXPECT_EQ(2, veh.get_exceptions_seen()); |
| 183 ::RemoveVectoredExceptionHandler(id); | 223 ::RemoveVectoredExceptionHandler(id); |
| 184 g_mock_veh = NULL; | 224 g_mock_veh = NULL; |
| 185 } | 225 } |
| OLD | NEW |