xref: /aosp_15_r20/external/compiler-rt/lib/lsan/lsan_allocator.cc (revision 7c3d14c8b49c529e04be81a3ce6f5cc23712e4c6)
1*7c3d14c8STreehugger Robot //=-- lsan_allocator.cc ---------------------------------------------------===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot //                     The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot //
10*7c3d14c8STreehugger Robot // This file is a part of LeakSanitizer.
11*7c3d14c8STreehugger Robot // See lsan_allocator.h for details.
12*7c3d14c8STreehugger Robot //
13*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
14*7c3d14c8STreehugger Robot 
15*7c3d14c8STreehugger Robot #include "lsan_allocator.h"
16*7c3d14c8STreehugger Robot 
17*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_allocator.h"
18*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_allocator_interface.h"
19*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_internal_defs.h"
20*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_stackdepot.h"
21*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_stacktrace.h"
22*7c3d14c8STreehugger Robot #include "lsan_common.h"
23*7c3d14c8STreehugger Robot 
24*7c3d14c8STreehugger Robot extern "C" void *memset(void *ptr, int value, uptr num);
25*7c3d14c8STreehugger Robot 
26*7c3d14c8STreehugger Robot namespace __lsan {
27*7c3d14c8STreehugger Robot 
28*7c3d14c8STreehugger Robot struct ChunkMetadata {
29*7c3d14c8STreehugger Robot   u8 allocated : 8;  // Must be first.
30*7c3d14c8STreehugger Robot   ChunkTag tag : 2;
31*7c3d14c8STreehugger Robot   uptr requested_size : 54;
32*7c3d14c8STreehugger Robot   u32 stack_trace_id;
33*7c3d14c8STreehugger Robot };
34*7c3d14c8STreehugger Robot 
35*7c3d14c8STreehugger Robot #if defined(__mips64) || defined(__aarch64__)
36*7c3d14c8STreehugger Robot static const uptr kMaxAllowedMallocSize = 4UL << 30;
37*7c3d14c8STreehugger Robot static const uptr kRegionSizeLog = 20;
38*7c3d14c8STreehugger Robot static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
39*7c3d14c8STreehugger Robot typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
40*7c3d14c8STreehugger Robot typedef CompactSizeClassMap SizeClassMap;
41*7c3d14c8STreehugger Robot typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE,
42*7c3d14c8STreehugger Robot     sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap>
43*7c3d14c8STreehugger Robot     PrimaryAllocator;
44*7c3d14c8STreehugger Robot #else
45*7c3d14c8STreehugger Robot static const uptr kMaxAllowedMallocSize = 8UL << 30;
46*7c3d14c8STreehugger Robot static const uptr kAllocatorSpace = 0x600000000000ULL;
47*7c3d14c8STreehugger Robot static const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
48*7c3d14c8STreehugger Robot typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
49*7c3d14c8STreehugger Robot         sizeof(ChunkMetadata), DefaultSizeClassMap> PrimaryAllocator;
50*7c3d14c8STreehugger Robot #endif
51*7c3d14c8STreehugger Robot typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
52*7c3d14c8STreehugger Robot typedef LargeMmapAllocator<> SecondaryAllocator;
53*7c3d14c8STreehugger Robot typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
54*7c3d14c8STreehugger Robot           SecondaryAllocator> Allocator;
55*7c3d14c8STreehugger Robot 
56*7c3d14c8STreehugger Robot static Allocator allocator;
57*7c3d14c8STreehugger Robot static THREADLOCAL AllocatorCache cache;
58*7c3d14c8STreehugger Robot 
InitializeAllocator()59*7c3d14c8STreehugger Robot void InitializeAllocator() {
60*7c3d14c8STreehugger Robot   allocator.InitLinkerInitialized(common_flags()->allocator_may_return_null);
61*7c3d14c8STreehugger Robot }
62*7c3d14c8STreehugger Robot 
AllocatorThreadFinish()63*7c3d14c8STreehugger Robot void AllocatorThreadFinish() {
64*7c3d14c8STreehugger Robot   allocator.SwallowCache(&cache);
65*7c3d14c8STreehugger Robot }
66*7c3d14c8STreehugger Robot 
Metadata(const void * p)67*7c3d14c8STreehugger Robot static ChunkMetadata *Metadata(const void *p) {
68*7c3d14c8STreehugger Robot   return reinterpret_cast<ChunkMetadata *>(allocator.GetMetaData(p));
69*7c3d14c8STreehugger Robot }
70*7c3d14c8STreehugger Robot 
RegisterAllocation(const StackTrace & stack,void * p,uptr size)71*7c3d14c8STreehugger Robot static void RegisterAllocation(const StackTrace &stack, void *p, uptr size) {
72*7c3d14c8STreehugger Robot   if (!p) return;
73*7c3d14c8STreehugger Robot   ChunkMetadata *m = Metadata(p);
74*7c3d14c8STreehugger Robot   CHECK(m);
75*7c3d14c8STreehugger Robot   m->tag = DisabledInThisThread() ? kIgnored : kDirectlyLeaked;
76*7c3d14c8STreehugger Robot   m->stack_trace_id = StackDepotPut(stack);
77*7c3d14c8STreehugger Robot   m->requested_size = size;
78*7c3d14c8STreehugger Robot   atomic_store(reinterpret_cast<atomic_uint8_t *>(m), 1, memory_order_relaxed);
79*7c3d14c8STreehugger Robot }
80*7c3d14c8STreehugger Robot 
RegisterDeallocation(void * p)81*7c3d14c8STreehugger Robot static void RegisterDeallocation(void *p) {
82*7c3d14c8STreehugger Robot   if (!p) return;
83*7c3d14c8STreehugger Robot   ChunkMetadata *m = Metadata(p);
84*7c3d14c8STreehugger Robot   CHECK(m);
85*7c3d14c8STreehugger Robot   atomic_store(reinterpret_cast<atomic_uint8_t *>(m), 0, memory_order_relaxed);
86*7c3d14c8STreehugger Robot }
87*7c3d14c8STreehugger Robot 
Allocate(const StackTrace & stack,uptr size,uptr alignment,bool cleared)88*7c3d14c8STreehugger Robot void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
89*7c3d14c8STreehugger Robot                bool cleared) {
90*7c3d14c8STreehugger Robot   if (size == 0)
91*7c3d14c8STreehugger Robot     size = 1;
92*7c3d14c8STreehugger Robot   if (size > kMaxAllowedMallocSize) {
93*7c3d14c8STreehugger Robot     Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size);
94*7c3d14c8STreehugger Robot     return nullptr;
95*7c3d14c8STreehugger Robot   }
96*7c3d14c8STreehugger Robot   void *p = allocator.Allocate(&cache, size, alignment, false);
97*7c3d14c8STreehugger Robot   // Do not rely on the allocator to clear the memory (it's slow).
98*7c3d14c8STreehugger Robot   if (cleared && allocator.FromPrimary(p))
99*7c3d14c8STreehugger Robot     memset(p, 0, size);
100*7c3d14c8STreehugger Robot   RegisterAllocation(stack, p, size);
101*7c3d14c8STreehugger Robot   if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(p, size);
102*7c3d14c8STreehugger Robot   RunMallocHooks(p, size);
103*7c3d14c8STreehugger Robot   return p;
104*7c3d14c8STreehugger Robot }
105*7c3d14c8STreehugger Robot 
Deallocate(void * p)106*7c3d14c8STreehugger Robot void Deallocate(void *p) {
107*7c3d14c8STreehugger Robot   if (&__sanitizer_free_hook) __sanitizer_free_hook(p);
108*7c3d14c8STreehugger Robot   RunFreeHooks(p);
109*7c3d14c8STreehugger Robot   RegisterDeallocation(p);
110*7c3d14c8STreehugger Robot   allocator.Deallocate(&cache, p);
111*7c3d14c8STreehugger Robot }
112*7c3d14c8STreehugger Robot 
Reallocate(const StackTrace & stack,void * p,uptr new_size,uptr alignment)113*7c3d14c8STreehugger Robot void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
114*7c3d14c8STreehugger Robot                  uptr alignment) {
115*7c3d14c8STreehugger Robot   RegisterDeallocation(p);
116*7c3d14c8STreehugger Robot   if (new_size > kMaxAllowedMallocSize) {
117*7c3d14c8STreehugger Robot     Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size);
118*7c3d14c8STreehugger Robot     allocator.Deallocate(&cache, p);
119*7c3d14c8STreehugger Robot     return nullptr;
120*7c3d14c8STreehugger Robot   }
121*7c3d14c8STreehugger Robot   p = allocator.Reallocate(&cache, p, new_size, alignment);
122*7c3d14c8STreehugger Robot   RegisterAllocation(stack, p, new_size);
123*7c3d14c8STreehugger Robot   return p;
124*7c3d14c8STreehugger Robot }
125*7c3d14c8STreehugger Robot 
GetAllocatorCacheRange(uptr * begin,uptr * end)126*7c3d14c8STreehugger Robot void GetAllocatorCacheRange(uptr *begin, uptr *end) {
127*7c3d14c8STreehugger Robot   *begin = (uptr)&cache;
128*7c3d14c8STreehugger Robot   *end = *begin + sizeof(cache);
129*7c3d14c8STreehugger Robot }
130*7c3d14c8STreehugger Robot 
GetMallocUsableSize(const void * p)131*7c3d14c8STreehugger Robot uptr GetMallocUsableSize(const void *p) {
132*7c3d14c8STreehugger Robot   ChunkMetadata *m = Metadata(p);
133*7c3d14c8STreehugger Robot   if (!m) return 0;
134*7c3d14c8STreehugger Robot   return m->requested_size;
135*7c3d14c8STreehugger Robot }
136*7c3d14c8STreehugger Robot 
137*7c3d14c8STreehugger Robot ///// Interface to the common LSan module. /////
138*7c3d14c8STreehugger Robot 
LockAllocator()139*7c3d14c8STreehugger Robot void LockAllocator() {
140*7c3d14c8STreehugger Robot   allocator.ForceLock();
141*7c3d14c8STreehugger Robot }
142*7c3d14c8STreehugger Robot 
UnlockAllocator()143*7c3d14c8STreehugger Robot void UnlockAllocator() {
144*7c3d14c8STreehugger Robot   allocator.ForceUnlock();
145*7c3d14c8STreehugger Robot }
146*7c3d14c8STreehugger Robot 
GetAllocatorGlobalRange(uptr * begin,uptr * end)147*7c3d14c8STreehugger Robot void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
148*7c3d14c8STreehugger Robot   *begin = (uptr)&allocator;
149*7c3d14c8STreehugger Robot   *end = *begin + sizeof(allocator);
150*7c3d14c8STreehugger Robot }
151*7c3d14c8STreehugger Robot 
PointsIntoChunk(void * p)152*7c3d14c8STreehugger Robot uptr PointsIntoChunk(void* p) {
153*7c3d14c8STreehugger Robot   uptr addr = reinterpret_cast<uptr>(p);
154*7c3d14c8STreehugger Robot   uptr chunk = reinterpret_cast<uptr>(allocator.GetBlockBeginFastLocked(p));
155*7c3d14c8STreehugger Robot   if (!chunk) return 0;
156*7c3d14c8STreehugger Robot   // LargeMmapAllocator considers pointers to the meta-region of a chunk to be
157*7c3d14c8STreehugger Robot   // valid, but we don't want that.
158*7c3d14c8STreehugger Robot   if (addr < chunk) return 0;
159*7c3d14c8STreehugger Robot   ChunkMetadata *m = Metadata(reinterpret_cast<void *>(chunk));
160*7c3d14c8STreehugger Robot   CHECK(m);
161*7c3d14c8STreehugger Robot   if (!m->allocated)
162*7c3d14c8STreehugger Robot     return 0;
163*7c3d14c8STreehugger Robot   if (addr < chunk + m->requested_size)
164*7c3d14c8STreehugger Robot     return chunk;
165*7c3d14c8STreehugger Robot   if (IsSpecialCaseOfOperatorNew0(chunk, m->requested_size, addr))
166*7c3d14c8STreehugger Robot     return chunk;
167*7c3d14c8STreehugger Robot   return 0;
168*7c3d14c8STreehugger Robot }
169*7c3d14c8STreehugger Robot 
GetUserBegin(uptr chunk)170*7c3d14c8STreehugger Robot uptr GetUserBegin(uptr chunk) {
171*7c3d14c8STreehugger Robot   return chunk;
172*7c3d14c8STreehugger Robot }
173*7c3d14c8STreehugger Robot 
LsanMetadata(uptr chunk)174*7c3d14c8STreehugger Robot LsanMetadata::LsanMetadata(uptr chunk) {
175*7c3d14c8STreehugger Robot   metadata_ = Metadata(reinterpret_cast<void *>(chunk));
176*7c3d14c8STreehugger Robot   CHECK(metadata_);
177*7c3d14c8STreehugger Robot }
178*7c3d14c8STreehugger Robot 
allocated() const179*7c3d14c8STreehugger Robot bool LsanMetadata::allocated() const {
180*7c3d14c8STreehugger Robot   return reinterpret_cast<ChunkMetadata *>(metadata_)->allocated;
181*7c3d14c8STreehugger Robot }
182*7c3d14c8STreehugger Robot 
tag() const183*7c3d14c8STreehugger Robot ChunkTag LsanMetadata::tag() const {
184*7c3d14c8STreehugger Robot   return reinterpret_cast<ChunkMetadata *>(metadata_)->tag;
185*7c3d14c8STreehugger Robot }
186*7c3d14c8STreehugger Robot 
set_tag(ChunkTag value)187*7c3d14c8STreehugger Robot void LsanMetadata::set_tag(ChunkTag value) {
188*7c3d14c8STreehugger Robot   reinterpret_cast<ChunkMetadata *>(metadata_)->tag = value;
189*7c3d14c8STreehugger Robot }
190*7c3d14c8STreehugger Robot 
requested_size() const191*7c3d14c8STreehugger Robot uptr LsanMetadata::requested_size() const {
192*7c3d14c8STreehugger Robot   return reinterpret_cast<ChunkMetadata *>(metadata_)->requested_size;
193*7c3d14c8STreehugger Robot }
194*7c3d14c8STreehugger Robot 
stack_trace_id() const195*7c3d14c8STreehugger Robot u32 LsanMetadata::stack_trace_id() const {
196*7c3d14c8STreehugger Robot   return reinterpret_cast<ChunkMetadata *>(metadata_)->stack_trace_id;
197*7c3d14c8STreehugger Robot }
198*7c3d14c8STreehugger Robot 
ForEachChunk(ForEachChunkCallback callback,void * arg)199*7c3d14c8STreehugger Robot void ForEachChunk(ForEachChunkCallback callback, void *arg) {
200*7c3d14c8STreehugger Robot   allocator.ForEachChunk(callback, arg);
201*7c3d14c8STreehugger Robot }
202*7c3d14c8STreehugger Robot 
IgnoreObjectLocked(const void * p)203*7c3d14c8STreehugger Robot IgnoreObjectResult IgnoreObjectLocked(const void *p) {
204*7c3d14c8STreehugger Robot   void *chunk = allocator.GetBlockBegin(p);
205*7c3d14c8STreehugger Robot   if (!chunk || p < chunk) return kIgnoreObjectInvalid;
206*7c3d14c8STreehugger Robot   ChunkMetadata *m = Metadata(chunk);
207*7c3d14c8STreehugger Robot   CHECK(m);
208*7c3d14c8STreehugger Robot   if (m->allocated && (uptr)p < (uptr)chunk + m->requested_size) {
209*7c3d14c8STreehugger Robot     if (m->tag == kIgnored)
210*7c3d14c8STreehugger Robot       return kIgnoreObjectAlreadyIgnored;
211*7c3d14c8STreehugger Robot     m->tag = kIgnored;
212*7c3d14c8STreehugger Robot     return kIgnoreObjectSuccess;
213*7c3d14c8STreehugger Robot   } else {
214*7c3d14c8STreehugger Robot     return kIgnoreObjectInvalid;
215*7c3d14c8STreehugger Robot   }
216*7c3d14c8STreehugger Robot }
217*7c3d14c8STreehugger Robot } // namespace __lsan
218*7c3d14c8STreehugger Robot 
219*7c3d14c8STreehugger Robot using namespace __lsan;
220*7c3d14c8STreehugger Robot 
221*7c3d14c8STreehugger Robot extern "C" {
222*7c3d14c8STreehugger Robot SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_get_current_allocated_bytes()223*7c3d14c8STreehugger Robot uptr __sanitizer_get_current_allocated_bytes() {
224*7c3d14c8STreehugger Robot   uptr stats[AllocatorStatCount];
225*7c3d14c8STreehugger Robot   allocator.GetStats(stats);
226*7c3d14c8STreehugger Robot   return stats[AllocatorStatAllocated];
227*7c3d14c8STreehugger Robot }
228*7c3d14c8STreehugger Robot 
229*7c3d14c8STreehugger Robot SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_get_heap_size()230*7c3d14c8STreehugger Robot uptr __sanitizer_get_heap_size() {
231*7c3d14c8STreehugger Robot   uptr stats[AllocatorStatCount];
232*7c3d14c8STreehugger Robot   allocator.GetStats(stats);
233*7c3d14c8STreehugger Robot   return stats[AllocatorStatMapped];
234*7c3d14c8STreehugger Robot }
235*7c3d14c8STreehugger Robot 
236*7c3d14c8STreehugger Robot SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_get_free_bytes()237*7c3d14c8STreehugger Robot uptr __sanitizer_get_free_bytes() { return 0; }
238*7c3d14c8STreehugger Robot 
239*7c3d14c8STreehugger Robot SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_get_unmapped_bytes()240*7c3d14c8STreehugger Robot uptr __sanitizer_get_unmapped_bytes() { return 0; }
241*7c3d14c8STreehugger Robot 
242*7c3d14c8STreehugger Robot SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_get_estimated_allocated_size(uptr size)243*7c3d14c8STreehugger Robot uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
244*7c3d14c8STreehugger Robot 
245*7c3d14c8STreehugger Robot SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_get_ownership(const void * p)246*7c3d14c8STreehugger Robot int __sanitizer_get_ownership(const void *p) { return Metadata(p) != nullptr; }
247*7c3d14c8STreehugger Robot 
248*7c3d14c8STreehugger Robot SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_get_allocated_size(const void * p)249*7c3d14c8STreehugger Robot uptr __sanitizer_get_allocated_size(const void *p) {
250*7c3d14c8STreehugger Robot   return GetMallocUsableSize(p);
251*7c3d14c8STreehugger Robot }
252*7c3d14c8STreehugger Robot } // extern "C"
253