diff options
Diffstat (limited to 'lib/interception/tests/interception_win_test.cc')
-rw-r--r-- | lib/interception/tests/interception_win_test.cc | 592 |
1 files changed, 592 insertions, 0 deletions
diff --git a/lib/interception/tests/interception_win_test.cc b/lib/interception/tests/interception_win_test.cc new file mode 100644 index 000000000000..611354f03d12 --- /dev/null +++ b/lib/interception/tests/interception_win_test.cc @@ -0,0 +1,592 @@ +//===-- interception_win_test.cc ------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer/AddressSanitizer runtime. +// Tests for interception_win.h. +// +//===----------------------------------------------------------------------===// +#include "interception/interception.h" + +#include "gtest/gtest.h" + +// Too slow for debug build +#if !SANITIZER_DEBUG +#if SANITIZER_WINDOWS + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +namespace __interception { +namespace { + +enum FunctionPrefixKind { + FunctionPrefixNone, + FunctionPrefixPadding, + FunctionPrefixHotPatch, + FunctionPrefixDetour, +}; + +typedef bool (*TestOverrideFunction)(uptr, uptr, uptr*); +typedef int (*IdentityFunction)(int); + +#if SANITIZER_WINDOWS64 + +const u8 kIdentityCodeWithPrologue[] = { + 0x55, // push rbp + 0x48, 0x89, 0xE5, // mov rbp,rsp + 0x8B, 0xC1, // mov eax,ecx + 0x5D, // pop rbp + 0xC3, // ret +}; + +const u8 kIdentityCodeWithPushPop[] = { + 0x55, // push rbp + 0x48, 0x89, 0xE5, // mov rbp,rsp + 0x53, // push rbx + 0x50, // push rax + 0x58, // pop rax + 0x8B, 0xC1, // mov rax,rcx + 0x5B, // pop rbx + 0x5D, // pop rbp + 0xC3, // ret +}; + +const u8 kIdentityTwiceOffset = 16; +const u8 kIdentityTwice[] = { + 0x55, // push rbp + 0x48, 0x89, 0xE5, // mov rbp,rsp + 0x8B, 0xC1, // mov eax,ecx + 0x5D, // pop rbp + 0xC3, // ret + 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, + 0x55, // push rbp + 0x48, 0x89, 0xE5, // mov rbp,rsp + 0x8B, 0xC1, // mov eax,ecx + 0x5D, // pop rbp + 0xC3, // ret +}; + +const u8 kIdentityCodeWithMov[] = { + 0x89, 0xC8, // mov eax, ecx + 0xC3, // ret +}; + +const u8 kIdentityCodeWithJump[] = { + 0xE9, 0x04, 0x00, 0x00, + 0x00, // jmp + 4 + 0xCC, 0xCC, 0xCC, 0xCC, + 0x89, 0xC8, // mov eax, ecx + 0xC3, // ret +}; + +#else + +const u8 kIdentityCodeWithPrologue[] = { + 0x55, // push ebp + 0x8B, 0xEC, // mov ebp,esp + 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8] + 0x5D, // pop ebp + 0xC3, // ret +}; + +const u8 kIdentityCodeWithPushPop[] = { + 0x55, // push ebp + 0x8B, 0xEC, // mov ebp,esp + 0x53, // push ebx + 0x50, // push eax + 0x58, // pop eax + 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8] + 0x5B, // pop ebx + 0x5D, // pop ebp + 0xC3, // ret +}; + +const u8 kIdentityTwiceOffset = 8; +const u8 kIdentityTwice[] = { + 0x55, // push ebp + 0x8B, 0xEC, // mov ebp,esp + 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8] + 0x5D, // pop ebp + 0xC3, // ret + 0x55, // push ebp + 0x8B, 0xEC, // mov ebp,esp + 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8] + 0x5D, // pop ebp + 0xC3, // ret +}; + +const u8 kIdentityCodeWithMov[] = { + 0x8B, 0x44, 0x24, 0x04, // mov eax,dword ptr [esp + 4] + 0xC3, // ret +}; + +const u8 kIdentityCodeWithJump[] = { + 0xE9, 0x04, 0x00, 0x00, + 0x00, // jmp + 4 + 0xCC, 0xCC, 0xCC, 0xCC, + 0x8B, 0x44, 0x24, 0x04, // mov eax,dword ptr [esp + 4] + 0xC3, // ret +}; + +#endif + +const u8 kPatchableCode1[] = { + 0xB8, 0x4B, 0x00, 0x00, 0x00, // mov eax,4B + 0x33, 0xC9, // xor ecx,ecx + 0xC3, // ret +}; + +const u8 kPatchableCode2[] = { + 0x55, // push ebp + 0x8B, 0xEC, // mov ebp,esp + 0x33, 0xC0, // xor eax,eax + 0x5D, // pop ebp + 0xC3, // ret +}; + +const u8 kPatchableCode3[] = { + 0x55, // push ebp + 0x8B, 0xEC, // mov ebp,esp + 0x6A, 0x00, // push 0 + 0xE8, 0x3D, 0xFF, 0xFF, 0xFF, // call <func> +}; + +const u8 kPatchableCode4[] = { + 0xE9, 0xCC, 0xCC, 0xCC, 0xCC, // jmp <label> + 0x90, 0x90, 0x90, 0x90, +}; + +const u8 kUnpatchableCode1[] = { + 0xC3, // ret +}; + +const u8 kUnpatchableCode2[] = { + 0x33, 0xC9, // xor ecx,ecx + 0xC3, // ret +}; + +const u8 kUnpatchableCode3[] = { + 0x75, 0xCC, // jne <label> + 0x33, 0xC9, // xor ecx,ecx + 0xC3, // ret +}; + +const u8 kUnpatchableCode4[] = { + 0x74, 0xCC, // jne <label> + 0x33, 0xC9, // xor ecx,ecx + 0xC3, // ret +}; + +const u8 kUnpatchableCode5[] = { + 0xEB, 0x02, // jmp <label> + 0x33, 0xC9, // xor ecx,ecx + 0xC3, // ret +}; + +const u8 kUnpatchableCode6[] = { + 0xE8, 0xCC, 0xCC, 0xCC, 0xCC, // call <func> + 0x90, 0x90, 0x90, 0x90, +}; + +// A buffer holding the dynamically generated code under test. +u8* ActiveCode; +size_t ActiveCodeLength = 4096; + +template<class T> +static void LoadActiveCode( + const T &code, + uptr *entry_point, + FunctionPrefixKind prefix_kind = FunctionPrefixNone) { + if (ActiveCode == nullptr) { + ActiveCode = + (u8*)::VirtualAlloc(nullptr, ActiveCodeLength, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + ASSERT_NE(ActiveCode, nullptr); + } + + size_t position = 0; + + // Add padding to avoid memory violation when scanning the prefix. + for (int i = 0; i < 16; ++i) + ActiveCode[position++] = 0xC3; // Instruction 'ret'. + + // Add function padding. + size_t padding = 0; + if (prefix_kind == FunctionPrefixPadding) + padding = 16; + else if (prefix_kind == FunctionPrefixDetour || + prefix_kind == FunctionPrefixHotPatch) + padding = FIRST_32_SECOND_64(5, 6); + // Insert |padding| instructions 'nop'. + for (size_t i = 0; i < padding; ++i) + ActiveCode[position++] = 0x90; + + // Keep track of the entry point. + *entry_point = (uptr)&ActiveCode[position]; + + // Add the detour instruction (i.e. mov edi, edi) + if (prefix_kind == FunctionPrefixDetour) { +#if SANITIZER_WINDOWS64 + // Note that "mov edi,edi" is NOP in 32-bit only, in 64-bit it clears + // higher bits of RDI. + // Use 66,90H as NOP for Windows64. + ActiveCode[position++] = 0x66; + ActiveCode[position++] = 0x90; +#else + // mov edi,edi. + ActiveCode[position++] = 0x8B; + ActiveCode[position++] = 0xFF; +#endif + + } + + // Copy the function body. + for (size_t i = 0; i < sizeof(T); ++i) + ActiveCode[position++] = code[i]; +} + +int InterceptorFunctionCalled; +IdentityFunction InterceptedRealFunction; + +int InterceptorFunction(int x) { + ++InterceptorFunctionCalled; + return InterceptedRealFunction(x); +} + +} // namespace + +// Tests for interception_win.h +TEST(Interception, InternalGetProcAddress) { + HMODULE ntdll_handle = ::GetModuleHandle("ntdll"); + ASSERT_NE(nullptr, ntdll_handle); + uptr DbgPrint_expected = (uptr)::GetProcAddress(ntdll_handle, "DbgPrint"); + uptr isdigit_expected = (uptr)::GetProcAddress(ntdll_handle, "isdigit"); + uptr DbgPrint_adddress = InternalGetProcAddress(ntdll_handle, "DbgPrint"); + uptr isdigit_address = InternalGetProcAddress(ntdll_handle, "isdigit"); + + EXPECT_EQ(DbgPrint_expected, DbgPrint_adddress); + EXPECT_EQ(isdigit_expected, isdigit_address); + EXPECT_NE(DbgPrint_adddress, isdigit_address); +} + +template<class T> +static void TestIdentityFunctionPatching( + const T &code, + TestOverrideFunction override, + FunctionPrefixKind prefix_kind = FunctionPrefixNone) { + uptr identity_address; + LoadActiveCode(code, &identity_address, prefix_kind); + IdentityFunction identity = (IdentityFunction)identity_address; + + // Validate behavior before dynamic patching. + InterceptorFunctionCalled = 0; + EXPECT_EQ(0, identity(0)); + EXPECT_EQ(42, identity(42)); + EXPECT_EQ(0, InterceptorFunctionCalled); + + // Patch the function. + uptr real_identity_address = 0; + bool success = override(identity_address, + (uptr)&InterceptorFunction, + &real_identity_address); + EXPECT_TRUE(success); + EXPECT_NE(0U, real_identity_address); + IdentityFunction real_identity = (IdentityFunction)real_identity_address; + InterceptedRealFunction = real_identity; + + // Don't run tests if hooking failed or the real function is not valid. + if (!success || !real_identity_address) + return; + + // Calling the redirected function. + InterceptorFunctionCalled = 0; + EXPECT_EQ(0, identity(0)); + EXPECT_EQ(42, identity(42)); + EXPECT_EQ(2, InterceptorFunctionCalled); + + // Calling the real function. + InterceptorFunctionCalled = 0; + EXPECT_EQ(0, real_identity(0)); + EXPECT_EQ(42, real_identity(42)); + EXPECT_EQ(0, InterceptorFunctionCalled); + + TestOnlyReleaseTrampolineRegions(); +} + +#if !SANITIZER_WINDOWS64 +TEST(Interception, OverrideFunctionWithDetour) { + TestOverrideFunction override = OverrideFunctionWithDetour; + FunctionPrefixKind prefix = FunctionPrefixDetour; + TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); + TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); + TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix); + TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix); +} +#endif // !SANITIZER_WINDOWS64 + +TEST(Interception, OverrideFunctionWithRedirectJump) { + TestOverrideFunction override = OverrideFunctionWithRedirectJump; + TestIdentityFunctionPatching(kIdentityCodeWithJump, override); +} + +TEST(Interception, OverrideFunctionWithHotPatch) { + TestOverrideFunction override = OverrideFunctionWithHotPatch; + FunctionPrefixKind prefix = FunctionPrefixHotPatch; + TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix); +} + +TEST(Interception, OverrideFunctionWithTrampoline) { + TestOverrideFunction override = OverrideFunctionWithTrampoline; + FunctionPrefixKind prefix = FunctionPrefixNone; + TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); + TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); + + prefix = FunctionPrefixPadding; + TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); + TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); +} + +TEST(Interception, OverrideFunction) { + TestOverrideFunction override = OverrideFunction; + FunctionPrefixKind prefix = FunctionPrefixNone; + TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); + TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); + TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix); + + prefix = FunctionPrefixPadding; + TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); + TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); + TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix); + TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix); + + prefix = FunctionPrefixHotPatch; + TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); + TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); + TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix); + TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix); + + prefix = FunctionPrefixDetour; + TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); + TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); + TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix); + TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix); +} + +template<class T> +static void TestIdentityFunctionMultiplePatching( + const T &code, + TestOverrideFunction override, + FunctionPrefixKind prefix_kind = FunctionPrefixNone) { + uptr identity_address; + LoadActiveCode(code, &identity_address, prefix_kind); + + // Patch the function. + uptr real_identity_address = 0; + bool success = override(identity_address, + (uptr)&InterceptorFunction, + &real_identity_address); + EXPECT_TRUE(success); + EXPECT_NE(0U, real_identity_address); + + // Re-patching the function should not work. + success = override(identity_address, + (uptr)&InterceptorFunction, + &real_identity_address); + EXPECT_FALSE(success); + + TestOnlyReleaseTrampolineRegions(); +} + +TEST(Interception, OverrideFunctionMultiplePatchingIsFailing) { +#if !SANITIZER_WINDOWS64 + TestIdentityFunctionMultiplePatching(kIdentityCodeWithPrologue, + OverrideFunctionWithDetour, + FunctionPrefixDetour); +#endif + + TestIdentityFunctionMultiplePatching(kIdentityCodeWithMov, + OverrideFunctionWithHotPatch, + FunctionPrefixHotPatch); + + TestIdentityFunctionMultiplePatching(kIdentityCodeWithPushPop, + OverrideFunctionWithTrampoline, + FunctionPrefixPadding); +} + +TEST(Interception, OverrideFunctionTwice) { + uptr identity_address1; + LoadActiveCode(kIdentityTwice, &identity_address1); + uptr identity_address2 = identity_address1 + kIdentityTwiceOffset; + IdentityFunction identity1 = (IdentityFunction)identity_address1; + IdentityFunction identity2 = (IdentityFunction)identity_address2; + + // Patch the two functions. + uptr real_identity_address = 0; + EXPECT_TRUE(OverrideFunction(identity_address1, + (uptr)&InterceptorFunction, + &real_identity_address)); + EXPECT_TRUE(OverrideFunction(identity_address2, + (uptr)&InterceptorFunction, + &real_identity_address)); + IdentityFunction real_identity = (IdentityFunction)real_identity_address; + InterceptedRealFunction = real_identity; + + // Calling the redirected function. + InterceptorFunctionCalled = 0; + EXPECT_EQ(42, identity1(42)); + EXPECT_EQ(42, identity2(42)); + EXPECT_EQ(2, InterceptorFunctionCalled); + + TestOnlyReleaseTrampolineRegions(); +} + +template<class T> +static bool TestFunctionPatching( + const T &code, + TestOverrideFunction override, + FunctionPrefixKind prefix_kind = FunctionPrefixNone) { + uptr address; + LoadActiveCode(code, &address, prefix_kind); + uptr unused_real_address = 0; + bool result = override( + address, (uptr)&InterceptorFunction, &unused_real_address); + + TestOnlyReleaseTrampolineRegions(); + return result; +} + +TEST(Interception, PatchableFunction) { + TestOverrideFunction override = OverrideFunction; + // Test without function padding. + EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override)); + EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override)); +#if SANITIZER_WINDOWS64 + EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override)); +#else + EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override)); +#endif + EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override)); + + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override)); +} + +#if !SANITIZER_WINDOWS64 +TEST(Interception, PatchableFunctionWithDetour) { + TestOverrideFunction override = OverrideFunctionWithDetour; + // Without the prefix, no function can be detoured. + EXPECT_FALSE(TestFunctionPatching(kPatchableCode1, override)); + EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override)); + EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override)); + EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override)); + + // With the prefix, all functions can be detoured. + FunctionPrefixKind prefix = FunctionPrefixDetour; + EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix)); + EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix)); + EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix)); + EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override, prefix)); + EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode1, override, prefix)); + EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix)); + EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode3, override, prefix)); + EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode4, override, prefix)); + EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode5, override, prefix)); + EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode6, override, prefix)); +} +#endif // !SANITIZER_WINDOWS64 + +TEST(Interception, PatchableFunctionWithRedirectJump) { + TestOverrideFunction override = OverrideFunctionWithRedirectJump; + EXPECT_FALSE(TestFunctionPatching(kPatchableCode1, override)); + EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override)); + EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override)); + EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override)); +} + +TEST(Interception, PatchableFunctionWithHotPatch) { + TestOverrideFunction override = OverrideFunctionWithHotPatch; + FunctionPrefixKind prefix = FunctionPrefixHotPatch; + + EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix)); + EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override, prefix)); + EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix)); + EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override, prefix)); + + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix)); + EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix)); +} + +TEST(Interception, PatchableFunctionWithTrampoline) { + TestOverrideFunction override = OverrideFunctionWithTrampoline; + FunctionPrefixKind prefix = FunctionPrefixPadding; + + EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix)); + EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix)); +#if SANITIZER_WINDOWS64 + EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix)); +#else + EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix)); +#endif + EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override, prefix)); + + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override, prefix)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix)); +} + +TEST(Interception, PatchableFunctionPadding) { + TestOverrideFunction override = OverrideFunction; + FunctionPrefixKind prefix = FunctionPrefixPadding; + + EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix)); + EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix)); +#if SANITIZER_WINDOWS64 + EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix)); +#else + EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix)); +#endif + EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override, prefix)); + + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix)); + EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix)); + EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix)); +} + +} // namespace __interception + +#endif // SANITIZER_WINDOWS +#endif // #if !SANITIZER_DEBUG |