Index: compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h +++ compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -209,6 +209,16 @@ UnmapWithCallbackOrDie(SpaceBeg(), kSpaceSize + AdditionalSize()); } + // Test-only. + uptr TestOnlySize() { + return kSpaceSize + AdditionalSize(); + } + + // Test-only. + uptr TestOnlySpaceBeg() { + return SpaceBeg(); + } + static void FillMemoryProfile(uptr start, uptr rss, bool file, uptr *stats, uptr stats_size) { for (uptr class_id = 0; class_id < stats_size; class_id++) Index: compiler-rt/lib/sanitizer_common/sanitizer_common.h =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -83,6 +83,20 @@ uptr *tls_addr, uptr *tls_size); // Memory management +// This class relies on zero-initialization. +class ReservedAddressRange { + public: + uptr Init(uptr size, const char *name = nullptr, uptr fixed_addr = 0); + uptr Map(uptr offset, uptr size, bool tolerate_enomem = false); + void *base() { return base_; } + private: +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-private-field" + uptr os_cookie_; + void* base_; + uptr size_; +}; + void *MmapOrDie(uptr size, const char *mem_type, bool raw_report = false); INLINE void *MmapOrDieQuietly(uptr size, const char *mem_type) { return MmapOrDie(size, mem_type, /*raw_report*/ true); Index: compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -236,6 +236,19 @@ return DoAnonymousMmapOrDie(size, mem_type, false, false); } +uptr ReservedAddressRange::Init(uptr init_size, const char* name = nullptr, + uptr fixed_addr = uptr(0)) { + return reinterpret_cast(MmapNoAccess(init_size)); +} + +// Uses fixed_addr for now. +// Will use offset instead once we've implemented this function for real. +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size, + bool tolerate_enomem = true) { + return reinterpret_cast(MmapFixedOrDie(fixed_addr, size, + tolerate_enomem)); +} + // MmapNoAccess and MmapFixedOrDie are used only by sanitizer_allocator. // Instead of doing exactly what they say, we make MmapNoAccess actually // just allocate a VMAR to reserve the address space. Then MmapFixedOrDie Index: compiler-rt/lib/sanitizer_common/sanitizer_posix.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_posix.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_posix.cc @@ -141,6 +141,16 @@ return MmapFixedImpl(fixed_addr, size, false /*tolerate_enomem*/); } +// Uses fixed_addr for now. +// Will use offset instead once we've implemented this function for real. +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, + bool tolerate_enomem) { + if (tolerate_enomem) { + return reinterpret_cast(MmapFixedOrDieOnFatalError(fixed_addr, size)); + } + return reinterpret_cast(MmapFixedOrDie(fixed_addr, size)); +} + void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) { return MmapFixedImpl(fixed_addr, size, true /*tolerate_enomem*/); } Index: compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -337,6 +337,16 @@ return (void *)p; } +uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { + if (fixed_addr) { + base_ = MmapFixedNoAccess(fixed_addr, size, name); + } else { + base_ = MmapNoAccess(size); + } + size_ = size; + return reinterpret_cast(base_); +} + void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { int fd = name ? GetNamedMappingFd(name, size) : -1; unsigned flags = MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE; Index: compiler-rt/lib/sanitizer_common/sanitizer_win.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_win.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_win.cc @@ -235,6 +235,16 @@ return p; } +// Uses fixed_addr for now. +// Will use offset instead once we've implemented this function for real. +uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, + bool tolerate_enomem) { + if (tolerate_enomem) { + return reinterpret_cast(MmapFixedOrDieOnFatalError(fixed_addr, size)); + } + return reinterpret_cast(MmapFixedOrDie(uptr fixed_addr, uptr size)); +} + void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) { void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_COMMIT, PAGE_READWRITE); @@ -252,6 +262,13 @@ return MmapOrDie(size, mem_type); } +uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { + if (fixed_addr) { + return reinterpret_cast(MmapFixedNoAccess(fixed_addr, size, name)); + } + return reinterpret_cast(MmapNoAccess(size)); +} + void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { (void)name; // unsupported void *res = VirtualAlloc((LPVOID)fixed_addr, size, Index: compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cc =================================================================== --- compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cc +++ compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cc @@ -481,6 +481,28 @@ } #endif +#if SANITIZER_CAN_USE_ALLOCATOR64 + +TEST(SanitizerCommon, ReservedAddressRange) { + Allocator64 a; + a.Init(kReleaseToOSIntervalNever); + // Returns (beginnning address of mmaped space + (kRegionSize * 0)). + // We have to use this indirect way of determining it, since the starting + // address is private. + uptr addr = a.GetRegionBeginBySizeClass(0); + uptr size = a.TestOnlySize(); + // The actual beginning of the space can be different from addr. + uptr spacebeg = a.TestOnlySpaceBeg(); + a.TestOnlyUnmap(); + + // Try to make a ReservedAddressSpace where the Allocator64 was. + ReservedAddressRange address_range; + address_range.Init(size, "", addr); + CHECK_EQ(addr, reinterpret_cast(address_range.base())); +} + +#endif + TEST(SanitizerCommon, LargeMmapAllocator) { LargeMmapAllocator a; a.Init();