1229109Sed//===-- asan_allocator.h ----------------------------------------*- C++ -*-===//
2229109Sed//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6229109Sed//
7229109Sed//===----------------------------------------------------------------------===//
8229109Sed//
9229109Sed// This file is a part of AddressSanitizer, an address sanity checker.
10229109Sed//
11360784Sdim// ASan-private header for asan_allocator.cpp.
12229109Sed//===----------------------------------------------------------------------===//
13229109Sed
14229109Sed#ifndef ASAN_ALLOCATOR_H
15229109Sed#define ASAN_ALLOCATOR_H
16229109Sed
17280031Sdim#include "asan_flags.h"
18229109Sed#include "asan_internal.h"
19229109Sed#include "asan_interceptors.h"
20276789Sdim#include "sanitizer_common/sanitizer_allocator.h"
21245614Sandrew#include "sanitizer_common/sanitizer_list.h"
22229109Sed
23229109Sednamespace __asan {
24229109Sed
25245614Sandrewenum AllocType {
26245614Sandrew  FROM_MALLOC = 1,  // Memory block came from malloc, calloc, realloc, etc.
27245614Sandrew  FROM_NEW = 2,     // Memory block came from operator new.
28245614Sandrew  FROM_NEW_BR = 3   // Memory block came from operator new [ ]
29245614Sandrew};
30245614Sandrew
31229109Sedstruct AsanChunk;
32229109Sed
33280031Sdimstruct AllocatorOptions {
34280031Sdim  u32 quarantine_size_mb;
35314564Sdim  u32 thread_local_quarantine_size_kb;
36280031Sdim  u16 min_redzone;
37280031Sdim  u16 max_redzone;
38280031Sdim  u8 may_return_null;
39280031Sdim  u8 alloc_dealloc_mismatch;
40314564Sdim  s32 release_to_os_interval_ms;
41251034Sed
42280031Sdim  void SetFrom(const Flags *f, const CommonFlags *cf);
43280031Sdim  void CopyTo(Flags *f, CommonFlags *cf);
44280031Sdim};
45280031Sdim
46280031Sdimvoid InitializeAllocator(const AllocatorOptions &options);
47280031Sdimvoid ReInitializeAllocator(const AllocatorOptions &options);
48280031Sdimvoid GetAllocatorOptions(AllocatorOptions *options);
49280031Sdim
50245614Sandrewclass AsanChunkView {
51229109Sed public:
52245614Sandrew  explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
53314564Sdim  bool IsValid() const;        // Checks if AsanChunkView points to a valid
54314564Sdim                               // allocated or quarantined chunk.
55314564Sdim  bool IsAllocated() const;    // Checks if the memory is currently allocated.
56314564Sdim  bool IsQuarantined() const;  // Checks if the memory is currently quarantined.
57314564Sdim  uptr Beg() const;            // First byte of user memory.
58314564Sdim  uptr End() const;            // Last byte of user memory.
59314564Sdim  uptr UsedSize() const;       // Size requested by the user.
60327952Sdim  u32 UserRequestedAlignment() const;  // Originally requested alignment.
61314564Sdim  uptr AllocTid() const;
62314564Sdim  uptr FreeTid() const;
63276789Sdim  bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
64314564Sdim  u32 GetAllocStackId() const;
65314564Sdim  u32 GetFreeStackId() const;
66314564Sdim  StackTrace GetAllocStack() const;
67314564Sdim  StackTrace GetFreeStack() const;
68314564Sdim  AllocType GetAllocType() const;
69314564Sdim  bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) const {
70245614Sandrew    if (addr >= Beg() && (addr + access_size) <= End()) {
71245614Sandrew      *offset = addr - Beg();
72245614Sandrew      return true;
73245614Sandrew    }
74245614Sandrew    return false;
75245614Sandrew  }
76314564Sdim  bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) const {
77245614Sandrew    (void)access_size;
78245614Sandrew    if (addr < Beg()) {
79245614Sandrew      *offset = Beg() - addr;
80245614Sandrew      return true;
81245614Sandrew    }
82245614Sandrew    return false;
83245614Sandrew  }
84314564Sdim  bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) const {
85251034Sed    if (addr + access_size > End()) {
86251034Sed      *offset = addr - End();
87245614Sandrew      return true;
88245614Sandrew    }
89245614Sandrew    return false;
90245614Sandrew  }
91245614Sandrew
92245614Sandrew private:
93245614Sandrew  AsanChunk *const chunk_;
94245614Sandrew};
95245614Sandrew
96245614SandrewAsanChunkView FindHeapChunkByAddress(uptr address);
97314564SdimAsanChunkView FindHeapChunkByAllocBeg(uptr address);
98245614Sandrew
99245614Sandrew// List of AsanChunks with total size.
100245614Sandrewclass AsanChunkFifoList: public IntrusiveList<AsanChunk> {
101245614Sandrew public:
102229109Sed  explicit AsanChunkFifoList(LinkerInitialized) { }
103229109Sed  AsanChunkFifoList() { clear(); }
104229109Sed  void Push(AsanChunk *n);
105229109Sed  void PushList(AsanChunkFifoList *q);
106229109Sed  AsanChunk *Pop();
107238901Sandrew  uptr size() { return size_; }
108229109Sed  void clear() {
109245614Sandrew    IntrusiveList<AsanChunk>::clear();
110229109Sed    size_ = 0;
111229109Sed  }
112229109Sed private:
113238901Sandrew  uptr size_;
114229109Sed};
115229109Sed
116276789Sdimstruct AsanMapUnmapCallback {
117276789Sdim  void OnMap(uptr p, uptr size) const;
118276789Sdim  void OnUnmap(uptr p, uptr size) const;
119276789Sdim};
120276789Sdim
121276789Sdim#if SANITIZER_CAN_USE_ALLOCATOR64
122327952Sdim# if SANITIZER_FUCHSIA
123327952Sdimconst uptr kAllocatorSpace = ~(uptr)0;
124327952Sdimconst uptr kAllocatorSize  =  0x40000000000ULL;  // 4T.
125327952Sdimtypedef DefaultSizeClassMap SizeClassMap;
126327952Sdim# elif defined(__powerpc64__)
127341825Sdimconst uptr kAllocatorSpace = ~(uptr)0;
128276789Sdimconst uptr kAllocatorSize  =  0x20000000000ULL;  // 2T.
129314564Sdimtypedef DefaultSizeClassMap SizeClassMap;
130314564Sdim# elif defined(__aarch64__) && SANITIZER_ANDROID
131341825Sdim// Android needs to support 39, 42 and 48 bit VMA.
132341825Sdimconst uptr kAllocatorSpace =  ~(uptr)0;
133314564Sdimconst uptr kAllocatorSize  =  0x2000000000ULL;  // 128G.
134314564Sdimtypedef VeryCompactSizeClassMap SizeClassMap;
135296417Sdim# elif defined(__aarch64__)
136353358Sdim// AArch64/SANITIZER_CAN_USE_ALLOCATOR64 is only for 42-bit VMA
137296417Sdim// so no need to different values for different VMA.
138296417Sdimconst uptr kAllocatorSpace =  0x10000000000ULL;
139296417Sdimconst uptr kAllocatorSize  =  0x10000000000ULL;  // 3T.
140314564Sdimtypedef DefaultSizeClassMap SizeClassMap;
141353358Sdim#elif defined(__sparc__)
142353358Sdimconst uptr kAllocatorSpace = ~(uptr)0;
143353358Sdimconst uptr kAllocatorSize = 0x20000000000ULL;  // 2T.
144353358Sdimtypedef DefaultSizeClassMap SizeClassMap;
145314564Sdim# elif SANITIZER_WINDOWS
146314564Sdimconst uptr kAllocatorSpace = ~(uptr)0;
147314564Sdimconst uptr kAllocatorSize  =  0x8000000000ULL;  // 500G
148314564Sdimtypedef DefaultSizeClassMap SizeClassMap;
149276789Sdim# else
150276789Sdimconst uptr kAllocatorSpace = 0x600000000000ULL;
151276789Sdimconst uptr kAllocatorSize  =  0x40000000000ULL;  // 4T.
152314564Sdimtypedef DefaultSizeClassMap SizeClassMap;
153276789Sdim# endif
154344779Sdimtemplate <typename AddressSpaceViewTy>
155314564Sdimstruct AP64 {  // Allocator64 parameters. Deliberately using a short name.
156314564Sdim  static const uptr kSpaceBeg = kAllocatorSpace;
157314564Sdim  static const uptr kSpaceSize = kAllocatorSize;
158314564Sdim  static const uptr kMetadataSize = 0;
159314564Sdim  typedef __asan::SizeClassMap SizeClassMap;
160314564Sdim  typedef AsanMapUnmapCallback MapUnmapCallback;
161314564Sdim  static const uptr kFlags = 0;
162344779Sdim  using AddressSpaceView = AddressSpaceViewTy;
163314564Sdim};
164314564Sdim
165344779Sdimtemplate <typename AddressSpaceView>
166344779Sdimusing PrimaryAllocatorASVT = SizeClassAllocator64<AP64<AddressSpaceView>>;
167344779Sdimusing PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
168276789Sdim#else  // Fallback to SizeClassAllocator32.
169276789Sdimtypedef CompactSizeClassMap SizeClassMap;
170344779Sdimtemplate <typename AddressSpaceViewTy>
171321369Sdimstruct AP32 {
172321369Sdim  static const uptr kSpaceBeg = 0;
173321369Sdim  static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
174321369Sdim  static const uptr kMetadataSize = 16;
175321369Sdim  typedef __asan::SizeClassMap SizeClassMap;
176353358Sdim  static const uptr kRegionSizeLog = 20;
177344779Sdim  using AddressSpaceView = AddressSpaceViewTy;
178321369Sdim  typedef AsanMapUnmapCallback MapUnmapCallback;
179321369Sdim  static const uptr kFlags = 0;
180321369Sdim};
181344779Sdimtemplate <typename AddressSpaceView>
182344779Sdimusing PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView> >;
183344779Sdimusing PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
184276789Sdim#endif  // SANITIZER_CAN_USE_ALLOCATOR64
185276789Sdim
186288943Sdimstatic const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses;
187276789Sdim
188344779Sdimtemplate <typename AddressSpaceView>
189344779Sdimusing AsanAllocatorASVT =
190353358Sdim    CombinedAllocator<PrimaryAllocatorASVT<AddressSpaceView>>;
191344779Sdimusing AsanAllocator = AsanAllocatorASVT<LocalAddressSpaceView>;
192353358Sdimusing AllocatorCache = AsanAllocator::AllocatorCache;
193276789Sdim
194229109Sedstruct AsanThreadLocalMallocStorage {
195245614Sandrew  uptr quarantine_cache[16];
196280031Sdim  AllocatorCache allocator_cache;
197229109Sed  void CommitBack();
198276789Sdim private:
199276789Sdim  // These objects are allocated via mmap() and are zero-initialized.
200276789Sdim  AsanThreadLocalMallocStorage() {}
201229109Sed};
202229109Sed
203276789Sdimvoid *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
204245614Sandrew                    AllocType alloc_type);
205276789Sdimvoid asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type);
206327952Sdimvoid asan_delete(void *ptr, uptr size, uptr alignment,
207327952Sdim                 BufferedStackTrace *stack, AllocType alloc_type);
208229109Sed
209276789Sdimvoid *asan_malloc(uptr size, BufferedStackTrace *stack);
210276789Sdimvoid *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack);
211276789Sdimvoid *asan_realloc(void *p, uptr size, BufferedStackTrace *stack);
212353358Sdimvoid *asan_reallocarray(void *p, uptr nmemb, uptr size,
213353358Sdim                        BufferedStackTrace *stack);
214276789Sdimvoid *asan_valloc(uptr size, BufferedStackTrace *stack);
215276789Sdimvoid *asan_pvalloc(uptr size, BufferedStackTrace *stack);
216229109Sed
217341825Sdimvoid *asan_aligned_alloc(uptr alignment, uptr size, BufferedStackTrace *stack);
218238901Sandrewint asan_posix_memalign(void **memptr, uptr alignment, uptr size,
219276789Sdim                        BufferedStackTrace *stack);
220309124Sdimuptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp);
221229109Sed
222238901Sandrewuptr asan_mz_size(const void *ptr);
223238901Sandrewvoid asan_mz_force_lock();
224238901Sandrewvoid asan_mz_force_unlock();
225229109Sed
226245614Sandrewvoid PrintInternalAllocatorStats();
227280031Sdimvoid AsanSoftRssLimitExceededCallback(bool exceeded);
228245614Sandrew
229229109Sed}  // namespace __asan
230229109Sed#endif  // ASAN_ALLOCATOR_H
231