From 0d7c42c7abb3a822ce5b3c5960923dee07cc496f Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 15 Nov 2016 18:29:17 +0000 Subject: [PATCH] [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 llvm-svn: 286997 --- compiler-rt/lib/interception/interception_win.cc | 6 +++++ compiler-rt/lib/interception/tests/CMakeLists.txt | 1 + .../interception/tests/interception_win_test.cc | 31 +++++++++++++++++----- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/compiler-rt/lib/interception/interception_win.cc b/compiler-rt/lib/interception/interception_win.cc index 8ffc5ae..91abecf 100644 --- a/compiler-rt/lib/interception/interception_win.cc +++ b/compiler-rt/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/compiler-rt/lib/interception/tests/CMakeLists.txt b/compiler-rt/lib/interception/tests/CMakeLists.txt index bfe41fe..5ea943f 100644 --- a/compiler-rt/lib/interception/tests/CMakeLists.txt +++ b/compiler-rt/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/compiler-rt/lib/interception/tests/interception_win_test.cc b/compiler-rt/lib/interception/tests/interception_win_test.cc index 67b40f7..684ee03 100644 --- a/compiler-rt/lib/interception/tests/interception_win_test.cc +++ b/compiler-rt/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 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; -- 2.7.4