315 lines · c
1//===-- asan_allocator.h ----------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of AddressSanitizer, an address sanity checker.10//11// ASan-private header for asan_allocator.cpp.12//===----------------------------------------------------------------------===//13 14#ifndef ASAN_ALLOCATOR_H15#define ASAN_ALLOCATOR_H16 17#include "asan_flags.h"18#include "asan_interceptors.h"19#include "asan_internal.h"20#include "sanitizer_common/sanitizer_allocator.h"21#include "sanitizer_common/sanitizer_list.h"22#include "sanitizer_common/sanitizer_platform.h"23 24namespace __asan {25 26enum AllocType {27 FROM_MALLOC = 1, // Memory block came from malloc, calloc, realloc, etc.28 FROM_NEW = 2, // Memory block came from operator new.29 FROM_NEW_BR = 3 // Memory block came from operator new [ ]30};31 32class AsanChunk;33 34struct AllocatorOptions {35 u32 quarantine_size_mb;36 u32 thread_local_quarantine_size_kb;37 u16 min_redzone;38 u16 max_redzone;39 u8 may_return_null;40 u8 alloc_dealloc_mismatch;41 s32 release_to_os_interval_ms;42 43 void SetFrom(const Flags *f, const CommonFlags *cf);44 void CopyTo(Flags *f, CommonFlags *cf);45};46 47void InitializeAllocator(const AllocatorOptions &options);48void ReInitializeAllocator(const AllocatorOptions &options);49void GetAllocatorOptions(AllocatorOptions *options);50void ApplyAllocatorOptions(const AllocatorOptions &options);51 52class AsanChunkView {53 public:54 explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}55 bool IsValid() const; // Checks if AsanChunkView points to a valid56 // allocated or quarantined chunk.57 bool IsAllocated() const; // Checks if the memory is currently allocated.58 bool IsQuarantined() const; // Checks if the memory is currently quarantined.59 uptr Beg() const; // First byte of user memory.60 uptr End() const; // Last byte of user memory.61 uptr UsedSize() const; // Size requested by the user.62 u32 UserRequestedAlignment() const; // Originally requested alignment.63 uptr AllocTid() const;64 uptr FreeTid() const;65 bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }66 u32 GetAllocStackId() const;67 u32 GetFreeStackId() const;68 AllocType GetAllocType() const;69 bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) const {70 if (addr >= Beg() && (addr + access_size) <= End()) {71 *offset = addr - Beg();72 return true;73 }74 return false;75 }76 bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) const {77 (void)access_size;78 if (addr < Beg()) {79 *offset = Beg() - addr;80 return true;81 }82 return false;83 }84 bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) const {85 if (addr + access_size > End()) {86 *offset = addr - End();87 return true;88 }89 return false;90 }91 92 private:93 AsanChunk *const chunk_;94};95 96AsanChunkView FindHeapChunkByAddress(uptr address);97AsanChunkView FindHeapChunkByAllocBeg(uptr address);98 99// List of AsanChunks with total size.100class AsanChunkFifoList: public IntrusiveList<AsanChunk> {101 public:102 explicit AsanChunkFifoList(LinkerInitialized) { }103 AsanChunkFifoList() { clear(); }104 void Push(AsanChunk *n);105 void PushList(AsanChunkFifoList *q);106 AsanChunk *Pop();107 uptr size() { return size_; }108 void clear() {109 IntrusiveList<AsanChunk>::clear();110 size_ = 0;111 }112 private:113 uptr size_;114};115 116struct AsanMapUnmapCallback {117 void OnMap(uptr p, uptr size) const;118 void OnMapSecondary(uptr p, uptr size, uptr user_begin, uptr user_size) const;119 void OnUnmap(uptr p, uptr size) const;120};121 122#if SANITIZER_CAN_USE_ALLOCATOR64123# if SANITIZER_FUCHSIA124// This is a sentinel indicating we do not want the primary allocator arena to125// be placed at a fixed address. It will be anonymously mmap'd.126const uptr kAllocatorSpace = ~(uptr)0;127# if SANITIZER_RISCV64128 129// These are sanitizer tunings that allow all bringup tests for RISCV-64 Sv39 +130// Fuchsia to run with asan-instrumented. That is, we can run bringup, e2e,131// libc, and scudo tests with this configuration.132//133// TODO: This is specifically tuned for Sv39. 48/57 will likely require other134// tunings, or possibly use the same tunings Fuchsia uses for other archs. The135// VMA size isn't technically tied to the Fuchsia System ABI, so once 48/57 is136// supported, we'd need a way of dynamically checking what the VMA size is and137// determining optimal configuration.138 139// This indicates the total amount of space dedicated for the primary allocator140// during initialization. This is roughly proportional to the size set by the141// FuchsiaConfig for scudo (~11.25GB == ~2^33.49). Requesting any more could142// lead to some failures in sanitized bringup tests where we can't allocate new143// vmars because there wouldn't be enough contiguous space. We could try 2^34 if144// we re-evaluate the SizeClassMap settings.145const uptr kAllocatorSize = UINT64_C(1) << 33; // 8GB146 147// This is roughly equivalent to the configuration for the VeryDenseSizeClassMap148// but has fewer size classes (ideally at most 32). Fewer class sizes means the149// region size for each class is larger, thus less chances of running out of150// space for each region. The main differences are the MidSizeLog (which is151// smaller) and the MaxSizeLog (which is larger).152//153// - The MaxSizeLog is higher to allow some of the largest allocations I've154// observed to be placed in the primary allocator's arena as opposed to being155// mmap'd by the secondary allocator. This helps reduce fragmentation from156// large classes. A huge example of this the scudo allocator tests (and its157// testing infrastructure) which malloc's/new's objects on the order of158// hundreds of kilobytes which normally would not be in the primary allocator159// arena with the default VeryDenseSizeClassMap.160// - The MidSizeLog is reduced to help shrink the number of size classes and161// increase region size. Without this, we'd see ASan complain many times about162// a region running out of available space.163//164// This differs a bit from the fuchsia config in scudo, mainly from the NumBits,165// MaxSizeLog, and NumCachedHintT. This should place the number of size classes166// for scudo at 45 and some large objects allocated by this config would be167// placed in the arena whereas scudo would mmap them. The asan allocator needs168// to have a number of classes that are a power of 2 for various internal things169// to work, so we can't match the scudo settings to a tee. The sanitizer170// allocator is slightly slower than scudo's but this is enough to get171// memory-intensive scudo tests to run with asan instrumentation.172typedef SizeClassMap</*kNumBits=*/2,173 /*kMinSizeLog=*/5,174 /*kMidSizeLog=*/8,175 /*kMaxSizeLog=*/18,176 /*kNumCachedHintT=*/8,177 /*kMaxBytesCachedLog=*/10>178 SizeClassMap;179static_assert(SizeClassMap::kNumClassesRounded <= 32,180 "The above tunings were specifically selected to ensure there "181 "would be at most 32 size classes. This restriction could be "182 "loosened to 64 size classes if we can find a configuration of "183 "allocator size and SizeClassMap tunings that allows us to "184 "reliably run all bringup tests in a sanitized environment.");185 186# else // SANITIZER_RISCV64187// These are the default allocator tunings for non-RISCV environments where the188// VMA is usually 48 bits and we have lots of space.189const uptr kAllocatorSize = 0x40000000000ULL; // 4T.190typedef DefaultSizeClassMap SizeClassMap;191# endif // SANITIZER_RISCV64192# else // SANITIZER_FUCHSIA193 194# if SANITIZER_APPLE195const uptr kAllocatorSpace = 0x600000000000ULL;196# else // SANITIZER_APPLE197const uptr kAllocatorSpace = ~(uptr)0;198# endif // SANITIZER_APPLE199 200# if defined(__powerpc64__)201const uptr kAllocatorSize = 0x20000000000ULL; // 2T.202typedef DefaultSizeClassMap SizeClassMap;203# elif defined(__aarch64__) && SANITIZER_ANDROID204// Android needs to support 39, 42 and 48 bit VMA.205const uptr kAllocatorSize = 0x2000000000ULL; // 128G.206typedef VeryCompactSizeClassMap SizeClassMap;207# elif SANITIZER_RISCV64208const uptr kAllocatorSize = 0x2000000000ULL; // 128G.209typedef VeryDenseSizeClassMap SizeClassMap;210# elif defined(__sparc__)211const uptr kAllocatorSize = 0x20000000000ULL; // 2T.212typedef DefaultSizeClassMap SizeClassMap;213# elif SANITIZER_WINDOWS214const uptr kAllocatorSize = 0x8000000000ULL; // 500G215typedef DefaultSizeClassMap SizeClassMap;216# elif SANITIZER_APPLE217const uptr kAllocatorSize = 0x40000000000ULL; // 4T.218typedef DefaultSizeClassMap SizeClassMap;219# else220const uptr kAllocatorSize = 0x40000000000ULL; // 4T.221typedef DefaultSizeClassMap SizeClassMap;222# endif // defined(__powerpc64__) etc.223# endif // SANITIZER_FUCHSIA224template <typename AddressSpaceViewTy>225struct AP64 { // Allocator64 parameters. Deliberately using a short name.226 static const uptr kSpaceBeg = kAllocatorSpace;227 static const uptr kSpaceSize = kAllocatorSize;228 static const uptr kMetadataSize = 0;229 typedef __asan::SizeClassMap SizeClassMap;230 typedef AsanMapUnmapCallback MapUnmapCallback;231 static const uptr kFlags = 0;232 using AddressSpaceView = AddressSpaceViewTy;233};234 235template <typename AddressSpaceView>236using PrimaryAllocatorASVT = SizeClassAllocator64<AP64<AddressSpaceView>>;237using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;238#else // SANITIZER_CAN_USE_ALLOCATOR64. Fallback to SizeClassAllocator32.239typedef CompactSizeClassMap SizeClassMap;240template <typename AddressSpaceViewTy>241struct AP32 {242 static const uptr kSpaceBeg = SANITIZER_MMAP_BEGIN;243 static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;244 static const uptr kMetadataSize = 0;245 typedef __asan::SizeClassMap SizeClassMap;246 static const uptr kRegionSizeLog = 20;247 using AddressSpaceView = AddressSpaceViewTy;248 typedef AsanMapUnmapCallback MapUnmapCallback;249 static const uptr kFlags = 0;250};251template <typename AddressSpaceView>252using PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView> >;253using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;254#endif // SANITIZER_CAN_USE_ALLOCATOR64255 256static const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses;257 258template <typename AddressSpaceView>259using AsanAllocatorASVT =260 CombinedAllocator<PrimaryAllocatorASVT<AddressSpaceView>>;261using AsanAllocator = AsanAllocatorASVT<LocalAddressSpaceView>;262using AllocatorCache = AsanAllocator::AllocatorCache;263 264struct AsanThreadLocalMallocStorage {265 uptr quarantine_cache[16];266 AllocatorCache allocator_cache;267 void CommitBack();268 private:269 // These objects are allocated via mmap() and are zero-initialized.270 AsanThreadLocalMallocStorage() {}271};272 273void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack);274void asan_free(void *ptr, BufferedStackTrace *stack);275 276void *asan_malloc(uptr size, BufferedStackTrace *stack);277void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack);278void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack);279void *asan_reallocarray(void *p, uptr nmemb, uptr size,280 BufferedStackTrace *stack);281void *asan_valloc(uptr size, BufferedStackTrace *stack);282void *asan_pvalloc(uptr size, BufferedStackTrace *stack);283 284void *asan_aligned_alloc(uptr alignment, uptr size, BufferedStackTrace *stack);285int asan_posix_memalign(void **memptr, uptr alignment, uptr size,286 BufferedStackTrace *stack);287uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp);288 289void *asan_new(uptr size, BufferedStackTrace *stack);290void *asan_new_aligned(uptr size, uptr alignment, BufferedStackTrace *stack);291void *asan_new_array(uptr size, BufferedStackTrace *stack);292void *asan_new_array_aligned(uptr size, uptr alignment,293 BufferedStackTrace *stack);294void asan_delete(void *ptr, BufferedStackTrace *stack);295void asan_delete_aligned(void *ptr, uptr alignment, BufferedStackTrace *stack);296void asan_delete_sized(void *ptr, uptr size, BufferedStackTrace *stack);297void asan_delete_sized_aligned(void *ptr, uptr size, uptr alignment,298 BufferedStackTrace *stack);299void asan_delete_array(void *ptr, BufferedStackTrace *stack);300void asan_delete_array_aligned(void *ptr, uptr alignment,301 BufferedStackTrace *stack);302void asan_delete_array_sized(void *ptr, uptr size, BufferedStackTrace *stack);303void asan_delete_array_sized_aligned(void *ptr, uptr size, uptr alignment,304 BufferedStackTrace *stack);305 306uptr asan_mz_size(const void *ptr);307void asan_mz_force_lock();308void asan_mz_force_unlock();309 310void PrintInternalAllocatorStats();311void AsanSoftRssLimitExceededCallback(bool exceeded);312 313} // namespace __asan314#endif // ASAN_ALLOCATOR_H315