1 //=-- lsan_allocator.cc ---------------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of LeakSanitizer.
9 // See lsan_allocator.h for details.
11 //===----------------------------------------------------------------------===//
13 #include "lsan_allocator.h"
15 #include "sanitizer_common/sanitizer_allocator.h"
16 #include "sanitizer_common/sanitizer_allocator_interface.h"
17 #include "sanitizer_common/sanitizer_internal_defs.h"
18 #include "sanitizer_common/sanitizer_stackdepot.h"
19 #include "sanitizer_common/sanitizer_stacktrace.h"
20 #include "lsan_common.h"
22 extern "C" void *memset(void *ptr
, int value
, uptr num
);
26 struct ChunkMetadata
{
27 u8 allocated
: 8; // Must be first.
29 uptr requested_size
: 54;
33 #if defined(__mips64) || defined(__aarch64__)
34 static const uptr kMaxAllowedMallocSize
= 4UL << 30;
35 static const uptr kRegionSizeLog
= 20;
36 static const uptr kNumRegions
= SANITIZER_MMAP_RANGE_SIZE
>> kRegionSizeLog
;
37 typedef TwoLevelByteMap
<(kNumRegions
>> 12), 1 << 12> ByteMap
;
38 typedef CompactSizeClassMap SizeClassMap
;
39 typedef SizeClassAllocator32
<0, SANITIZER_MMAP_RANGE_SIZE
,
40 sizeof(ChunkMetadata
), SizeClassMap
, kRegionSizeLog
, ByteMap
>
43 static const uptr kMaxAllowedMallocSize
= 8UL << 30;
44 static const uptr kAllocatorSpace
= 0x600000000000ULL
;
45 static const uptr kAllocatorSize
= 0x40000000000ULL
; // 4T.
46 typedef SizeClassAllocator64
<kAllocatorSpace
, kAllocatorSize
,
47 sizeof(ChunkMetadata
), DefaultSizeClassMap
> PrimaryAllocator
;
49 typedef SizeClassAllocatorLocalCache
<PrimaryAllocator
> AllocatorCache
;
50 typedef LargeMmapAllocator
<> SecondaryAllocator
;
51 typedef CombinedAllocator
<PrimaryAllocator
, AllocatorCache
,
52 SecondaryAllocator
> Allocator
;
54 static Allocator allocator
;
55 static THREADLOCAL AllocatorCache cache
;
57 void InitializeAllocator() {
58 allocator
.InitLinkerInitialized(common_flags()->allocator_may_return_null
);
61 void AllocatorThreadFinish() {
62 allocator
.SwallowCache(&cache
);
65 static ChunkMetadata
*Metadata(const void *p
) {
66 return reinterpret_cast<ChunkMetadata
*>(allocator
.GetMetaData(p
));
69 static void RegisterAllocation(const StackTrace
&stack
, void *p
, uptr size
) {
71 ChunkMetadata
*m
= Metadata(p
);
73 m
->tag
= DisabledInThisThread() ? kIgnored
: kDirectlyLeaked
;
74 m
->stack_trace_id
= StackDepotPut(stack
);
75 m
->requested_size
= size
;
76 atomic_store(reinterpret_cast<atomic_uint8_t
*>(m
), 1, memory_order_relaxed
);
79 static void RegisterDeallocation(void *p
) {
81 ChunkMetadata
*m
= Metadata(p
);
83 atomic_store(reinterpret_cast<atomic_uint8_t
*>(m
), 0, memory_order_relaxed
);
86 void *Allocate(const StackTrace
&stack
, uptr size
, uptr alignment
,
90 if (size
> kMaxAllowedMallocSize
) {
91 Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size
);
94 void *p
= allocator
.Allocate(&cache
, size
, alignment
, false);
95 // Do not rely on the allocator to clear the memory (it's slow).
96 if (cleared
&& allocator
.FromPrimary(p
))
98 RegisterAllocation(stack
, p
, size
);
99 if (&__sanitizer_malloc_hook
) __sanitizer_malloc_hook(p
, size
);
103 void Deallocate(void *p
) {
104 if (&__sanitizer_free_hook
) __sanitizer_free_hook(p
);
105 RegisterDeallocation(p
);
106 allocator
.Deallocate(&cache
, p
);
109 void *Reallocate(const StackTrace
&stack
, void *p
, uptr new_size
,
111 RegisterDeallocation(p
);
112 if (new_size
> kMaxAllowedMallocSize
) {
113 Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size
);
114 allocator
.Deallocate(&cache
, p
);
117 p
= allocator
.Reallocate(&cache
, p
, new_size
, alignment
);
118 RegisterAllocation(stack
, p
, new_size
);
122 void GetAllocatorCacheRange(uptr
*begin
, uptr
*end
) {
123 *begin
= (uptr
)&cache
;
124 *end
= *begin
+ sizeof(cache
);
127 uptr
GetMallocUsableSize(const void *p
) {
128 ChunkMetadata
*m
= Metadata(p
);
130 return m
->requested_size
;
133 ///// Interface to the common LSan module. /////
135 void LockAllocator() {
136 allocator
.ForceLock();
139 void UnlockAllocator() {
140 allocator
.ForceUnlock();
143 void GetAllocatorGlobalRange(uptr
*begin
, uptr
*end
) {
144 *begin
= (uptr
)&allocator
;
145 *end
= *begin
+ sizeof(allocator
);
148 uptr
PointsIntoChunk(void* p
) {
149 uptr addr
= reinterpret_cast<uptr
>(p
);
150 uptr chunk
= reinterpret_cast<uptr
>(allocator
.GetBlockBeginFastLocked(p
));
151 if (!chunk
) return 0;
152 // LargeMmapAllocator considers pointers to the meta-region of a chunk to be
153 // valid, but we don't want that.
154 if (addr
< chunk
) return 0;
155 ChunkMetadata
*m
= Metadata(reinterpret_cast<void *>(chunk
));
159 if (addr
< chunk
+ m
->requested_size
)
161 if (IsSpecialCaseOfOperatorNew0(chunk
, m
->requested_size
, addr
))
166 uptr
GetUserBegin(uptr chunk
) {
170 LsanMetadata::LsanMetadata(uptr chunk
) {
171 metadata_
= Metadata(reinterpret_cast<void *>(chunk
));
175 bool LsanMetadata::allocated() const {
176 return reinterpret_cast<ChunkMetadata
*>(metadata_
)->allocated
;
179 ChunkTag
LsanMetadata::tag() const {
180 return reinterpret_cast<ChunkMetadata
*>(metadata_
)->tag
;
183 void LsanMetadata::set_tag(ChunkTag value
) {
184 reinterpret_cast<ChunkMetadata
*>(metadata_
)->tag
= value
;
187 uptr
LsanMetadata::requested_size() const {
188 return reinterpret_cast<ChunkMetadata
*>(metadata_
)->requested_size
;
191 u32
LsanMetadata::stack_trace_id() const {
192 return reinterpret_cast<ChunkMetadata
*>(metadata_
)->stack_trace_id
;
195 void ForEachChunk(ForEachChunkCallback callback
, void *arg
) {
196 allocator
.ForEachChunk(callback
, arg
);
199 IgnoreObjectResult
IgnoreObjectLocked(const void *p
) {
200 void *chunk
= allocator
.GetBlockBegin(p
);
201 if (!chunk
|| p
< chunk
) return kIgnoreObjectInvalid
;
202 ChunkMetadata
*m
= Metadata(chunk
);
204 if (m
->allocated
&& (uptr
)p
< (uptr
)chunk
+ m
->requested_size
) {
205 if (m
->tag
== kIgnored
)
206 return kIgnoreObjectAlreadyIgnored
;
208 return kIgnoreObjectSuccess
;
210 return kIgnoreObjectInvalid
;
213 } // namespace __lsan
215 using namespace __lsan
;
218 SANITIZER_INTERFACE_ATTRIBUTE
219 uptr
__sanitizer_get_current_allocated_bytes() {
220 uptr stats
[AllocatorStatCount
];
221 allocator
.GetStats(stats
);
222 return stats
[AllocatorStatAllocated
];
225 SANITIZER_INTERFACE_ATTRIBUTE
226 uptr
__sanitizer_get_heap_size() {
227 uptr stats
[AllocatorStatCount
];
228 allocator
.GetStats(stats
);
229 return stats
[AllocatorStatMapped
];
232 SANITIZER_INTERFACE_ATTRIBUTE
233 uptr
__sanitizer_get_free_bytes() { return 0; }
235 SANITIZER_INTERFACE_ATTRIBUTE
236 uptr
__sanitizer_get_unmapped_bytes() { return 0; }
238 SANITIZER_INTERFACE_ATTRIBUTE
239 uptr
__sanitizer_get_estimated_allocated_size(uptr size
) { return size
; }
241 SANITIZER_INTERFACE_ATTRIBUTE
242 int __sanitizer_get_ownership(const void *p
) { return Metadata(p
) != nullptr; }
244 SANITIZER_INTERFACE_ATTRIBUTE
245 uptr
__sanitizer_get_allocated_size(const void *p
) {
246 return GetMallocUsableSize(p
);