Index: third_party/tcmalloc/chromium/src/windows/preamble_patcher_test.cc |
=================================================================== |
--- third_party/tcmalloc/chromium/src/windows/preamble_patcher_test.cc (revision 124832) |
+++ third_party/tcmalloc/chromium/src/windows/preamble_patcher_test.cc (working copy) |
@@ -1,367 +0,0 @@ |
-/* Copyright (c) 2011, Google Inc. |
- * All rights reserved. |
- * |
- * Redistribution and use in source and binary forms, with or without |
- * modification, are permitted provided that the following conditions are |
- * met: |
- * |
- * * Redistributions of source code must retain the above copyright |
- * notice, this list of conditions and the following disclaimer. |
- * * Redistributions in binary form must reproduce the above |
- * copyright notice, this list of conditions and the following disclaimer |
- * in the documentation and/or other materials provided with the |
- * distribution. |
- * * Neither the name of Google Inc. nor the names of its |
- * contributors may be used to endorse or promote products derived from |
- * this software without specific prior written permission. |
- * |
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
- * |
- * --- |
- * Author: Joi Sigurdsson |
- * Author: Scott Francis |
- * |
- * Unit tests for PreamblePatcher |
- */ |
- |
-#include "config_for_unittests.h" |
-#include "preamble_patcher.h" |
-#include "mini_disassembler.h" |
-#pragma warning(push) |
-#pragma warning(disable:4553) |
-#include "auto_testing_hook.h" |
-#pragma warning(pop) |
- |
-#define WIN32_LEAN_AND_MEAN |
-#include <windows.h> |
-#include <tchar.h> |
- |
-// Turning off all optimizations for this file, since the official build's |
-// "Whole program optimization" seems to cause the TestPatchUsingDynamicStub |
-// test to crash with an access violation. We debugged this and found |
-// that the optimized access a register that is changed by a call to the hook |
-// function. |
-#pragma optimize("", off) |
- |
-// A convenience macro to avoid a lot of casting in the tests. |
-// I tried to make this a templated function, but windows complained: |
-// error C2782: 'sidestep::SideStepError `anonymous-namespace'::Unpatch(T,T,T *)' : template parameter 'T' is ambiguous |
-// could be 'int (int)' |
-// or 'int (__cdecl *)(int)' |
-// My life isn't long enough to try to figure out how to fix this. |
-#define UNPATCH(target_function, replacement_function, original_function_stub) \ |
- sidestep::PreamblePatcher::Unpatch((void*)(target_function), \ |
- (void*)(replacement_function), \ |
- (void*)(original_function)) |
- |
-namespace { |
- |
-// Function for testing - this is what we patch |
-// |
-// NOTE: Because of the way the compiler optimizes this function in |
-// release builds, we need to use a different input value every time we |
-// call it within a function, otherwise the compiler will just reuse the |
-// last calculated incremented value. |
-int __declspec(noinline) IncrementNumber(int i) { |
-#ifdef _M_X64 |
- __int64 i2 = i + 1; |
- return (int) i2; |
-#else |
- return i + 1; |
-#endif |
-} |
- |
-extern "C" int TooShortFunction(int); |
- |
-extern "C" int JumpShortCondFunction(int); |
- |
-extern "C" int JumpNearCondFunction(int); |
- |
-extern "C" int JumpAbsoluteFunction(int); |
- |
-extern "C" int CallNearRelativeFunction(int); |
- |
-typedef int (*IncrementingFunc)(int); |
-IncrementingFunc original_function = NULL; |
- |
-int HookIncrementNumber(int i) { |
- SIDESTEP_ASSERT(original_function != NULL); |
- int incremented_once = original_function(i); |
- return incremented_once + 1; |
-} |
- |
-// For the AutoTestingHook test, we can't use original_function, because |
-// all that is encapsulated. |
-// This function "increments" by 10, just to set it apart from the other |
-// functions. |
-int __declspec(noinline) AutoHookIncrementNumber(int i) { |
- return i + 10; |
-} |
- |
-}; // namespace |
- |
-namespace sidestep { |
- |
-bool TestDisassembler() { |
- unsigned int instruction_size = 0; |
- sidestep::MiniDisassembler disassembler; |
- void * target = reinterpret_cast<unsigned char *>(IncrementNumber); |
- void * new_target = PreamblePatcher::ResolveTarget(target); |
- if (target != new_target) |
- target = new_target; |
- |
- while (1) { |
- sidestep::InstructionType instructionType = disassembler.Disassemble( |
- reinterpret_cast<unsigned char *>(target) + instruction_size, |
- instruction_size); |
- if (sidestep::IT_RETURN == instructionType) { |
- return true; |
- } |
- } |
-} |
- |
-bool TestPatchWithLongJump() { |
- original_function = NULL; |
- void *p = ::VirtualAlloc(reinterpret_cast<void *>(0x0000020000000000), 4096, |
- MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); |
- SIDESTEP_EXPECT_TRUE(p != NULL); |
- memset(p, 0xcc, 4096); |
- SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS == |
- sidestep::PreamblePatcher::Patch(IncrementNumber, |
- (IncrementingFunc) p, |
- &original_function)); |
- SIDESTEP_ASSERT((*original_function)(1) == 2); |
- SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS == |
- UNPATCH(IncrementNumber, |
- (IncrementingFunc)p, |
- original_function)); |
- ::VirtualFree(p, 0, MEM_RELEASE); |
- return true; |
-} |
- |
-bool TestPatchWithPreambleShortCondJump() { |
- original_function = NULL; |
- SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS == |
- sidestep::PreamblePatcher::Patch(JumpShortCondFunction, |
- HookIncrementNumber, |
- &original_function)); |
- (*original_function)(1); |
- SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS == |
- UNPATCH(JumpShortCondFunction, |
- (void*)HookIncrementNumber, |
- original_function)); |
- return true; |
-} |
- |
-bool TestPatchWithPreambleNearRelativeCondJump() { |
- original_function = NULL; |
- SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS == |
- sidestep::PreamblePatcher::Patch(JumpNearCondFunction, |
- HookIncrementNumber, |
- &original_function)); |
- (*original_function)(0); |
- (*original_function)(1); |
- SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS == |
- UNPATCH(JumpNearCondFunction, |
- HookIncrementNumber, |
- original_function)); |
- return true; |
-} |
- |
-bool TestPatchWithPreambleAbsoluteJump() { |
- original_function = NULL; |
- SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS == |
- sidestep::PreamblePatcher::Patch(JumpAbsoluteFunction, |
- HookIncrementNumber, |
- &original_function)); |
- (*original_function)(0); |
- (*original_function)(1); |
- SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS == |
- UNPATCH(JumpAbsoluteFunction, |
- HookIncrementNumber, |
- original_function)); |
- return true; |
-} |
- |
-bool TestPatchWithPreambleNearRelativeCall() { |
- original_function = NULL; |
- SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS == |
- sidestep::PreamblePatcher::Patch( |
- CallNearRelativeFunction, |
- HookIncrementNumber, |
- &original_function)); |
- (*original_function)(0); |
- (*original_function)(1); |
- SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS == |
- UNPATCH(CallNearRelativeFunction, |
- HookIncrementNumber, |
- original_function)); |
- return true; |
-} |
- |
-bool TestPatchUsingDynamicStub() { |
- original_function = NULL; |
- SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2); |
- SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS == |
- sidestep::PreamblePatcher::Patch(IncrementNumber, |
- HookIncrementNumber, |
- &original_function)); |
- SIDESTEP_EXPECT_TRUE(original_function); |
- SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 4); |
- SIDESTEP_EXPECT_TRUE(original_function(3) == 4); |
- |
- // Clearbox test to see that the function has been patched. |
- sidestep::MiniDisassembler disassembler; |
- unsigned int instruction_size = 0; |
- SIDESTEP_EXPECT_TRUE(sidestep::IT_JUMP == disassembler.Disassemble( |
- reinterpret_cast<unsigned char*>(IncrementNumber), |
- instruction_size)); |
- |
- // Since we patched IncrementNumber, its first statement is a |
- // jmp to the hook function. So verify that we now can not patch |
- // IncrementNumber because it starts with a jump. |
-#if 0 |
- IncrementingFunc dummy = NULL; |
- // TODO(joi@chromium.org): restore this test once flag is added to |
- // disable JMP following |
- SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_JUMP_INSTRUCTION == |
- sidestep::PreamblePatcher::Patch(IncrementNumber, |
- HookIncrementNumber, |
- &dummy)); |
- |
- // This test disabled because code in preamble_patcher_with_stub.cc |
- // asserts before returning the error code -- so there is no way |
- // to get an error code here, in debug build. |
- dummy = NULL; |
- SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_FUNCTION_TOO_SMALL == |
- sidestep::PreamblePatcher::Patch(TooShortFunction, |
- HookIncrementNumber, |
- &dummy)); |
-#endif |
- |
- SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS == |
- UNPATCH(IncrementNumber, |
- HookIncrementNumber, |
- original_function)); |
- return true; |
-} |
- |
-bool PatchThenUnpatch() { |
- original_function = NULL; |
- SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS == |
- sidestep::PreamblePatcher::Patch(IncrementNumber, |
- HookIncrementNumber, |
- &original_function)); |
- SIDESTEP_EXPECT_TRUE(original_function); |
- SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 3); |
- SIDESTEP_EXPECT_TRUE(original_function(2) == 3); |
- |
- SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS == |
- UNPATCH(IncrementNumber, |
- HookIncrementNumber, |
- original_function)); |
- original_function = NULL; |
- SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4); |
- |
- return true; |
-} |
- |
-bool AutoTestingHookTest() { |
- SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2); |
- |
- // Inner scope, so we can test what happens when the AutoTestingHook |
- // goes out of scope |
- { |
- AutoTestingHook hook = MakeTestingHook(IncrementNumber, |
- AutoHookIncrementNumber); |
- (void) hook; |
- SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 12); |
- } |
- SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4); |
- |
- return true; |
-} |
- |
-bool AutoTestingHookInContainerTest() { |
- SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2); |
- |
- // Inner scope, so we can test what happens when the AutoTestingHook |
- // goes out of scope |
- { |
- AutoTestingHookHolder hook(MakeTestingHookHolder(IncrementNumber, |
- AutoHookIncrementNumber)); |
- (void) hook; |
- SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 12); |
- } |
- SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4); |
- |
- return true; |
-} |
- |
-bool TestPreambleAllocation() { |
- __int64 diff = 0; |
- void* p1 = reinterpret_cast<void*>(0x110000000); |
- void* p2 = reinterpret_cast<void*>(0x810000000); |
- unsigned char* b1 = PreamblePatcher::AllocPreambleBlockNear(p1); |
- SIDESTEP_EXPECT_TRUE(b1 != NULL); |
- diff = reinterpret_cast<__int64>(p1) - reinterpret_cast<__int64>(b1); |
- // Ensure blocks are within 2GB |
- SIDESTEP_EXPECT_TRUE(diff <= INT_MAX && diff >= INT_MIN); |
- unsigned char* b2 = PreamblePatcher::AllocPreambleBlockNear(p2); |
- SIDESTEP_EXPECT_TRUE(b2 != NULL); |
- diff = reinterpret_cast<__int64>(p2) - reinterpret_cast<__int64>(b2); |
- SIDESTEP_EXPECT_TRUE(diff <= INT_MAX && diff >= INT_MIN); |
- |
- // Ensure we're reusing free blocks |
- unsigned char* b3 = b1; |
- unsigned char* b4 = b2; |
- PreamblePatcher::FreePreambleBlock(b1); |
- PreamblePatcher::FreePreambleBlock(b2); |
- b1 = PreamblePatcher::AllocPreambleBlockNear(p1); |
- SIDESTEP_EXPECT_TRUE(b1 == b3); |
- b2 = PreamblePatcher::AllocPreambleBlockNear(p2); |
- SIDESTEP_EXPECT_TRUE(b2 == b4); |
- PreamblePatcher::FreePreambleBlock(b1); |
- PreamblePatcher::FreePreambleBlock(b2); |
- |
- return true; |
-} |
- |
-bool UnitTests() { |
- return TestPatchWithPreambleNearRelativeCall() && |
- TestPatchWithPreambleAbsoluteJump() && |
- TestPatchWithPreambleNearRelativeCondJump() && |
- TestPatchWithPreambleShortCondJump() && |
- TestDisassembler() && TestPatchWithLongJump() && |
- TestPatchUsingDynamicStub() && PatchThenUnpatch() && |
- AutoTestingHookTest() && AutoTestingHookInContainerTest() && |
- TestPreambleAllocation(); |
-} |
- |
-}; // namespace sidestep |
- |
-int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) { |
- if (size == 0) // not even room for a \0? |
- return -1; // not what C99 says to do, but what windows does |
- str[size-1] = '\0'; |
- return _vsnprintf(str, size-1, format, ap); |
-} |
- |
-int _tmain(int argc, _TCHAR* argv[]) |
-{ |
- bool ret = sidestep::UnitTests(); |
- printf("%s\n", ret ? "PASS" : "FAIL"); |
- return ret ? 0 : -1; |
-} |
- |
-#pragma optimize("", on) |