- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / tcmalloc / vendor / src / windows / preamble_patcher_test.cc
1 /* Copyright (c) 2011, Google Inc.
2  * All rights reserved.
3  * 
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  * 
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
13  * distribution.
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.
17  * 
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.
29  *
30  * ---
31  * Author: Joi Sigurdsson
32  * Author: Scott Francis
33  *
34  * Unit tests for PreamblePatcher
35  */
36
37 #include "config_for_unittests.h"
38 #include "preamble_patcher.h"
39 #include "mini_disassembler.h"
40 #pragma warning(push)
41 #pragma warning(disable:4553)
42 #include "auto_testing_hook.h"
43 #pragma warning(pop)
44
45 #define WIN32_LEAN_AND_MEAN
46 #include <windows.h>
47 #include <tchar.h>
48
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
53 // function.
54 #pragma optimize("", off)
55
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))
66
67 namespace {
68
69 // Function for testing - this is what we patch
70 //
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) {
76 #ifdef _M_X64
77   __int64 i2 = i + 1;
78   return (int) i2;
79 #else
80    return i + 1;
81 #endif
82 }
83
84 extern "C" int TooShortFunction(int);
85
86 extern "C" int JumpShortCondFunction(int);
87
88 extern "C" int JumpNearCondFunction(int);
89
90 extern "C" int JumpAbsoluteFunction(int);
91
92 extern "C" int CallNearRelativeFunction(int);
93
94 typedef int (*IncrementingFunc)(int);
95 IncrementingFunc original_function = NULL;
96
97 int HookIncrementNumber(int i) {
98   SIDESTEP_ASSERT(original_function != NULL);
99   int incremented_once = original_function(i);
100   return incremented_once + 1;
101 }
102
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
106 // functions.
107 int __declspec(noinline) AutoHookIncrementNumber(int i) {
108   return i + 10;
109 }
110
111 };  // namespace
112
113 namespace sidestep {
114
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)
121       target = new_target;
122
123    while (1) {
124       sidestep::InstructionType instructionType = disassembler.Disassemble(
125          reinterpret_cast<unsigned char *>(target) + instruction_size,
126          instruction_size);
127       if (sidestep::IT_RETURN == instructionType) {
128          return true;
129       }
130    }
131 }
132
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,
146                                (IncrementingFunc)p,
147                                original_function));
148   ::VirtualFree(p, 0, MEM_RELEASE);
149   return true;
150 }
151
152 bool TestPatchWithPreambleShortCondJump() {
153   original_function = NULL;
154   SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
155                        sidestep::PreamblePatcher::Patch(JumpShortCondFunction,
156                                                         HookIncrementNumber,
157                                                         &original_function));
158   (*original_function)(1);
159   SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
160                        UNPATCH(JumpShortCondFunction,
161                                (void*)HookIncrementNumber,
162                                original_function));
163   return true;
164 }
165
166 bool TestPatchWithPreambleNearRelativeCondJump() {
167   original_function = NULL;
168   SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
169                        sidestep::PreamblePatcher::Patch(JumpNearCondFunction,
170                                                         HookIncrementNumber,
171                                                         &original_function));
172   (*original_function)(0);
173   (*original_function)(1);
174   SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
175                        UNPATCH(JumpNearCondFunction,
176                                HookIncrementNumber,
177                                original_function));
178   return true;
179 }
180
181 bool TestPatchWithPreambleAbsoluteJump() {
182   original_function = NULL;
183   SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
184                        sidestep::PreamblePatcher::Patch(JumpAbsoluteFunction,
185                                                         HookIncrementNumber,
186                                                         &original_function));
187   (*original_function)(0);
188   (*original_function)(1);
189   SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
190                        UNPATCH(JumpAbsoluteFunction,
191                                HookIncrementNumber,
192                                original_function));
193   return true;
194 }
195
196 bool TestPatchWithPreambleNearRelativeCall() {
197   original_function = NULL;
198   SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
199                        sidestep::PreamblePatcher::Patch(
200                                                     CallNearRelativeFunction,
201                                                     HookIncrementNumber,
202                                                     &original_function));
203   (*original_function)(0);
204   (*original_function)(1);
205   SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
206                        UNPATCH(CallNearRelativeFunction,
207                                HookIncrementNumber,
208                                original_function));
209   return true;
210 }
211
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,
217                                                         HookIncrementNumber,
218                                                         &original_function));
219   SIDESTEP_EXPECT_TRUE(original_function);
220   SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 4);
221   SIDESTEP_EXPECT_TRUE(original_function(3) == 4);
222
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),
228                            instruction_size));
229
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.
233 #if 0
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,
239                                                         HookIncrementNumber,
240                                                         &dummy));
241
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.
245   dummy = NULL;
246   SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_FUNCTION_TOO_SMALL ==
247                        sidestep::PreamblePatcher::Patch(TooShortFunction,
248                                                         HookIncrementNumber,
249                                                         &dummy));
250 #endif
251
252   SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
253                        UNPATCH(IncrementNumber,
254                                HookIncrementNumber,
255                                original_function));
256   return true;
257 }
258
259 bool PatchThenUnpatch() {
260   original_function = NULL;
261   SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
262                        sidestep::PreamblePatcher::Patch(IncrementNumber,
263                                                         HookIncrementNumber,
264                                                         &original_function));
265   SIDESTEP_EXPECT_TRUE(original_function);
266   SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 3);
267   SIDESTEP_EXPECT_TRUE(original_function(2) == 3);
268
269   SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
270                        UNPATCH(IncrementNumber,
271                                HookIncrementNumber,
272                                original_function));
273   original_function = NULL;
274   SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4);
275
276   return true;
277 }
278
279 bool AutoTestingHookTest() {
280   SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2);
281
282   // Inner scope, so we can test what happens when the AutoTestingHook
283   // goes out of scope
284   {
285     AutoTestingHook hook = MakeTestingHook(IncrementNumber,
286                                            AutoHookIncrementNumber);
287     (void) hook;
288     SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 12);
289   }
290   SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4);
291
292   return true;
293 }
294
295 bool AutoTestingHookInContainerTest() {
296   SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2);
297
298   // Inner scope, so we can test what happens when the AutoTestingHook
299   // goes out of scope
300   {
301     AutoTestingHookHolder hook(MakeTestingHookHolder(IncrementNumber,
302                                                      AutoHookIncrementNumber));
303     (void) hook;
304     SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 12);
305   }
306   SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4);
307
308   return true;
309 }
310
311 bool TestPreambleAllocation() {
312   __int64 diff = 0;
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);
324
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);
336
337   return true;
338 }
339
340 bool UnitTests() {
341   return TestPatchWithPreambleNearRelativeCall() &&
342       TestPatchWithPreambleAbsoluteJump() &&
343       TestPatchWithPreambleNearRelativeCondJump() && 
344       TestPatchWithPreambleShortCondJump() &&
345       TestDisassembler() && TestPatchWithLongJump() &&
346       TestPatchUsingDynamicStub() && PatchThenUnpatch() &&
347       AutoTestingHookTest() && AutoTestingHookInContainerTest() &&
348       TestPreambleAllocation();
349 }
350
351 };  // namespace sidestep
352
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
356   str[size-1] = '\0';
357   return _vsnprintf(str, size-1, format, ap);
358 }
359
360 int _tmain(int argc, _TCHAR* argv[])
361 {
362   bool ret = sidestep::UnitTests();
363   printf("%s\n", ret ? "PASS" : "FAIL");
364   return ret ? 0 : -1;
365 }
366
367 #pragma optimize("", on)