1 // Copyright (c) 2010 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.
6 #include "chrome_frame/function_stub.h"
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "testing/gmock/include/gmock/gmock.h"
12 // Test subclass to expose extra stuff.
13 class TestFunctionStub
: public FunctionStub
{
15 static void Init(TestFunctionStub
* stub
) {
16 stub
->FunctionStub::Init(&stub
->stub_
);
19 // Expose the offset to our signature_ field.
20 static const size_t kSignatureOffset
;
22 void set_signature(HMODULE signature
) { signature_
= signature
; }
25 const size_t TestFunctionStub::kSignatureOffset
=
26 FIELD_OFFSET(TestFunctionStub
, signature_
);
28 class FunctionStubTest
: public testing::Test
{
30 FunctionStubTest() : stub_(NULL
) {
33 virtual void SetUp() {
35 ::GetSystemInfo(&sys_info
);
37 // Playpen size is a system page.
38 playpen_size_
= sys_info
.dwPageSize
;
41 playpen_
= reinterpret_cast<uint8
*>(
45 PAGE_EXECUTE_READWRITE
));
46 ASSERT_TRUE(playpen_
!= NULL
);
48 // And commit the first one.
49 ASSERT_TRUE(::VirtualAlloc(playpen_
,
52 PAGE_EXECUTE_READWRITE
));
55 virtual void TearDown() {
57 EXPECT_TRUE(FunctionStub::Destroy(stub_
));
60 if (playpen_
!= NULL
) {
61 EXPECT_TRUE(::VirtualFree(playpen_
, 0, MEM_RELEASE
));
66 typedef uintptr_t (CALLBACK
*FuncPtr0
)();
67 typedef uintptr_t (CALLBACK
*FuncPtr1
)(uintptr_t arg
);
69 MOCK_METHOD0(Foo0
, uintptr_t());
70 MOCK_METHOD1(Foo1
, uintptr_t(uintptr_t));
71 MOCK_METHOD0(Bar0
, uintptr_t());
72 MOCK_METHOD1(Bar1
, uintptr_t(uintptr_t));
74 static uintptr_t CALLBACK
FooCallback0(FunctionStubTest
* test
) {
77 static uintptr_t CALLBACK
FooCallback1(FunctionStubTest
* test
,
79 return test
->Foo1(arg
);
81 static uintptr_t CALLBACK
BarCallback0(FunctionStubTest
* test
) {
84 static uintptr_t CALLBACK
BarCallback1(FunctionStubTest
* test
,
86 return test
->Foo1(arg
);
89 // If a stub is allocated during testing, assigning it here
90 // will deallocate it at the end of test.
93 // playpen_[0 .. playpen_size_ - 1] is committed, writable memory.
94 // playpen_[playpen_size_] is uncommitted, defined memory.
99 const uintptr_t kDivertedRetVal
= 0x42;
100 const uintptr_t kFooRetVal
= 0xCAFEBABE;
101 const uintptr_t kFooArg
= 0xF0F0F0F0;
103 uintptr_t CALLBACK
Foo() {
107 uintptr_t CALLBACK
FooDivert(uintptr_t arg
) {
113 TEST_F(FunctionStubTest
, Accessors
) {
114 uintptr_t argument
= reinterpret_cast<uintptr_t>(this);
115 uintptr_t dest_fn
= reinterpret_cast<uintptr_t>(FooDivert
);
116 stub_
= FunctionStub::Create(argument
, FooDivert
);
118 EXPECT_FALSE(stub_
->is_bypassed());
119 EXPECT_TRUE(stub_
->is_valid());
120 EXPECT_TRUE(stub_
->code() != NULL
);
122 // Check that the stub code is executable.
123 MEMORY_BASIC_INFORMATION info
= {};
124 EXPECT_NE(0u, ::VirtualQuery(stub_
->code(), &info
, sizeof(info
)));
125 const DWORD kExecutableMask
= PAGE_EXECUTE
| PAGE_EXECUTE_READ
|
126 PAGE_EXECUTE_READWRITE
| PAGE_EXECUTE_WRITECOPY
;
127 EXPECT_NE(0u, info
.Protect
& kExecutableMask
);
129 EXPECT_EQ(argument
, stub_
->argument());
130 EXPECT_TRUE(stub_
->bypass_address() != NULL
);
131 EXPECT_EQ(dest_fn
, stub_
->destination_function());
134 TEST_F(FunctionStubTest
, ZeroArgumentStub
) {
135 stub_
= FunctionStub::Create(reinterpret_cast<uintptr_t>(this),
136 &FunctionStubTest::FooCallback0
);
138 FuncPtr0 func
= reinterpret_cast<FuncPtr0
>(stub_
->code());
139 EXPECT_CALL(*this, Foo0())
140 .WillOnce(testing::Return(kDivertedRetVal
));
142 EXPECT_EQ(kDivertedRetVal
, func());
145 TEST_F(FunctionStubTest
, OneArgumentStub
) {
146 stub_
= FunctionStub::Create(reinterpret_cast<uintptr_t>(this),
147 &FunctionStubTest::FooCallback1
);
149 FuncPtr1 func
= reinterpret_cast<FuncPtr1
>(stub_
->code());
150 EXPECT_CALL(*this, Foo1(kFooArg
))
151 .WillOnce(testing::Return(kDivertedRetVal
));
153 EXPECT_EQ(kDivertedRetVal
, func(kFooArg
));
156 TEST_F(FunctionStubTest
, Bypass
) {
157 stub_
= FunctionStub::Create(reinterpret_cast<uintptr_t>(this),
158 &FunctionStubTest::FooCallback0
);
160 FuncPtr0 func
= reinterpret_cast<FuncPtr0
>(stub_
->code());
161 EXPECT_CALL(*this, Foo0())
162 .WillOnce(testing::Return(kDivertedRetVal
));
164 // This will call through to foo.
165 EXPECT_EQ(kDivertedRetVal
, func());
167 // Now bypass to Foo().
168 stub_
->BypassStub(Foo
);
169 EXPECT_TRUE(stub_
->is_bypassed());
170 EXPECT_FALSE(stub_
->is_valid());
172 // We should not call through anymore.
173 EXPECT_CALL(*this, Foo0())
176 EXPECT_EQ(kFooRetVal
, func());
179 TEST_F(FunctionStubTest
, FromCode
) {
180 // We should get NULL and no crash from reserved memory.
181 EXPECT_EQ(NULL
, FunctionStub::FromCode(playpen_
+ playpen_size_
));
183 // Create a FunctionStub pointer whose signature_
184 // field hangs just off the playpen.
185 TestFunctionStub
* stub
=
186 reinterpret_cast<TestFunctionStub
*>(playpen_
+ playpen_size_
-
187 TestFunctionStub::kSignatureOffset
);
188 TestFunctionStub::Init(stub
);
189 EXPECT_EQ(NULL
, FunctionStub::FromCode(stub
));
191 // Create a stub in committed memory.
192 stub
= reinterpret_cast<TestFunctionStub
*>(playpen_
);
193 TestFunctionStub::Init(stub
);
194 // Signature is NULL, which won't do.
195 EXPECT_EQ(NULL
, FunctionStub::FromCode(stub
));
197 const DWORD kFlags
= GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
|
198 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
;
200 HMODULE my_module
= NULL
;
201 EXPECT_TRUE(::GetModuleHandleEx(kFlags
,
202 reinterpret_cast<const wchar_t*>(&kDivertedRetVal
),
205 // Set our module as signature.
206 stub
->set_signature(my_module
);
207 EXPECT_EQ(stub
, FunctionStub::FromCode(stub
));