1229109Sed//===-- asan_allocator.h ----------------------------------------*- C++ -*-===// 2229109Sed// 3229109Sed// The LLVM Compiler Infrastructure 4229109Sed// 5229109Sed// This file is distributed under the University of Illinois Open Source 6229109Sed// License. See LICENSE.TXT for details. 7229109Sed// 8229109Sed//===----------------------------------------------------------------------===// 9229109Sed// 10229109Sed// This file is a part of AddressSanitizer, an address sanity checker. 11229109Sed// 12280031Sdim// ASan-private header for asan_allocator.cc. 13229109Sed//===----------------------------------------------------------------------===// 14229109Sed 15229109Sed#ifndef ASAN_ALLOCATOR_H 16229109Sed#define ASAN_ALLOCATOR_H 17229109Sed 18280031Sdim#include "asan_flags.h" 19229109Sed#include "asan_internal.h" 20229109Sed#include "asan_interceptors.h" 21276789Sdim#include "sanitizer_common/sanitizer_allocator.h" 22245614Sandrew#include "sanitizer_common/sanitizer_list.h" 23229109Sed 24229109Sednamespace __asan { 25229109Sed 26245614Sandrewenum AllocType { 27245614Sandrew FROM_MALLOC = 1, // Memory block came from malloc, calloc, realloc, etc. 28245614Sandrew FROM_NEW = 2, // Memory block came from operator new. 29245614Sandrew FROM_NEW_BR = 3 // Memory block came from operator new [ ] 30245614Sandrew}; 31245614Sandrew 32229109Sedstruct AsanChunk; 33229109Sed 34280031Sdimstruct AllocatorOptions { 35280031Sdim u32 quarantine_size_mb; 36280031Sdim u16 min_redzone; 37280031Sdim u16 max_redzone; 38280031Sdim u8 may_return_null; 39280031Sdim u8 alloc_dealloc_mismatch; 40251034Sed 41280031Sdim void SetFrom(const Flags *f, const CommonFlags *cf); 42280031Sdim void CopyTo(Flags *f, CommonFlags *cf); 43280031Sdim}; 44280031Sdim 45280031Sdimvoid InitializeAllocator(const AllocatorOptions &options); 46280031Sdimvoid ReInitializeAllocator(const AllocatorOptions &options); 47280031Sdimvoid GetAllocatorOptions(AllocatorOptions *options); 48280031Sdim 49245614Sandrewclass AsanChunkView { 50229109Sed public: 51245614Sandrew explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {} 52274201Sdim bool IsValid(); // Checks if AsanChunkView points to a valid allocated 53274201Sdim // or quarantined chunk. 54274201Sdim uptr Beg(); // First byte of user memory. 55274201Sdim uptr End(); // Last byte of user memory. 56274201Sdim uptr UsedSize(); // Size requested by the user. 57245614Sandrew uptr AllocTid(); 58245614Sandrew uptr FreeTid(); 59276789Sdim bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; } 60276789Sdim StackTrace GetAllocStack(); 61276789Sdim StackTrace GetFreeStack(); 62251034Sed bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) { 63245614Sandrew if (addr >= Beg() && (addr + access_size) <= End()) { 64245614Sandrew *offset = addr - Beg(); 65245614Sandrew return true; 66245614Sandrew } 67245614Sandrew return false; 68245614Sandrew } 69251034Sed bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) { 70245614Sandrew (void)access_size; 71245614Sandrew if (addr < Beg()) { 72245614Sandrew *offset = Beg() - addr; 73245614Sandrew return true; 74245614Sandrew } 75245614Sandrew return false; 76245614Sandrew } 77251034Sed bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) { 78251034Sed if (addr + access_size > End()) { 79251034Sed *offset = addr - End(); 80245614Sandrew return true; 81245614Sandrew } 82245614Sandrew return false; 83245614Sandrew } 84245614Sandrew 85245614Sandrew private: 86245614Sandrew AsanChunk *const chunk_; 87245614Sandrew}; 88245614Sandrew 89245614SandrewAsanChunkView FindHeapChunkByAddress(uptr address); 90245614Sandrew 91245614Sandrew// List of AsanChunks with total size. 92245614Sandrewclass AsanChunkFifoList: public IntrusiveList<AsanChunk> { 93245614Sandrew public: 94229109Sed explicit AsanChunkFifoList(LinkerInitialized) { } 95229109Sed AsanChunkFifoList() { clear(); } 96229109Sed void Push(AsanChunk *n); 97229109Sed void PushList(AsanChunkFifoList *q); 98229109Sed AsanChunk *Pop(); 99238901Sandrew uptr size() { return size_; } 100229109Sed void clear() { 101245614Sandrew IntrusiveList<AsanChunk>::clear(); 102229109Sed size_ = 0; 103229109Sed } 104229109Sed private: 105238901Sandrew uptr size_; 106229109Sed}; 107229109Sed 108276789Sdimstruct AsanMapUnmapCallback { 109276789Sdim void OnMap(uptr p, uptr size) const; 110276789Sdim void OnUnmap(uptr p, uptr size) const; 111276789Sdim}; 112276789Sdim 113276789Sdim#if SANITIZER_CAN_USE_ALLOCATOR64 114276789Sdim# if defined(__powerpc64__) 115276789Sdimconst uptr kAllocatorSpace = 0xa0000000000ULL; 116276789Sdimconst uptr kAllocatorSize = 0x20000000000ULL; // 2T. 117296417Sdim# elif defined(__aarch64__) 118296417Sdim// AArch64/SANITIZIER_CAN_USER_ALLOCATOR64 is only for 42-bit VMA 119296417Sdim// so no need to different values for different VMA. 120296417Sdimconst uptr kAllocatorSpace = 0x10000000000ULL; 121296417Sdimconst uptr kAllocatorSize = 0x10000000000ULL; // 3T. 122276789Sdim# else 123276789Sdimconst uptr kAllocatorSpace = 0x600000000000ULL; 124276789Sdimconst uptr kAllocatorSize = 0x40000000000ULL; // 4T. 125276789Sdim# endif 126276789Sdimtypedef DefaultSizeClassMap SizeClassMap; 127276789Sdimtypedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/, 128276789Sdim SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator; 129276789Sdim#else // Fallback to SizeClassAllocator32. 130276789Sdimstatic const uptr kRegionSizeLog = 20; 131276789Sdimstatic const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; 132276789Sdim# if SANITIZER_WORDSIZE == 32 133276789Sdimtypedef FlatByteMap<kNumRegions> ByteMap; 134276789Sdim# elif SANITIZER_WORDSIZE == 64 135276789Sdimtypedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; 136276789Sdim# endif 137276789Sdimtypedef CompactSizeClassMap SizeClassMap; 138276789Sdimtypedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 16, 139276789Sdim SizeClassMap, kRegionSizeLog, 140276789Sdim ByteMap, 141276789Sdim AsanMapUnmapCallback> PrimaryAllocator; 142276789Sdim#endif // SANITIZER_CAN_USE_ALLOCATOR64 143276789Sdim 144288943Sdimstatic const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses; 145276789Sdimtypedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache; 146276789Sdimtypedef LargeMmapAllocator<AsanMapUnmapCallback> SecondaryAllocator; 147276789Sdimtypedef CombinedAllocator<PrimaryAllocator, AllocatorCache, 148280031Sdim SecondaryAllocator> AsanAllocator; 149276789Sdim 150276789Sdim 151229109Sedstruct AsanThreadLocalMallocStorage { 152245614Sandrew uptr quarantine_cache[16]; 153280031Sdim AllocatorCache allocator_cache; 154229109Sed void CommitBack(); 155276789Sdim private: 156276789Sdim // These objects are allocated via mmap() and are zero-initialized. 157276789Sdim AsanThreadLocalMallocStorage() {} 158229109Sed}; 159229109Sed 160276789Sdimvoid *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, 161245614Sandrew AllocType alloc_type); 162276789Sdimvoid asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type); 163276789Sdimvoid asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack, 164276789Sdim AllocType alloc_type); 165229109Sed 166276789Sdimvoid *asan_malloc(uptr size, BufferedStackTrace *stack); 167276789Sdimvoid *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack); 168276789Sdimvoid *asan_realloc(void *p, uptr size, BufferedStackTrace *stack); 169276789Sdimvoid *asan_valloc(uptr size, BufferedStackTrace *stack); 170276789Sdimvoid *asan_pvalloc(uptr size, BufferedStackTrace *stack); 171229109Sed 172238901Sandrewint asan_posix_memalign(void **memptr, uptr alignment, uptr size, 173276789Sdim BufferedStackTrace *stack); 174274201Sdimuptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp); 175229109Sed 176238901Sandrewuptr asan_mz_size(const void *ptr); 177238901Sandrewvoid asan_mz_force_lock(); 178238901Sandrewvoid asan_mz_force_unlock(); 179229109Sed 180245614Sandrewvoid PrintInternalAllocatorStats(); 181280031Sdimvoid AsanSoftRssLimitExceededCallback(bool exceeded); 182245614Sandrew 183229109Sed} // namespace __asan 184229109Sed#endif // ASAN_ALLOCATOR_H 185