Index: compiler-rt/lib/lsan/lsan_allocator.h =================================================================== --- compiler-rt/lib/lsan/lsan_allocator.h +++ compiler-rt/lib/lsan/lsan_allocator.h @@ -49,8 +49,173 @@ u32 stack_trace_id; }; -#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \ - defined(__arm__) +#if defined(__aarch64__) + +template +struct AP32 { + static const uptr kSpaceBeg = 0; + static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; + static const uptr kMetadataSize = sizeof(ChunkMetadata); + typedef __sanitizer::CompactSizeClassMap SizeClassMap; + static const uptr kRegionSizeLog = 20; + using AddressSpaceView = AddressSpaceViewTy; + typedef NoOpMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; +}; + +const uptr kAllocatorSpace = 0x600000000000ULL; +const uptr kAllocatorSize = 0x40000000000ULL; // 4T. + +template +struct AP64 { // Allocator64 parameters. Deliberately using a short name. + static const uptr kSpaceBeg = kAllocatorSpace; + static const uptr kSpaceSize = kAllocatorSize; + static const uptr kMetadataSize = sizeof(ChunkMetadata); + typedef DefaultSizeClassMap SizeClassMap; + typedef NoOpMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; + using AddressSpaceView = AddressSpaceViewTy; +}; + +template +using Allocator32ASVT = SizeClassAllocator32>; +template +using Allocator64ASVT = SizeClassAllocator64>; + +using Allocator32 = Allocator32ASVT; +using Allocator64 = Allocator64ASVT; + +extern bool UseAllocator32; + +template +class DoubleAllocator { + A32 a32; + A64 a64; + + public: + class DoubleAllocatorCache { + typename A32::AllocatorCache a32; + typename A64::AllocatorCache a64; + + public: + void Init(AllocatorGlobalStats *s) { + if (UseAllocator32) + a32.Init(s); + else + a64.Init(s); + } + void *Allocate(DoubleAllocator *allocator, uptr class_id) { + if (UseAllocator32) + return a32.Allocate(&allocator->a32, class_id); + return a64.Allocate(&allocator->a64, class_id); + } + + void Deallocate(DoubleAllocator *allocator, uptr class_id, void *p) { + if (UseAllocator32) + a32.Deallocate(&allocator->a32, class_id, p); + else + a64.Deallocate(&allocator->a64, class_id, p); + } + + void Drain(DoubleAllocator *allocator) { + if (UseAllocator32) + a32.Drain(&allocator->a32); + else + a64.Drain(&allocator->a64); + } + + void Destroy(DoubleAllocator *allocator, AllocatorGlobalStats *s) { + if (UseAllocator32) + a32.Destroy(&allocator->a32, s); + else + a64.Destroy(&allocator->a64, s); + } + }; + + using MapUnmapCallback = Allocator32::MapUnmapCallback; + using AddressSpaceView = Allocator32::AddressSpaceView; + using AllocatorCache = DoubleAllocatorCache; + + void Init(s32 release_to_os_interval_ms) { + if (UseAllocator32) + a32.Init(release_to_os_interval_ms); + else + a64.Init(release_to_os_interval_ms); + } + + static bool CanAllocate(uptr size, uptr alignment) { + if (UseAllocator32) + return A32::CanAllocate(size, alignment); + return A64::CanAllocate(size, alignment); + } + + static uptr ClassID(uptr size) { + if (UseAllocator32) + return A32::ClassID(size); + return A64::ClassID(size); + } + + bool PointerIsMine(const void *p) { + if (UseAllocator32) + return a32.PointerIsMine(p); + return a64.PointerIsMine(p); + } + + void *GetMetaData(const void *p) { + if (UseAllocator32) + return a32.GetMetaData(p); + return a64.GetMetaData(p); + } + + uptr GetSizeClass(const void *p) { + if (UseAllocator32) + return a32.GetSizeClass(p); + return a64.GetSizeClass(p); + } + + void ForEachChunk(ForEachChunkCallback callback, void *arg) { + if (UseAllocator32) + a32.ForEachChunk(callback, arg); + else + a64.ForEachChunk(callback, arg); + } + + void TestOnlyUnmap() { + if (UseAllocator32) + a32.TestOnlyUnmap(); + else + a64.TestOnlyUnmap(); + } + void ForceLock() { + if (UseAllocator32) + a32.ForceLock(); + else + a64.ForceLock(); + } + void ForceUnlock() { + if (UseAllocator32) + a32.ForceUnlock(); + else + a64.ForceUnlock(); + } + void *GetBlockBegin(const void *p) { + if (UseAllocator32) + return a32.GetBlockBegin(p); + return a64.GetBlockBegin(p); + } + uptr GetActuallyAllocatedSize(void *p) { + if (UseAllocator32) + return a32.GetActuallyAllocatedSize(p); + return a64.GetActuallyAllocatedSize(p); + } +}; + +template +using PrimaryAllocatorASVT = DoubleAllocator, + Allocator64ASVT>; +using PrimaryAllocator = PrimaryAllocatorASVT; + +#elif defined(__mips64) || defined(__i386__) || defined(__arm__) template struct AP32 { static const uptr kSpaceBeg = 0; Index: compiler-rt/lib/lsan/lsan_allocator.cc =================================================================== --- compiler-rt/lib/lsan/lsan_allocator.cc +++ compiler-rt/lib/lsan/lsan_allocator.cc @@ -35,8 +35,16 @@ #endif static Allocator allocator; +bool UseAllocator32 = false; void InitializeAllocator() { + // Check whether the address space is 47-bit, that is large enough for the + // 64-bit allocator. + if (GetMaxVirtualAddress() < (((uptr)1 << 48) - 1)) + UseAllocator32 = true; + else + UseAllocator32 = false; + SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); allocator.InitLinkerInitialized( common_flags()->allocator_release_to_os_interval_ms); 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 @@ -690,6 +690,123 @@ TestCombinedAllocator(); } +static bool use1 = false; + +template +class DoubleAllocator { + A1 a1; + A2 a2; + + public: + class DoubleAllocatorCache { + typename A1::AllocatorCache a1; + typename A2::AllocatorCache a2; + + public: + void Init(AllocatorGlobalStats *s) { + if (use1) + return a1.Init(s); + else + return a2.Init(s); + } + void *Allocate(DoubleAllocator *allocator, uptr class_id) { + if (use1) + return a1.Allocate(&allocator->a1, class_id); + else + return a2.Allocate(&allocator->a2, class_id); + } + + void Deallocate(DoubleAllocator *allocator, uptr class_id, void *p) { + if (use1) + return a1.Deallocate(&allocator->a1, class_id, p); + else + return a2.Deallocate(&allocator->a2, class_id, p); + } + + void Drain(DoubleAllocator *allocator) { + if (use1) + return a1.Drain(&allocator->a1); + else + return a2.Drain(&allocator->a2); + } + + void Destroy(DoubleAllocator *allocator, AllocatorGlobalStats *s) { + if (use1) + return a1.Destroy(&allocator->a1, s); + else + return a2.Destroy(&allocator->a2, s); + } + }; + + using MapUnmapCallback = Allocator32Compact::MapUnmapCallback; + using AddressSpaceView = Allocator32Compact::AddressSpaceView; + using AllocatorCache = DoubleAllocatorCache; + + void Init(s32 release_to_os_interval_ms) { + if (use1) + return a1.Init(release_to_os_interval_ms); + else + return a2.Init(release_to_os_interval_ms); + } + + static bool CanAllocate(uptr size, uptr alignment) { + if (use1) + return A1::CanAllocate(size, alignment); + else + return A2::CanAllocate(size, alignment); + } + + static uptr ClassID(uptr size) { + if (use1) + return A1::ClassID(size); + else + return A2::ClassID(size); + } + + bool PointerIsMine(const void *p) { + if (use1) + return a1.PointerIsMine(p); + else + return a2.PointerIsMine(p); + } + + void *GetMetaData(const void *p) { + if (use1) + return a1.GetMetaData(p); + else + return a2.GetMetaData(p); + } + + uptr GetSizeClass(const void *p) { + if (use1) + return a1.GetSizeClass(p); + else + return a2.GetSizeClass(p); + } + + void ForEachChunk(ForEachChunkCallback callback, void *arg) { + if (use1) + return a1.ForEachChunk(callback, arg); + else + return a2.ForEachChunk(callback, arg); + } + + void TestOnlyUnmap() { + if (use1) + return a1.TestOnlyUnmap(); + else + return a2.TestOnlyUnmap(); + } +}; + +TEST(SanitizerCommon, CombinedDoubleAllocator) { + TestCombinedAllocator< + DoubleAllocator>(); + use1 = true; + TestCombinedAllocator< + DoubleAllocator>(); +} + #if !SANITIZER_ANDROID TEST(SanitizerCommon, CombinedAllocator64Compact) { TestCombinedAllocator();