[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
This commit is contained in:
Reid Kleckner 2016-11-15 18:29:17 +00:00
parent b17efcbcc5
commit 0d7c42c7ab
3 changed files with 32 additions and 6 deletions

View File

@ -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() {

View File

@ -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)

View File

@ -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;