- add sources.
[platform/framework/web/crosswalk.git] / src / chrome_frame / crash_reporting / vectored_handler_unittest.cc
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.
4
5 #include <atlbase.h>
6
7 #include "base/environment.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/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"
16
17 using testing::_;
18
19 ACTION_P(StackTraceDump, s) {
20   memcpy(arg2, s->stack_, s->count_ * sizeof(s->stack_[0]));
21   return s->count_;
22 }
23 namespace {
24 class MockApi : public Win32VEHTraits, public ModuleOfInterest {
25  public:
26   MockApi() {}
27
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));
32
33   // Helpers
34   void SetSEH(const SEHChain& sehchain) {
35     EXPECT_CALL(*this, RtlpGetExceptionList())
36         .Times(testing::AnyNumber())
37         .WillRepeatedly(testing::Return(sehchain.chain_));
38   }
39
40   void SetStack(const StackHelper& s) {
41     EXPECT_CALL(*this, RtlCaptureStackBackTrace(_, _, _, _))
42         .Times(testing::AnyNumber())
43         .WillRepeatedly(StackTraceDump(&s));
44   }
45
46   enum {max_back_trace = 15};
47 };
48 };  // namespace
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 }
55
56 TEST(ChromeFrame, ExceptionReport) {
57   MockApi api;
58   VectoredHandlerMock veh(&api);
59
60   // Start address of our module.
61   char* s = reinterpret_cast<char*>(&__ImageBase);
62   char *e = s + 0x10000;
63   api.SetModule(s, e);
64
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);
69
70   char* our_code = s + 0x1111;
71   char* not_our_code = s - 0x5555;
72   char* not_our_code2 = e + 0x5555;
73
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);
81
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);
89
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);
97
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);
106
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);
114
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);
125
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);
133
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);
139
140   g_mock_veh = &veh;
141   void* id = ::AddVectoredExceptionHandler(FALSE, VEH);
142
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);
148
149   testing::Mock::VerifyAndClearExpectations(&api);
150   EXPECT_EQ(exceptions_seen + 1, veh.get_exceptions_seen());
151   EXPECT_TRUE(env->UnSetVar(WideToUTF8(kCrashOnLoadMode).c_str()));
152
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"));
156
157   module = ::LoadLibrary(kCrashDllName);
158
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();
164
165   // Crash on unloading.
166   ::FreeLibrary(module);
167
168   EXPECT_EQ(exceptions_seen + 1, veh.get_exceptions_seen());
169   testing::Mock::VerifyAndClearExpectations(&api);
170
171   ::RemoveVectoredExceptionHandler(id);
172   g_mock_veh = NULL;
173 }
174
175 MATCHER_P(ExceptionCodeIs, code, "") {
176   return (arg->ExceptionRecord->ExceptionCode == code);
177 }
178
179 DECLSPEC_NOINLINE static void OverflowStack() {
180   char tmp[1024 * 2048] = {0};
181   GetSystemInfo(reinterpret_cast<SYSTEM_INFO*>(&tmp));
182 }
183
184 DWORD WINAPI CrashingThread(PVOID tmp) {
185   __try {
186     OverflowStack();
187   } __except(EXCEPTION_EXECUTE_HANDLER) {
188
189   }
190
191   // This will cause STATUS_ACCESS_VIOLATION
192   __try {
193     OverflowStack();
194   } __except(EXCEPTION_EXECUTE_HANDLER) {
195
196   }
197
198   return 0;
199 }
200
201 TEST(ChromeFrame, TrickyStackOverflow) {
202   MockApi api;
203   VectoredHandlerMock veh(&api);
204
205   // Start address of our module.
206   char* s = reinterpret_cast<char*>(0x30000000);
207   char *e = s + 0x10000;
208   api.SetModule(s, e);
209
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);
214
215   EXPECT_CALL(api, WriteDump(ExceptionCodeIs(STATUS_STACK_OVERFLOW))).Times(1);
216
217   g_mock_veh = &veh;
218   void* id = ::AddVectoredExceptionHandler(FALSE, VEH);
219
220   DWORD tid;
221   HANDLE h = ::CreateThread(0, 0, CrashingThread, 0, 0, &tid);
222   ::WaitForSingleObject(h, INFINITE);
223   ::CloseHandle(h);
224
225   EXPECT_EQ(2, veh.get_exceptions_seen());
226   ::RemoveVectoredExceptionHandler(id);
227   g_mock_veh = NULL;
228 }