1 //=-- lsan_allocator.cc ---------------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is a part of LeakSanitizer.
11 // See lsan_allocator.h for details.
13 //===----------------------------------------------------------------------===//
15 #include "lsan_allocator.h"
17 #include "sanitizer_common/sanitizer_allocator.h"
18 #include "sanitizer_common/sanitizer_allocator_interface.h"
19 #include "sanitizer_common/sanitizer_internal_defs.h"
20 #include "sanitizer_common/sanitizer_stackdepot.h"
21 #include "sanitizer_common/sanitizer_stacktrace.h"
22 #include "lsan_common.h"
24 extern "C" void *memset(void *ptr, int value, uptr num);
28 static const uptr kMaxAllowedMallocSize = 8UL << 30;
29 static const uptr kAllocatorSpace = 0x600000000000ULL;
30 static const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
32 struct ChunkMetadata {
33 bool allocated : 8; // Must be first.
35 uptr requested_size : 54;
39 typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
40 sizeof(ChunkMetadata), DefaultSizeClassMap> PrimaryAllocator;
41 typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
42 typedef LargeMmapAllocator<> SecondaryAllocator;
43 typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
44 SecondaryAllocator> Allocator;
46 static Allocator allocator;
47 static THREADLOCAL AllocatorCache cache;
49 void InitializeAllocator() {
53 void AllocatorThreadFinish() {
54 allocator.SwallowCache(&cache);
57 static ChunkMetadata *Metadata(const void *p) {
58 return reinterpret_cast<ChunkMetadata *>(allocator.GetMetaData(p));
61 static void RegisterAllocation(const StackTrace &stack, void *p, uptr size) {
63 ChunkMetadata *m = Metadata(p);
65 m->tag = DisabledInThisThread() ? kIgnored : kDirectlyLeaked;
66 m->stack_trace_id = StackDepotPut(stack);
67 m->requested_size = size;
68 atomic_store(reinterpret_cast<atomic_uint8_t *>(m), 1, memory_order_relaxed);
71 static void RegisterDeallocation(void *p) {
73 ChunkMetadata *m = Metadata(p);
75 atomic_store(reinterpret_cast<atomic_uint8_t *>(m), 0, memory_order_relaxed);
78 void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
82 if (size > kMaxAllowedMallocSize) {
83 Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size);
86 void *p = allocator.Allocate(&cache, size, alignment, false);
87 // Do not rely on the allocator to clear the memory (it's slow).
88 if (cleared && allocator.FromPrimary(p))
90 RegisterAllocation(stack, p, size);
91 if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(p, size);
95 void Deallocate(void *p) {
96 if (&__sanitizer_free_hook) __sanitizer_free_hook(p);
97 RegisterDeallocation(p);
98 allocator.Deallocate(&cache, p);
101 void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
103 RegisterDeallocation(p);
104 if (new_size > kMaxAllowedMallocSize) {
105 Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size);
106 allocator.Deallocate(&cache, p);
109 p = allocator.Reallocate(&cache, p, new_size, alignment);
110 RegisterAllocation(stack, p, new_size);
114 void GetAllocatorCacheRange(uptr *begin, uptr *end) {
115 *begin = (uptr)&cache;
116 *end = *begin + sizeof(cache);
119 uptr GetMallocUsableSize(const void *p) {
120 ChunkMetadata *m = Metadata(p);
122 return m->requested_size;
125 ///// Interface to the common LSan module. /////
127 void LockAllocator() {
128 allocator.ForceLock();
131 void UnlockAllocator() {
132 allocator.ForceUnlock();
135 void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
136 *begin = (uptr)&allocator;
137 *end = *begin + sizeof(allocator);
140 uptr PointsIntoChunk(void* p) {
141 uptr addr = reinterpret_cast<uptr>(p);
142 uptr chunk = reinterpret_cast<uptr>(allocator.GetBlockBeginFastLocked(p));
143 if (!chunk) return 0;
144 // LargeMmapAllocator considers pointers to the meta-region of a chunk to be
145 // valid, but we don't want that.
146 if (addr < chunk) return 0;
147 ChunkMetadata *m = Metadata(reinterpret_cast<void *>(chunk));
151 if (addr < chunk + m->requested_size)
153 if (IsSpecialCaseOfOperatorNew0(chunk, m->requested_size, addr))
158 uptr GetUserBegin(uptr chunk) {
162 LsanMetadata::LsanMetadata(uptr chunk) {
163 metadata_ = Metadata(reinterpret_cast<void *>(chunk));
167 bool LsanMetadata::allocated() const {
168 return reinterpret_cast<ChunkMetadata *>(metadata_)->allocated;
171 ChunkTag LsanMetadata::tag() const {
172 return reinterpret_cast<ChunkMetadata *>(metadata_)->tag;
175 void LsanMetadata::set_tag(ChunkTag value) {
176 reinterpret_cast<ChunkMetadata *>(metadata_)->tag = value;
179 uptr LsanMetadata::requested_size() const {
180 return reinterpret_cast<ChunkMetadata *>(metadata_)->requested_size;
183 u32 LsanMetadata::stack_trace_id() const {
184 return reinterpret_cast<ChunkMetadata *>(metadata_)->stack_trace_id;
187 void ForEachChunk(ForEachChunkCallback callback, void *arg) {
188 allocator.ForEachChunk(callback, arg);
191 IgnoreObjectResult IgnoreObjectLocked(const void *p) {
192 void *chunk = allocator.GetBlockBegin(p);
193 if (!chunk || p < chunk) return kIgnoreObjectInvalid;
194 ChunkMetadata *m = Metadata(chunk);
196 if (m->allocated && (uptr)p < (uptr)chunk + m->requested_size) {
197 if (m->tag == kIgnored)
198 return kIgnoreObjectAlreadyIgnored;
200 return kIgnoreObjectSuccess;
202 return kIgnoreObjectInvalid;
205 } // namespace __lsan
207 using namespace __lsan;
210 SANITIZER_INTERFACE_ATTRIBUTE
211 uptr __sanitizer_get_current_allocated_bytes() {
212 uptr stats[AllocatorStatCount];
213 allocator.GetStats(stats);
214 return stats[AllocatorStatAllocated];
217 SANITIZER_INTERFACE_ATTRIBUTE
218 uptr __sanitizer_get_heap_size() {
219 uptr stats[AllocatorStatCount];
220 allocator.GetStats(stats);
221 return stats[AllocatorStatMapped];
224 SANITIZER_INTERFACE_ATTRIBUTE
225 uptr __sanitizer_get_free_bytes() { return 0; }
227 SANITIZER_INTERFACE_ATTRIBUTE
228 uptr __sanitizer_get_unmapped_bytes() { return 0; }
230 SANITIZER_INTERFACE_ATTRIBUTE
231 uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
233 SANITIZER_INTERFACE_ATTRIBUTE
234 int __sanitizer_get_ownership(const void *p) { return Metadata(p) != 0; }
236 SANITIZER_INTERFACE_ATTRIBUTE
237 uptr __sanitizer_get_allocated_size(const void *p) {
238 return GetMallocUsableSize(p);