110d565efSmrg //===-- asan_allocator.h ----------------------------------------*- C++ -*-===//
210d565efSmrg //
310d565efSmrg // This file is distributed under the University of Illinois Open Source
410d565efSmrg // License. See LICENSE.TXT for details.
510d565efSmrg //
610d565efSmrg //===----------------------------------------------------------------------===//
710d565efSmrg //
810d565efSmrg // This file is a part of AddressSanitizer, an address sanity checker.
910d565efSmrg //
1010d565efSmrg // ASan-private header for asan_allocator.cc.
1110d565efSmrg //===----------------------------------------------------------------------===//
1210d565efSmrg 
1310d565efSmrg #ifndef ASAN_ALLOCATOR_H
1410d565efSmrg #define ASAN_ALLOCATOR_H
1510d565efSmrg 
1610d565efSmrg #include "asan_flags.h"
1710d565efSmrg #include "asan_internal.h"
1810d565efSmrg #include "asan_interceptors.h"
1910d565efSmrg #include "sanitizer_common/sanitizer_allocator.h"
2010d565efSmrg #include "sanitizer_common/sanitizer_list.h"
2110d565efSmrg 
2210d565efSmrg namespace __asan {
2310d565efSmrg 
2410d565efSmrg enum AllocType {
2510d565efSmrg   FROM_MALLOC = 1,  // Memory block came from malloc, calloc, realloc, etc.
2610d565efSmrg   FROM_NEW = 2,     // Memory block came from operator new.
2710d565efSmrg   FROM_NEW_BR = 3   // Memory block came from operator new [ ]
2810d565efSmrg };
2910d565efSmrg 
3010d565efSmrg struct AsanChunk;
3110d565efSmrg 
3210d565efSmrg struct AllocatorOptions {
3310d565efSmrg   u32 quarantine_size_mb;
34c7a68eb7Smrg   u32 thread_local_quarantine_size_kb;
3510d565efSmrg   u16 min_redzone;
3610d565efSmrg   u16 max_redzone;
3710d565efSmrg   u8 may_return_null;
3810d565efSmrg   u8 alloc_dealloc_mismatch;
39c7a68eb7Smrg   s32 release_to_os_interval_ms;
4010d565efSmrg 
4110d565efSmrg   void SetFrom(const Flags *f, const CommonFlags *cf);
4210d565efSmrg   void CopyTo(Flags *f, CommonFlags *cf);
4310d565efSmrg };
4410d565efSmrg 
4510d565efSmrg void InitializeAllocator(const AllocatorOptions &options);
4610d565efSmrg void ReInitializeAllocator(const AllocatorOptions &options);
4710d565efSmrg void GetAllocatorOptions(AllocatorOptions *options);
4810d565efSmrg 
4910d565efSmrg class AsanChunkView {
5010d565efSmrg  public:
AsanChunkView(AsanChunk * chunk)5110d565efSmrg   explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
52c7a68eb7Smrg   bool IsValid() const;        // Checks if AsanChunkView points to a valid
53c7a68eb7Smrg                                // allocated or quarantined chunk.
54c7a68eb7Smrg   bool IsAllocated() const;    // Checks if the memory is currently allocated.
55c7a68eb7Smrg   bool IsQuarantined() const;  // Checks if the memory is currently quarantined.
56c7a68eb7Smrg   uptr Beg() const;            // First byte of user memory.
57c7a68eb7Smrg   uptr End() const;            // Last byte of user memory.
58c7a68eb7Smrg   uptr UsedSize() const;       // Size requested by the user.
59*0fc04c29Smrg   u32 UserRequestedAlignment() const;  // Originally requested alignment.
60c7a68eb7Smrg   uptr AllocTid() const;
61c7a68eb7Smrg   uptr FreeTid() const;
Eq(const AsanChunkView & c)6210d565efSmrg   bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
63c7a68eb7Smrg   u32 GetAllocStackId() const;
64c7a68eb7Smrg   u32 GetFreeStackId() const;
65c7a68eb7Smrg   StackTrace GetAllocStack() const;
66c7a68eb7Smrg   StackTrace GetFreeStack() const;
67c7a68eb7Smrg   AllocType GetAllocType() const;
AddrIsInside(uptr addr,uptr access_size,sptr * offset)68c7a68eb7Smrg   bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) const {
6910d565efSmrg     if (addr >= Beg() && (addr + access_size) <= End()) {
7010d565efSmrg       *offset = addr - Beg();
7110d565efSmrg       return true;
7210d565efSmrg     }
7310d565efSmrg     return false;
7410d565efSmrg   }
AddrIsAtLeft(uptr addr,uptr access_size,sptr * offset)75c7a68eb7Smrg   bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) const {
7610d565efSmrg     (void)access_size;
7710d565efSmrg     if (addr < Beg()) {
7810d565efSmrg       *offset = Beg() - addr;
7910d565efSmrg       return true;
8010d565efSmrg     }
8110d565efSmrg     return false;
8210d565efSmrg   }
AddrIsAtRight(uptr addr,uptr access_size,sptr * offset)83c7a68eb7Smrg   bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) const {
8410d565efSmrg     if (addr + access_size > End()) {
8510d565efSmrg       *offset = addr - End();
8610d565efSmrg       return true;
8710d565efSmrg     }
8810d565efSmrg     return false;
8910d565efSmrg   }
9010d565efSmrg 
9110d565efSmrg  private:
9210d565efSmrg   AsanChunk *const chunk_;
9310d565efSmrg };
9410d565efSmrg 
9510d565efSmrg AsanChunkView FindHeapChunkByAddress(uptr address);
9610d565efSmrg AsanChunkView FindHeapChunkByAllocBeg(uptr address);
9710d565efSmrg 
9810d565efSmrg // List of AsanChunks with total size.
9910d565efSmrg class AsanChunkFifoList: public IntrusiveList<AsanChunk> {
10010d565efSmrg  public:
AsanChunkFifoList(LinkerInitialized)10110d565efSmrg   explicit AsanChunkFifoList(LinkerInitialized) { }
AsanChunkFifoList()10210d565efSmrg   AsanChunkFifoList() { clear(); }
10310d565efSmrg   void Push(AsanChunk *n);
10410d565efSmrg   void PushList(AsanChunkFifoList *q);
10510d565efSmrg   AsanChunk *Pop();
size()10610d565efSmrg   uptr size() { return size_; }
clear()10710d565efSmrg   void clear() {
10810d565efSmrg     IntrusiveList<AsanChunk>::clear();
10910d565efSmrg     size_ = 0;
11010d565efSmrg   }
11110d565efSmrg  private:
11210d565efSmrg   uptr size_;
11310d565efSmrg };
11410d565efSmrg 
11510d565efSmrg struct AsanMapUnmapCallback {
11610d565efSmrg   void OnMap(uptr p, uptr size) const;
11710d565efSmrg   void OnUnmap(uptr p, uptr size) const;
11810d565efSmrg };
11910d565efSmrg 
12010d565efSmrg #if SANITIZER_CAN_USE_ALLOCATOR64
121c7a68eb7Smrg # if SANITIZER_FUCHSIA
122c7a68eb7Smrg const uptr kAllocatorSpace = ~(uptr)0;
123c7a68eb7Smrg const uptr kAllocatorSize  =  0x40000000000ULL;  // 4T.
124c7a68eb7Smrg typedef DefaultSizeClassMap SizeClassMap;
125c7a68eb7Smrg # elif defined(__powerpc64__)
12610d565efSmrg const uptr kAllocatorSpace = ~(uptr)0;
12710d565efSmrg const uptr kAllocatorSize  =  0x20000000000ULL;  // 2T.
12810d565efSmrg typedef DefaultSizeClassMap SizeClassMap;
12910d565efSmrg # elif defined(__aarch64__) && SANITIZER_ANDROID
130*0fc04c29Smrg // Android needs to support 39, 42 and 48 bit VMA.
131*0fc04c29Smrg const uptr kAllocatorSpace =  ~(uptr)0;
13210d565efSmrg const uptr kAllocatorSize  =  0x2000000000ULL;  // 128G.
13310d565efSmrg typedef VeryCompactSizeClassMap SizeClassMap;
13410d565efSmrg # elif defined(__aarch64__)
135*0fc04c29Smrg // AArch64/SANITIZER_CAN_USE_ALLOCATOR64 is only for 42-bit VMA
13610d565efSmrg // so no need to different values for different VMA.
13710d565efSmrg const uptr kAllocatorSpace =  0x10000000000ULL;
13810d565efSmrg const uptr kAllocatorSize  =  0x10000000000ULL;  // 3T.
13910d565efSmrg typedef DefaultSizeClassMap SizeClassMap;
140*0fc04c29Smrg # elif defined(__sparc__)
141*0fc04c29Smrg const uptr kAllocatorSpace = ~(uptr)0;
142*0fc04c29Smrg const uptr kAllocatorSize  =  0x20000000000ULL;  // 2T.
143*0fc04c29Smrg typedef DefaultSizeClassMap SizeClassMap;
14410d565efSmrg # elif SANITIZER_WINDOWS
14510d565efSmrg const uptr kAllocatorSpace = ~(uptr)0;
14610d565efSmrg const uptr kAllocatorSize  =  0x8000000000ULL;  // 500G
14710d565efSmrg typedef DefaultSizeClassMap SizeClassMap;
14810d565efSmrg # else
149c7a68eb7Smrg #if _LP64
15010d565efSmrg const uptr kAllocatorSpace = 0x600000000000ULL;
15110d565efSmrg const uptr kAllocatorSize  =  0x40000000000ULL;  // 4T.
152c7a68eb7Smrg #else
153c7a68eb7Smrg const uptr kAllocatorSpace = 0x60000000UL;
154c7a68eb7Smrg const uptr kAllocatorSize  =  0x40000000ULL;     // 2G.
155c7a68eb7Smrg #endif
15610d565efSmrg typedef DefaultSizeClassMap SizeClassMap;
15710d565efSmrg # endif
15810d565efSmrg struct AP64 {  // Allocator64 parameters. Deliberately using a short name.
15910d565efSmrg   static const uptr kSpaceBeg = kAllocatorSpace;
16010d565efSmrg   static const uptr kSpaceSize = kAllocatorSize;
16110d565efSmrg   static const uptr kMetadataSize = 0;
16210d565efSmrg   typedef __asan::SizeClassMap SizeClassMap;
16310d565efSmrg   typedef AsanMapUnmapCallback MapUnmapCallback;
16410d565efSmrg   static const uptr kFlags = 0;
16510d565efSmrg };
16610d565efSmrg 
16710d565efSmrg typedef SizeClassAllocator64<AP64> PrimaryAllocator;
16810d565efSmrg #else  // Fallback to SizeClassAllocator32.
16910d565efSmrg static const uptr kRegionSizeLog = 20;
17010d565efSmrg static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
17110d565efSmrg # if SANITIZER_WORDSIZE == 32
17210d565efSmrg typedef FlatByteMap<kNumRegions> ByteMap;
17310d565efSmrg # elif SANITIZER_WORDSIZE == 64
17410d565efSmrg typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
17510d565efSmrg # endif
17610d565efSmrg typedef CompactSizeClassMap SizeClassMap;
177c7a68eb7Smrg struct AP32 {
178c7a68eb7Smrg   static const uptr kSpaceBeg = 0;
179c7a68eb7Smrg   static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
180c7a68eb7Smrg   static const uptr kMetadataSize = 16;
181c7a68eb7Smrg   typedef __asan::SizeClassMap SizeClassMap;
182c7a68eb7Smrg   static const uptr kRegionSizeLog = __asan::kRegionSizeLog;
183c7a68eb7Smrg   typedef __asan::ByteMap ByteMap;
184c7a68eb7Smrg   typedef AsanMapUnmapCallback MapUnmapCallback;
185c7a68eb7Smrg   static const uptr kFlags = 0;
186c7a68eb7Smrg };
187c7a68eb7Smrg typedef SizeClassAllocator32<AP32> PrimaryAllocator;
18810d565efSmrg #endif  // SANITIZER_CAN_USE_ALLOCATOR64
18910d565efSmrg 
19010d565efSmrg static const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses;
19110d565efSmrg typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
19210d565efSmrg typedef LargeMmapAllocator<AsanMapUnmapCallback> SecondaryAllocator;
19310d565efSmrg typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
19410d565efSmrg     SecondaryAllocator> AsanAllocator;
19510d565efSmrg 
19610d565efSmrg 
19710d565efSmrg struct AsanThreadLocalMallocStorage {
19810d565efSmrg   uptr quarantine_cache[16];
19910d565efSmrg   AllocatorCache allocator_cache;
20010d565efSmrg   void CommitBack();
20110d565efSmrg  private:
20210d565efSmrg   // These objects are allocated via mmap() and are zero-initialized.
AsanThreadLocalMallocStorageAsanThreadLocalMallocStorage20310d565efSmrg   AsanThreadLocalMallocStorage() {}
20410d565efSmrg };
20510d565efSmrg 
20610d565efSmrg void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
20710d565efSmrg                     AllocType alloc_type);
20810d565efSmrg void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type);
209*0fc04c29Smrg void asan_delete(void *ptr, uptr size, uptr alignment,
210*0fc04c29Smrg                  BufferedStackTrace *stack, AllocType alloc_type);
21110d565efSmrg 
21210d565efSmrg void *asan_malloc(uptr size, BufferedStackTrace *stack);
21310d565efSmrg void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack);
21410d565efSmrg void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack);
21510d565efSmrg void *asan_valloc(uptr size, BufferedStackTrace *stack);
21610d565efSmrg void *asan_pvalloc(uptr size, BufferedStackTrace *stack);
21710d565efSmrg 
218*0fc04c29Smrg void *asan_aligned_alloc(uptr alignment, uptr size, BufferedStackTrace *stack);
21910d565efSmrg int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
22010d565efSmrg                         BufferedStackTrace *stack);
22110d565efSmrg uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp);
22210d565efSmrg 
22310d565efSmrg uptr asan_mz_size(const void *ptr);
22410d565efSmrg void asan_mz_force_lock();
22510d565efSmrg void asan_mz_force_unlock();
22610d565efSmrg 
22710d565efSmrg void PrintInternalAllocatorStats();
22810d565efSmrg void AsanSoftRssLimitExceededCallback(bool exceeded);
22910d565efSmrg 
23010d565efSmrg }  // namespace __asan
23110d565efSmrg #endif  // ASAN_ALLOCATOR_H
232