diff --git a/compiler-rt/lib/lsan/lsan_allocator.h b/compiler-rt/lib/lsan/lsan_allocator.h --- a/compiler-rt/lib/lsan/lsan_allocator.h +++ b/compiler-rt/lib/lsan/lsan_allocator.h @@ -49,8 +49,35 @@ 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; +}; + +template +struct AP64 { // Allocator64 parameters. Deliberately using a short name. + static const uptr kSpaceBeg = 0x600000000000ULL; + static const uptr kSpaceSize = 0x40000000000ULL; // 4T. + static const uptr kMetadataSize = sizeof(ChunkMetadata); + typedef DefaultSizeClassMap SizeClassMap; + typedef NoOpMapUnmapCallback MapUnmapCallback; + static const uptr kFlags = 0; + using AddressSpaceView = AddressSpaceViewTy; +}; + +template +using PrimaryAllocatorASVT = + SizeClassAllocatorPair, AP32>; +using PrimaryAllocator = PrimaryAllocatorASVT; +#elif defined(__mips64) || defined(__i386__) || defined(__arm__) template struct AP32 { static const uptr kSpaceBeg = 0; diff --git a/compiler-rt/lib/lsan/lsan_allocator.cc b/compiler-rt/lib/lsan/lsan_allocator.cc --- a/compiler-rt/lib/lsan/lsan_allocator.cc +++ b/compiler-rt/lib/lsan/lsan_allocator.cc @@ -38,6 +38,13 @@ void InitializeAllocator() { SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); +#if defined(__aarch64__) + // 47+ bit Aarch64 address space needs a 64-bit allocator. + if (GetMaxVirtualAddress() < (((uptr)1 << 48) - 1)) + allocator.Use2(); // 32-bit. + else + allocator.Use1(); // 64-bit. +#endif allocator.InitLinkerInitialized( common_flags()->allocator_release_to_os_interval_ms); } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h b/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h @@ -75,6 +75,7 @@ #include "sanitizer_allocator_local_cache.h" #include "sanitizer_allocator_secondary.h" #include "sanitizer_allocator_combined.h" +#include "sanitizer_allocator_primary_pair.h" } // namespace __sanitizer diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary_pair.h b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary_pair.h new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary_pair.h @@ -0,0 +1,109 @@ +//===-- sanitizer_allocator_secondary.h -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Part of the Sanitizer Allocator. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_ALLOCATOR_H +#error This file must be included inside sanitizer_allocator.h +#endif + +static bool use1 = false; + +template +class SizeClassAllocatorPair { + A1 a1; + A2 a2; + + public: + class AllocatorCache { + typename A1::AllocatorCache a1; + typename A2::AllocatorCache a2; + + public: + void Init(AllocatorGlobalStats *s) { + if (use1) + return a1.Init(s); + return a2.Init(s); + } + void *Allocate(SizeClassAllocatorPair *allocator, uptr class_id) { + if (use1) + return a1.Allocate(&allocator->a1, class_id); + return a2.Allocate(&allocator->a2, class_id); + } + + void Deallocate(SizeClassAllocatorPair *allocator, uptr class_id, void *p) { + if (use1) + return a1.Deallocate(&allocator->a1, class_id, p); + return a2.Deallocate(&allocator->a2, class_id, p); + } + + void Drain(SizeClassAllocatorPair *allocator) { + if (use1) + return a1.Drain(&allocator->a1); + return a2.Drain(&allocator->a2); + } + + void Destroy(SizeClassAllocatorPair *allocator, AllocatorGlobalStats *s) { + if (use1) + return a1.Destroy(&allocator->a1, s); + return a2.Destroy(&allocator->a2, s); + } + }; + + void Init(s32 release_to_os_interval_ms) { + if (use1) + return a1.Init(release_to_os_interval_ms); + return a2.Init(release_to_os_interval_ms); + } + + void Use1() { use1 = true; } + void Use2() { use1 = false; } + + static bool CanAllocate(uptr size, uptr alignment) { + if (use1) + return A1::CanAllocate(size, alignment); + return A2::CanAllocate(size, alignment); + } + + static uptr ClassID(uptr size) { + if (use1) + return A1::ClassID(size); + return A2::ClassID(size); + } + + bool PointerIsMine(const void *p) { + if (use1) + return a1.PointerIsMine(p); + return a2.PointerIsMine(p); + } + + void *GetMetaData(const void *p) { + if (use1) + return a1.GetMetaData(p); + return a2.GetMetaData(p); + } + + uptr GetSizeClass(const void *p) { + if (use1) + return a1.GetSizeClass(p); + return a2.GetSizeClass(p); + } + + void ForEachChunk(ForEachChunkCallback callback, void *arg) { + if (use1) + return a1.ForEachChunk(callback, arg); + return a2.ForEachChunk(callback, arg); + } + + void TestOnlyUnmap() { + if (use1) + return a1.TestOnlyUnmap(); + return a2.TestOnlyUnmap(); + } +};