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

Side by Side Diff: chrome_frame/crash_reporting/nt_loader_unittest.cc

Issue 126143005: Remove Chrome Frame code and resources. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: sync to r244038 Created 6 years, 11 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
(Empty)
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 "chrome_frame/crash_reporting/nt_loader.h"
6
7 #include <tlhelp32.h>
8 #include <winnt.h>
9
10 #include "base/at_exit.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/environment.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/sys_info.h"
19 #include "base/threading/thread.h"
20 #include "base/win/scoped_handle.h"
21 #include "chrome_frame/crash_reporting/crash_dll.h"
22 #include "gtest/gtest.h"
23
24 namespace {
25 void AssertIsCriticalSection(CRITICAL_SECTION* critsec) {
26 // Assert on some of the internals of the debug info if it has one.
27 RTL_CRITICAL_SECTION_DEBUG* debug = critsec->DebugInfo;
28 if (debug) {
29 ASSERT_EQ(RTL_CRITSECT_TYPE, debug->Type);
30 ASSERT_EQ(critsec, debug->CriticalSection);
31 }
32
33 // TODO(siggi): assert on the semaphore handle & object type?
34 }
35
36 class ScopedEnterCriticalSection {
37 public:
38 explicit ScopedEnterCriticalSection(CRITICAL_SECTION* critsec)
39 : critsec_(critsec) {
40 ::EnterCriticalSection(critsec_);
41 }
42
43 ~ScopedEnterCriticalSection() {
44 ::LeaveCriticalSection(critsec_);
45 }
46
47 private:
48 CRITICAL_SECTION* critsec_;
49 };
50
51 std::wstring FromUnicodeString(const UNICODE_STRING& str) {
52 return std::wstring(str.Buffer, str.Length / sizeof(str.Buffer[0]));
53 }
54
55 } // namespace
56
57 using namespace nt_loader;
58
59 TEST(NtLoader, OwnsCriticalSection) {
60 // Use of Thread requires an atexit manager.
61 base::AtExitManager at_exit;
62
63 CRITICAL_SECTION cs = {};
64 ::InitializeCriticalSection(&cs);
65 EXPECT_FALSE(OwnsCriticalSection(&cs));
66
67 // Enter the critsec and assert we own it.
68 {
69 ScopedEnterCriticalSection lock1(&cs);
70
71 EXPECT_TRUE(OwnsCriticalSection(&cs));
72
73 // Re-enter the critsec and assert we own it.
74 ScopedEnterCriticalSection lock2(&cs);
75
76 EXPECT_TRUE(OwnsCriticalSection(&cs));
77 }
78
79 // Should no longer own it.
80 EXPECT_FALSE(OwnsCriticalSection(&cs));
81
82 // Make another thread grab it.
83 base::Thread other("Other threads");
84 ASSERT_TRUE(other.Start());
85 other.message_loop()->PostTask(
86 FROM_HERE, base::Bind(::EnterCriticalSection, &cs));
87
88 base::win::ScopedHandle event(::CreateEvent(NULL, FALSE, FALSE, NULL));
89 other.message_loop()->PostTask(
90 FROM_HERE, base::Bind(base::IgnoreResult(::SetEvent), event.Get()));
91
92 ASSERT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(event.Get(), INFINITE));
93
94 // We still shouldn't own it - the other thread does.
95 EXPECT_FALSE(OwnsCriticalSection(&cs));
96 // And we shouldn't be able to enter it.
97 EXPECT_EQ(0, ::TryEnterCriticalSection(&cs));
98
99 // Make the other thread release it.
100 other.message_loop()->PostTask(
101 FROM_HERE, base::Bind(::LeaveCriticalSection, &cs));
102
103 other.Stop();
104
105 ::DeleteCriticalSection(&cs);
106 }
107
108 TEST(NtLoader, GetLoaderLock) {
109 CRITICAL_SECTION* loader_lock = GetLoaderLock();
110
111 AssertIsCriticalSection(loader_lock);
112
113 // We should be able to enter and leave the loader's lock without trouble.
114 EnterCriticalSection(loader_lock);
115 LeaveCriticalSection(loader_lock);
116 }
117
118 TEST(NtLoader, OwnsLoaderLock) {
119 CRITICAL_SECTION* loader_lock = GetLoaderLock();
120
121 EXPECT_FALSE(OwnsLoaderLock());
122 EnterCriticalSection(loader_lock);
123 EXPECT_TRUE(OwnsLoaderLock());
124 LeaveCriticalSection(loader_lock);
125 EXPECT_FALSE(OwnsLoaderLock());
126 }
127
128 TEST(NtLoader, GetLoaderEntry) {
129 // Get all modules in the current process.
130 base::win::ScopedHandle snap(
131 ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ::GetCurrentProcessId()));
132 EXPECT_TRUE(snap.Get() != NULL);
133
134 // Walk them, while checking we get an entry for each, and that it
135 // contains sane information.
136 MODULEENTRY32 module = { sizeof(module) };
137 ASSERT_TRUE(::Module32First(snap.Get(), &module));
138 do {
139 ScopedEnterCriticalSection lock(GetLoaderLock());
140
141 nt_loader::LDR_DATA_TABLE_ENTRY* entry =
142 nt_loader::GetLoaderEntry(module.hModule);
143 ASSERT_TRUE(entry != NULL);
144 EXPECT_EQ(module.hModule, reinterpret_cast<HMODULE>(entry->DllBase));
145 EXPECT_STREQ(module.szModule,
146 FromUnicodeString(entry->BaseDllName).c_str());
147 EXPECT_STREQ(module.szExePath,
148 FromUnicodeString(entry->FullDllName).c_str());
149
150 ULONG flags = entry->Flags;
151
152 // All entries should have this flag set.
153 EXPECT_TRUE(flags & LDRP_ENTRY_PROCESSED);
154
155 if (0 == (flags & LDRP_IMAGE_DLL)) {
156 // TODO(siggi): write a test to assert this holds true for loading
157 // non-DLL, e.g. exe image files.
158 // Dlls have the LDRP_IMAGE_DLL flag set, any module that doesn't
159 // have that flag has to be the main executable.
160 EXPECT_TRUE(module.hModule == ::GetModuleHandle(NULL));
161 } else {
162 // Since we're not currently loading any modules, all loaded
163 // modules should either have the LDRP_PROCESS_ATTACH_CALLED,
164 // or a NULL entrypoint.
165 if (entry->EntryPoint == NULL) {
166 EXPECT_FALSE(flags & LDRP_PROCESS_ATTACH_CALLED);
167 } else {
168 // Shimeng.dll is an exception to the above, it's loaded
169 // in a special way, see e.g. http://www.alex-ionescu.com/?p=41
170 // for details.
171 bool is_shimeng = LowerCaseEqualsASCII(
172 FromUnicodeString(entry->BaseDllName), "shimeng.dll");
173
174 EXPECT_TRUE(is_shimeng || (flags & LDRP_PROCESS_ATTACH_CALLED));
175 }
176 }
177 } while (::Module32Next(snap.Get(), &module));
178 }
179
180 namespace {
181
182 typedef void (*ExceptionFunction)(EXCEPTION_POINTERS* ex_ptrs);
183
184 class NtLoaderTest: public testing::Test {
185 public:
186 NtLoaderTest() : veh_id_(NULL), exception_function_(NULL) {
187 EXPECT_EQ(NULL, current_);
188 current_ = this;
189 }
190
191 ~NtLoaderTest() {
192 EXPECT_TRUE(this == current_);
193 current_ = NULL;
194 }
195
196 void SetUp() {
197 veh_id_ = ::AddVectoredExceptionHandler(FALSE, &ExceptionHandler);
198 EXPECT_TRUE(veh_id_ != NULL);
199
200 // Clear the crash DLL environment.
201 scoped_ptr<base::Environment> env(base::Environment::Create());
202 env->UnSetVar(WideToASCII(kCrashOnLoadMode).c_str());
203 env->UnSetVar(WideToASCII(kCrashOnUnloadMode).c_str());
204 }
205
206 void TearDown() {
207 if (veh_id_ != NULL)
208 EXPECT_NE(0, ::RemoveVectoredExceptionHandler(veh_id_));
209
210 // Clear the crash DLL environment.
211 scoped_ptr<base::Environment> env(base::Environment::Create());
212 env->UnSetVar(WideToASCII(kCrashOnLoadMode).c_str());
213 env->UnSetVar(WideToASCII(kCrashOnUnloadMode).c_str());
214 }
215
216 void set_exception_function(ExceptionFunction func) {
217 exception_function_ = func;
218 }
219
220 private:
221 static LONG NTAPI ExceptionHandler(EXCEPTION_POINTERS* ex_ptrs){
222 // Dispatch the exception to any exception function,
223 // but only on the main thread.
224 if (main_thread_ == ::GetCurrentThreadId() &&
225 current_ != NULL &&
226 current_->exception_function_ != NULL)
227 current_->exception_function_(ex_ptrs);
228
229 return ExceptionContinueSearch;
230 }
231
232 void* veh_id_;
233 ExceptionFunction exception_function_;
234
235 static NtLoaderTest* current_;
236 static DWORD main_thread_;
237 };
238
239 NtLoaderTest* NtLoaderTest::current_ = NULL;
240 DWORD NtLoaderTest::main_thread_ = ::GetCurrentThreadId();
241
242 } // namespace
243
244 static int exceptions_handled = 0;
245 static void OnCrashDuringLoadLibrary(EXCEPTION_POINTERS* ex_ptrs) {
246 ASSERT_EQ(STATUS_ACCESS_VIOLATION, ex_ptrs->ExceptionRecord->ExceptionCode);
247 ASSERT_EQ(2, ex_ptrs->ExceptionRecord->NumberParameters);
248 ASSERT_EQ(EXCEPTION_WRITE_FAULT,
249 ex_ptrs->ExceptionRecord->ExceptionInformation[0]);
250 ASSERT_EQ(kCrashAddress,
251 ex_ptrs->ExceptionRecord->ExceptionInformation[1]);
252
253 // Bump the exceptions count.
254 exceptions_handled++;
255
256 EXPECT_TRUE(OwnsLoaderLock());
257
258 HMODULE crash_dll = ::GetModuleHandle(kCrashDllName);
259 ASSERT_TRUE(crash_dll != NULL);
260
261 nt_loader::LDR_DATA_TABLE_ENTRY* entry = GetLoaderEntry(crash_dll);
262 ASSERT_TRUE(entry != NULL);
263 ASSERT_EQ(0, entry->Flags & LDRP_PROCESS_ATTACH_CALLED);
264 }
265
266 TEST_F(NtLoaderTest, CrashOnLoadLibrary) {
267 exceptions_handled = 0;
268 set_exception_function(OnCrashDuringLoadLibrary);
269
270 // Setup to crash on load.
271 scoped_ptr<base::Environment> env(base::Environment::Create());
272 env->SetVar(WideToASCII(kCrashOnLoadMode).c_str(), "1");
273
274 // And load it.
275 HMODULE module = ::LoadLibrary(kCrashDllName);
276 DWORD err = ::GetLastError();
277 EXPECT_EQ(NULL, module);
278 EXPECT_EQ(ERROR_NOACCESS, err);
279 EXPECT_EQ(1, exceptions_handled);
280
281 if (module != NULL)
282 ::FreeLibrary(module);
283 }
284
285 static void OnCrashDuringUnloadLibrary(EXCEPTION_POINTERS* ex_ptrs) {
286 ASSERT_EQ(STATUS_ACCESS_VIOLATION, ex_ptrs->ExceptionRecord->ExceptionCode);
287 ASSERT_EQ(2, ex_ptrs->ExceptionRecord->NumberParameters);
288 ASSERT_EQ(EXCEPTION_WRITE_FAULT,
289 ex_ptrs->ExceptionRecord->ExceptionInformation[0]);
290 ASSERT_EQ(kCrashAddress,
291 ex_ptrs->ExceptionRecord->ExceptionInformation[1]);
292
293 // Bump the exceptions count.
294 exceptions_handled++;
295
296 EXPECT_TRUE(OwnsLoaderLock());
297
298 HMODULE crash_dll = ::GetModuleHandle(kCrashDllName);
299 ASSERT_TRUE(crash_dll == NULL);
300
301 nt_loader::LDR_DATA_TABLE_ENTRY* entry = GetLoaderEntry(crash_dll);
302 ASSERT_TRUE(entry == NULL);
303 }
304
305 TEST_F(NtLoaderTest, CrashOnUnloadLibrary) {
306 // Setup to crash on unload.
307 scoped_ptr<base::Environment> env(base::Environment::Create());
308 env->SetVar(WideToASCII(kCrashOnUnloadMode).c_str(), "1");
309
310 // And load it.
311 HMODULE module = ::LoadLibrary(kCrashDllName);
312 EXPECT_TRUE(module != NULL);
313
314 exceptions_handled = 0;
315 set_exception_function(OnCrashDuringUnloadLibrary);
316
317 // We should crash during unload.
318 if (module != NULL)
319 ::FreeLibrary(module);
320
321 EXPECT_EQ(1, exceptions_handled);
322 }
OLDNEW
« no previous file with comments | « chrome_frame/crash_reporting/nt_loader.cc ('k') | chrome_frame/crash_reporting/vectored_handler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698