1 /* Copyright (c) 2011, Google Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * Author: Joi Sigurdsson
32 * Author: Scott Francis
34 * Unit tests for PreamblePatcher
37 #include "config_for_unittests.h"
38 #include "preamble_patcher.h"
39 #include "mini_disassembler.h"
41 #pragma warning(disable:4553)
42 #include "auto_testing_hook.h"
45 #define WIN32_LEAN_AND_MEAN
49 // Turning off all optimizations for this file, since the official build's
50 // "Whole program optimization" seems to cause the TestPatchUsingDynamicStub
51 // test to crash with an access violation. We debugged this and found
52 // that the optimized access a register that is changed by a call to the hook
54 #pragma optimize("", off)
56 // A convenience macro to avoid a lot of casting in the tests.
57 // I tried to make this a templated function, but windows complained:
58 // error C2782: 'sidestep::SideStepError `anonymous-namespace'::Unpatch(T,T,T *)' : template parameter 'T' is ambiguous
59 // could be 'int (int)'
60 // or 'int (__cdecl *)(int)'
61 // My life isn't long enough to try to figure out how to fix this.
62 #define UNPATCH(target_function, replacement_function, original_function_stub) \
63 sidestep::PreamblePatcher::Unpatch((void*)(target_function), \
64 (void*)(replacement_function), \
65 (void*)(original_function))
69 // Function for testing - this is what we patch
71 // NOTE: Because of the way the compiler optimizes this function in
72 // release builds, we need to use a different input value every time we
73 // call it within a function, otherwise the compiler will just reuse the
74 // last calculated incremented value.
75 int __declspec(noinline
) IncrementNumber(int i
) {
84 extern "C" int TooShortFunction(int);
86 extern "C" int JumpShortCondFunction(int);
88 extern "C" int JumpNearCondFunction(int);
90 extern "C" int JumpAbsoluteFunction(int);
92 extern "C" int CallNearRelativeFunction(int);
94 typedef int (*IncrementingFunc
)(int);
95 IncrementingFunc original_function
= NULL
;
97 int HookIncrementNumber(int i
) {
98 SIDESTEP_ASSERT(original_function
!= NULL
);
99 int incremented_once
= original_function(i
);
100 return incremented_once
+ 1;
103 // For the AutoTestingHook test, we can't use original_function, because
104 // all that is encapsulated.
105 // This function "increments" by 10, just to set it apart from the other
107 int __declspec(noinline
) AutoHookIncrementNumber(int i
) {
115 bool TestDisassembler() {
116 unsigned int instruction_size
= 0;
117 sidestep::MiniDisassembler disassembler
;
118 void * target
= reinterpret_cast<unsigned char *>(IncrementNumber
);
119 void * new_target
= PreamblePatcher::ResolveTarget(target
);
120 if (target
!= new_target
)
124 sidestep::InstructionType instructionType
= disassembler
.Disassemble(
125 reinterpret_cast<unsigned char *>(target
) + instruction_size
,
127 if (sidestep::IT_RETURN
== instructionType
) {
133 bool TestPatchWithLongJump() {
134 original_function
= NULL
;
135 void *p
= ::VirtualAlloc(reinterpret_cast<void *>(0x0000020000000000), 4096,
136 MEM_RESERVE
| MEM_COMMIT
, PAGE_EXECUTE_READWRITE
);
137 SIDESTEP_EXPECT_TRUE(p
!= NULL
);
138 memset(p
, 0xcc, 4096);
139 SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS
==
140 sidestep::PreamblePatcher::Patch(IncrementNumber
,
141 (IncrementingFunc
) p
,
142 &original_function
));
143 SIDESTEP_ASSERT((*original_function
)(1) == 2);
144 SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS
==
145 UNPATCH(IncrementNumber
,
148 ::VirtualFree(p
, 0, MEM_RELEASE
);
152 bool TestPatchWithPreambleShortCondJump() {
153 original_function
= NULL
;
154 SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS
==
155 sidestep::PreamblePatcher::Patch(JumpShortCondFunction
,
157 &original_function
));
158 (*original_function
)(1);
159 SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS
==
160 UNPATCH(JumpShortCondFunction
,
161 (void*)HookIncrementNumber
,
166 bool TestPatchWithPreambleNearRelativeCondJump() {
167 original_function
= NULL
;
168 SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS
==
169 sidestep::PreamblePatcher::Patch(JumpNearCondFunction
,
171 &original_function
));
172 (*original_function
)(0);
173 (*original_function
)(1);
174 SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS
==
175 UNPATCH(JumpNearCondFunction
,
181 bool TestPatchWithPreambleAbsoluteJump() {
182 original_function
= NULL
;
183 SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS
==
184 sidestep::PreamblePatcher::Patch(JumpAbsoluteFunction
,
186 &original_function
));
187 (*original_function
)(0);
188 (*original_function
)(1);
189 SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS
==
190 UNPATCH(JumpAbsoluteFunction
,
196 bool TestPatchWithPreambleNearRelativeCall() {
197 original_function
= NULL
;
198 SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS
==
199 sidestep::PreamblePatcher::Patch(
200 CallNearRelativeFunction
,
202 &original_function
));
203 (*original_function
)(0);
204 (*original_function
)(1);
205 SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS
==
206 UNPATCH(CallNearRelativeFunction
,
212 bool TestPatchUsingDynamicStub() {
213 original_function
= NULL
;
214 SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2);
215 SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS
==
216 sidestep::PreamblePatcher::Patch(IncrementNumber
,
218 &original_function
));
219 SIDESTEP_EXPECT_TRUE(original_function
);
220 SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 4);
221 SIDESTEP_EXPECT_TRUE(original_function(3) == 4);
223 // Clearbox test to see that the function has been patched.
224 sidestep::MiniDisassembler disassembler
;
225 unsigned int instruction_size
= 0;
226 SIDESTEP_EXPECT_TRUE(sidestep::IT_JUMP
== disassembler
.Disassemble(
227 reinterpret_cast<unsigned char*>(IncrementNumber
),
230 // Since we patched IncrementNumber, its first statement is a
231 // jmp to the hook function. So verify that we now can not patch
232 // IncrementNumber because it starts with a jump.
234 IncrementingFunc dummy
= NULL
;
235 // TODO(joi@chromium.org): restore this test once flag is added to
236 // disable JMP following
237 SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_JUMP_INSTRUCTION
==
238 sidestep::PreamblePatcher::Patch(IncrementNumber
,
242 // This test disabled because code in preamble_patcher_with_stub.cc
243 // asserts before returning the error code -- so there is no way
244 // to get an error code here, in debug build.
246 SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_FUNCTION_TOO_SMALL
==
247 sidestep::PreamblePatcher::Patch(TooShortFunction
,
252 SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS
==
253 UNPATCH(IncrementNumber
,
259 bool PatchThenUnpatch() {
260 original_function
= NULL
;
261 SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS
==
262 sidestep::PreamblePatcher::Patch(IncrementNumber
,
264 &original_function
));
265 SIDESTEP_EXPECT_TRUE(original_function
);
266 SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 3);
267 SIDESTEP_EXPECT_TRUE(original_function(2) == 3);
269 SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS
==
270 UNPATCH(IncrementNumber
,
273 original_function
= NULL
;
274 SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4);
279 bool AutoTestingHookTest() {
280 SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2);
282 // Inner scope, so we can test what happens when the AutoTestingHook
285 AutoTestingHook hook
= MakeTestingHook(IncrementNumber
,
286 AutoHookIncrementNumber
);
288 SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 12);
290 SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4);
295 bool AutoTestingHookInContainerTest() {
296 SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2);
298 // Inner scope, so we can test what happens when the AutoTestingHook
301 AutoTestingHookHolder
hook(MakeTestingHookHolder(IncrementNumber
,
302 AutoHookIncrementNumber
));
304 SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 12);
306 SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4);
311 bool TestPreambleAllocation() {
313 void* p1
= reinterpret_cast<void*>(0x110000000);
314 void* p2
= reinterpret_cast<void*>(0x810000000);
315 unsigned char* b1
= PreamblePatcher::AllocPreambleBlockNear(p1
);
316 SIDESTEP_EXPECT_TRUE(b1
!= NULL
);
317 diff
= reinterpret_cast<__int64
>(p1
) - reinterpret_cast<__int64
>(b1
);
318 // Ensure blocks are within 2GB
319 SIDESTEP_EXPECT_TRUE(diff
<= INT_MAX
&& diff
>= INT_MIN
);
320 unsigned char* b2
= PreamblePatcher::AllocPreambleBlockNear(p2
);
321 SIDESTEP_EXPECT_TRUE(b2
!= NULL
);
322 diff
= reinterpret_cast<__int64
>(p2
) - reinterpret_cast<__int64
>(b2
);
323 SIDESTEP_EXPECT_TRUE(diff
<= INT_MAX
&& diff
>= INT_MIN
);
325 // Ensure we're reusing free blocks
326 unsigned char* b3
= b1
;
327 unsigned char* b4
= b2
;
328 PreamblePatcher::FreePreambleBlock(b1
);
329 PreamblePatcher::FreePreambleBlock(b2
);
330 b1
= PreamblePatcher::AllocPreambleBlockNear(p1
);
331 SIDESTEP_EXPECT_TRUE(b1
== b3
);
332 b2
= PreamblePatcher::AllocPreambleBlockNear(p2
);
333 SIDESTEP_EXPECT_TRUE(b2
== b4
);
334 PreamblePatcher::FreePreambleBlock(b1
);
335 PreamblePatcher::FreePreambleBlock(b2
);
341 return TestPatchWithPreambleNearRelativeCall() &&
342 TestPatchWithPreambleAbsoluteJump() &&
343 TestPatchWithPreambleNearRelativeCondJump() &&
344 TestPatchWithPreambleShortCondJump() &&
345 TestDisassembler() && TestPatchWithLongJump() &&
346 TestPatchUsingDynamicStub() && PatchThenUnpatch() &&
347 AutoTestingHookTest() && AutoTestingHookInContainerTest() &&
348 TestPreambleAllocation();
351 }; // namespace sidestep
353 int safe_vsnprintf(char *str
, size_t size
, const char *format
, va_list ap
) {
354 if (size
== 0) // not even room for a \0?
355 return -1; // not what C99 says to do, but what windows does
357 return _vsnprintf(str
, size
-1, format
, ap
);
360 int _tmain(int argc
, _TCHAR
* argv
[])
362 bool ret
= sidestep::UnitTests();
363 printf("%s\n", ret
? "PASS" : "FAIL");
367 #pragma optimize("", on)