diff options
author | Reid Kleckner <rnk@google.com> | 2016-11-15 18:29:17 +0000 |
---|---|---|
committer | Reid Kleckner <rnk@google.com> | 2016-11-15 18:29:17 +0000 |
commit | 3b544c6cc98dd653ddb9ec6963929c5b9e937db5 (patch) | |
tree | ea761a7b7c63785b8aab31917288f74aa26c6271 | |
parent | d747c8264087b15f8412b5f02564318668f24606 (diff) | |
download | compiler-rt-3b544c6cc98dd653ddb9ec6963929c5b9e937db5.tar.gz |
[asan] Don't assert that a target is within 2GB on 32-bit Windows
Summary:
In a 32-bit address space, PC-relative jump targets are wrapped, so a
direct branch at 0x90000001 can reach address 0x10000000 with a
displacement of 0x7FFFFFFFF. This can happen in applications, such as
Chrome, that are linked with /LARGEADDRESSAWARE.
Reviewers: etienneb
Subscribers: mgorny, llvm-commits
Differential Revision: https://reviews.llvm.org/D26650
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@286997 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/interception/interception_win.cc | 6 | ||||
-rw-r--r-- | lib/interception/tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/interception/tests/interception_win_test.cc | 31 |
3 files changed, 32 insertions, 6 deletions
diff --git a/lib/interception/interception_win.cc b/lib/interception/interception_win.cc index 8ffc5ae8f..91abecf6d 100644 --- a/lib/interception/interception_win.cc +++ b/lib/interception/interception_win.cc @@ -148,10 +148,16 @@ static void InterceptionFailed() { } static bool DistanceIsWithin2Gig(uptr from, uptr target) { +#if SANITIZER_WINDOWS64 if (from < target) return target - from <= (uptr)0x7FFFFFFFU; else return from - target <= (uptr)0x80000000U; +#else + // In a 32-bit address space, the address calculation will wrap, so this check + // is unnecessary. + return true; +#endif } static uptr GetMmapGranularity() { diff --git a/lib/interception/tests/CMakeLists.txt b/lib/interception/tests/CMakeLists.txt index bfe41fed2..5ea943f9a 100644 --- a/lib/interception/tests/CMakeLists.txt +++ b/lib/interception/tests/CMakeLists.txt @@ -29,6 +29,7 @@ else() endif() if(MSVC) list(APPEND INTERCEPTION_TEST_CFLAGS_COMMON -gcodeview) + list(APPEND INTERCEPTION_TEST_LINK_FLAGS_COMMON -Wl,-largeaddressaware) endif() list(APPEND INTERCEPTION_TEST_LINK_FLAGS_COMMON -g) diff --git a/lib/interception/tests/interception_win_test.cc b/lib/interception/tests/interception_win_test.cc index 67b40f701..684ee0303 100644 --- a/lib/interception/tests/interception_win_test.cc +++ b/lib/interception/tests/interception_win_test.cc @@ -204,7 +204,29 @@ const u8 kUnpatchableCode6[] = { // A buffer holding the dynamically generated code under test. u8* ActiveCode; -size_t ActiveCodeLength = 4096; +const size_t ActiveCodeLength = 4096; + +int InterceptorFunction(int x); + +/// Allocate code memory more than 2GB away from Base. +u8 *AllocateCode2GBAway(u8 *Base) { + // Find a 64K aligned location after Base plus 2GB. + size_t TwoGB = 0x80000000; + size_t AllocGranularity = 0x10000; + Base = (u8 *)((((uptr)Base + TwoGB + AllocGranularity)) & ~(AllocGranularity - 1)); + + // Check if that location is free, and if not, loop over regions until we find + // one that is. + MEMORY_BASIC_INFORMATION mbi = {}; + while (sizeof(mbi) == VirtualQuery(Base, &mbi, sizeof(mbi))) { + if (mbi.State & MEM_FREE) break; + Base += mbi.RegionSize; + } + + // Allocate one RWX page at the free location. + return (u8 *)::VirtualAlloc(Base, ActiveCodeLength, MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE); +} template<class T> static void LoadActiveCode( @@ -212,11 +234,8 @@ static void LoadActiveCode( 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); + ActiveCode = AllocateCode2GBAway((u8*)&InterceptorFunction); + ASSERT_NE(ActiveCode, nullptr) << "failed to allocate RWX memory 2GB away"; } size_t position = 0; |