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