asan_allocator2.cc revision b5433dd977c6b528b7e0d83fa1fc45d6503a1226
1//===-- asan_allocator2.cc ------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of AddressSanitizer, an address sanity checker.
11//
12// Implementation of ASan's memory allocator, 2-nd version.
13// This variant uses the allocator from sanitizer_common, i.e. the one shared
14// with ThreadSanitizer and MemorySanitizer.
15//
16//===----------------------------------------------------------------------===//
17#include "asan_allocator.h"
18
19#include "asan_mapping.h"
20#include "asan_poisoning.h"
21#include "asan_report.h"
22#include "asan_thread.h"
23#include "sanitizer_common/sanitizer_allocator.h"
24#include "sanitizer_common/sanitizer_flags.h"
25#include "sanitizer_common/sanitizer_internal_defs.h"
26#include "sanitizer_common/sanitizer_list.h"
27#include "sanitizer_common/sanitizer_stackdepot.h"
28#include "sanitizer_common/sanitizer_quarantine.h"
29#include "lsan/lsan_common.h"
30
31namespace __asan {
32
33struct AsanMapUnmapCallback {
34  void OnMap(uptr p, uptr size) const {
35    PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic);
36    // Statistics.
37    AsanStats &thread_stats = GetCurrentThreadStats();
38    thread_stats.mmaps++;
39    thread_stats.mmaped += size;
40  }
41  void OnUnmap(uptr p, uptr size) const {
42    PoisonShadow(p, size, 0);
43    // We are about to unmap a chunk of user memory.
44    // Mark the corresponding shadow memory as not needed.
45    // Since asan's mapping is compacting, the shadow chunk may be
46    // not page-aligned, so we only flush the page-aligned portion.
47    uptr page_size = GetPageSizeCached();
48    uptr shadow_beg = RoundUpTo(MemToShadow(p), page_size);
49    uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size);
50    FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
51    // Statistics.
52    AsanStats &thread_stats = GetCurrentThreadStats();
53    thread_stats.munmaps++;
54    thread_stats.munmaped += size;
55  }
56};
57
58#if SANITIZER_WORDSIZE == 64
59#if defined(__powerpc64__)
60const uptr kAllocatorSpace =  0xa0000000000ULL;
61const uptr kAllocatorSize  =  0x20000000000ULL;  // 2T.
62#else
63const uptr kAllocatorSpace = 0x600000000000ULL;
64const uptr kAllocatorSize  =  0x40000000000ULL;  // 4T.
65#endif
66typedef DefaultSizeClassMap SizeClassMap;
67typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
68    SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
69#elif SANITIZER_WORDSIZE == 32
70static const u64 kAddressSpaceSize = 1ULL << 32;
71typedef CompactSizeClassMap SizeClassMap;
72static const uptr kRegionSizeLog = 20;
73static const uptr kFlatByteMapSize = kAddressSpaceSize >> kRegionSizeLog;
74typedef SizeClassAllocator32<0, kAddressSpaceSize, 16,
75  SizeClassMap, kRegionSizeLog,
76  FlatByteMap<kFlatByteMapSize>,
77  AsanMapUnmapCallback> PrimaryAllocator;
78#endif
79
80typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
81typedef LargeMmapAllocator<AsanMapUnmapCallback> SecondaryAllocator;
82typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
83    SecondaryAllocator> Allocator;
84
85// We can not use THREADLOCAL because it is not supported on some of the
86// platforms we care about (OSX 10.6, Android).
87// static THREADLOCAL AllocatorCache cache;
88AllocatorCache *GetAllocatorCache(AsanThreadLocalMallocStorage *ms) {
89  CHECK(ms);
90  CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator2_cache));
91  return reinterpret_cast<AllocatorCache *>(ms->allocator2_cache);
92}
93
94static Allocator allocator;
95
96static const uptr kMaxAllowedMallocSize =
97  FIRST_32_SECOND_64(3UL << 30, 8UL << 30);
98
99static const uptr kMaxThreadLocalQuarantine =
100  FIRST_32_SECOND_64(1 << 18, 1 << 20);
101
102// Every chunk of memory allocated by this allocator can be in one of 3 states:
103// CHUNK_AVAILABLE: the chunk is in the free list and ready to be allocated.
104// CHUNK_ALLOCATED: the chunk is allocated and not yet freed.
105// CHUNK_QUARANTINE: the chunk was freed and put into quarantine zone.
106enum {
107  CHUNK_AVAILABLE  = 0,  // 0 is the default value even if we didn't set it.
108  CHUNK_ALLOCATED  = 2,
109  CHUNK_QUARANTINE = 3
110};
111
112// Valid redzone sizes are 16, 32, 64, ... 2048, so we encode them in 3 bits.
113// We use adaptive redzones: for larger allocation larger redzones are used.
114static u32 RZLog2Size(u32 rz_log) {
115  CHECK_LT(rz_log, 8);
116  return 16 << rz_log;
117}
118
119static u32 RZSize2Log(u32 rz_size) {
120  CHECK_GE(rz_size, 16);
121  CHECK_LE(rz_size, 2048);
122  CHECK(IsPowerOfTwo(rz_size));
123  u32 res = Log2(rz_size) - 4;
124  CHECK_EQ(rz_size, RZLog2Size(res));
125  return res;
126}
127
128static uptr ComputeRZLog(uptr user_requested_size) {
129  u32 rz_log =
130    user_requested_size <= 64        - 16   ? 0 :
131    user_requested_size <= 128       - 32   ? 1 :
132    user_requested_size <= 512       - 64   ? 2 :
133    user_requested_size <= 4096      - 128  ? 3 :
134    user_requested_size <= (1 << 14) - 256  ? 4 :
135    user_requested_size <= (1 << 15) - 512  ? 5 :
136    user_requested_size <= (1 << 16) - 1024 ? 6 : 7;
137  return Max(rz_log, RZSize2Log(flags()->redzone));
138}
139
140// The memory chunk allocated from the underlying allocator looks like this:
141// L L L L L L H H U U U U U U R R
142//   L -- left redzone words (0 or more bytes)
143//   H -- ChunkHeader (16 bytes), which is also a part of the left redzone.
144//   U -- user memory.
145//   R -- right redzone (0 or more bytes)
146// ChunkBase consists of ChunkHeader and other bytes that overlap with user
147// memory.
148
149// If a memory chunk is allocated by memalign and we had to increase the
150// allocation size to achieve the proper alignment, then we store this magic
151// value in the first uptr word of the memory block and store the address of
152// ChunkBase in the next uptr.
153// M B ? ? ? L L L L L L  H H U U U U U U
154//   M -- magic value kMemalignMagic
155//   B -- address of ChunkHeader pointing to the first 'H'
156static const uptr kMemalignMagic = 0xCC6E96B9;
157
158struct ChunkHeader {
159  // 1-st 8 bytes.
160  u32 chunk_state       : 8;  // Must be first.
161  u32 alloc_tid         : 24;
162
163  u32 free_tid          : 24;
164  u32 from_memalign     : 1;
165  u32 alloc_type        : 2;
166  u32 rz_log            : 3;
167  u32 lsan_tag          : 2;
168  // 2-nd 8 bytes
169  // This field is used for small sizes. For large sizes it is equal to
170  // SizeClassMap::kMaxSize and the actual size is stored in the
171  // SecondaryAllocator's metadata.
172  u32 user_requested_size;
173  u32 alloc_context_id;
174};
175
176struct ChunkBase : ChunkHeader {
177  // Header2, intersects with user memory.
178  u32 free_context_id;
179};
180
181static const uptr kChunkHeaderSize = sizeof(ChunkHeader);
182static const uptr kChunkHeader2Size = sizeof(ChunkBase) - kChunkHeaderSize;
183COMPILER_CHECK(kChunkHeaderSize == 16);
184COMPILER_CHECK(kChunkHeader2Size <= 16);
185
186struct AsanChunk: ChunkBase {
187  uptr Beg() { return reinterpret_cast<uptr>(this) + kChunkHeaderSize; }
188  uptr UsedSize() {
189    if (user_requested_size != SizeClassMap::kMaxSize)
190      return user_requested_size;
191    return *reinterpret_cast<uptr *>(allocator.GetMetaData(AllocBeg()));
192  }
193  void *AllocBeg() {
194    if (from_memalign)
195      return allocator.GetBlockBegin(reinterpret_cast<void *>(this));
196    return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
197  }
198  // If we don't use stack depot, we store the alloc/free stack traces
199  // in the chunk itself.
200  u32 *AllocStackBeg() {
201    return (u32*)(Beg() - RZLog2Size(rz_log));
202  }
203  uptr AllocStackSize() {
204    CHECK_LE(RZLog2Size(rz_log), kChunkHeaderSize);
205    return (RZLog2Size(rz_log) - kChunkHeaderSize) / sizeof(u32);
206  }
207  u32 *FreeStackBeg() {
208    return (u32*)(Beg() + kChunkHeader2Size);
209  }
210  uptr FreeStackSize() {
211    if (user_requested_size < kChunkHeader2Size) return 0;
212    uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY);
213    return (available - kChunkHeader2Size) / sizeof(u32);
214  }
215  bool AddrIsInside(uptr addr) {
216    return (addr >= Beg()) && (addr < Beg() + UsedSize());
217  }
218};
219
220uptr AsanChunkView::Beg() { return chunk_->Beg(); }
221uptr AsanChunkView::End() { return Beg() + UsedSize(); }
222uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); }
223uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; }
224uptr AsanChunkView::FreeTid() { return chunk_->free_tid; }
225
226static void GetStackTraceFromId(u32 id, StackTrace *stack) {
227  CHECK(id);
228  uptr size = 0;
229  const uptr *trace = StackDepotGet(id, &size);
230  CHECK_LT(size, kStackTraceMax);
231  internal_memcpy(stack->trace, trace, sizeof(uptr) * size);
232  stack->size = size;
233}
234
235void AsanChunkView::GetAllocStack(StackTrace *stack) {
236  if (flags()->use_stack_depot)
237    GetStackTraceFromId(chunk_->alloc_context_id, stack);
238  else
239    StackTrace::UncompressStack(stack, chunk_->AllocStackBeg(),
240                                chunk_->AllocStackSize());
241}
242
243void AsanChunkView::GetFreeStack(StackTrace *stack) {
244  if (flags()->use_stack_depot)
245    GetStackTraceFromId(chunk_->free_context_id, stack);
246  else
247    StackTrace::UncompressStack(stack, chunk_->FreeStackBeg(),
248                                chunk_->FreeStackSize());
249}
250
251struct QuarantineCallback;
252typedef Quarantine<QuarantineCallback, AsanChunk> AsanQuarantine;
253typedef AsanQuarantine::Cache QuarantineCache;
254static AsanQuarantine quarantine(LINKER_INITIALIZED);
255static QuarantineCache fallback_quarantine_cache(LINKER_INITIALIZED);
256static AllocatorCache fallback_allocator_cache;
257static SpinMutex fallback_mutex;
258
259QuarantineCache *GetQuarantineCache(AsanThreadLocalMallocStorage *ms) {
260  CHECK(ms);
261  CHECK_LE(sizeof(QuarantineCache), sizeof(ms->quarantine_cache));
262  return reinterpret_cast<QuarantineCache *>(ms->quarantine_cache);
263}
264
265struct QuarantineCallback {
266  explicit QuarantineCallback(AllocatorCache *cache)
267      : cache_(cache) {
268  }
269
270  void Recycle(AsanChunk *m) {
271    CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
272    atomic_store((atomic_uint8_t*)m, CHUNK_AVAILABLE, memory_order_relaxed);
273    CHECK_NE(m->alloc_tid, kInvalidTid);
274    CHECK_NE(m->free_tid, kInvalidTid);
275    PoisonShadow(m->Beg(),
276                 RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
277                 kAsanHeapLeftRedzoneMagic);
278    void *p = reinterpret_cast<void *>(m->AllocBeg());
279    if (m->from_memalign) {
280      uptr *memalign_magic = reinterpret_cast<uptr *>(p);
281      CHECK_EQ(memalign_magic[0], kMemalignMagic);
282      CHECK_EQ(memalign_magic[1], reinterpret_cast<uptr>(m));
283    }
284
285    // Statistics.
286    AsanStats &thread_stats = GetCurrentThreadStats();
287    thread_stats.real_frees++;
288    thread_stats.really_freed += m->UsedSize();
289
290    allocator.Deallocate(cache_, p);
291  }
292
293  void *Allocate(uptr size) {
294    return allocator.Allocate(cache_, size, 1, false);
295  }
296
297  void Deallocate(void *p) {
298    allocator.Deallocate(cache_, p);
299  }
300
301  AllocatorCache *cache_;
302};
303
304void InitializeAllocator() {
305  allocator.Init();
306  quarantine.Init((uptr)flags()->quarantine_size, kMaxThreadLocalQuarantine);
307}
308
309static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
310                      AllocType alloc_type, bool can_fill) {
311  if (!asan_inited)
312    __asan_init();
313  Flags &fl = *flags();
314  CHECK(stack);
315  const uptr min_alignment = SHADOW_GRANULARITY;
316  if (alignment < min_alignment)
317    alignment = min_alignment;
318  if (size == 0) {
319    // We'd be happy to avoid allocating memory for zero-size requests, but
320    // some programs/tests depend on this behavior and assume that malloc would
321    // not return NULL even for zero-size allocations. Moreover, it looks like
322    // operator new should never return NULL, and results of consecutive "new"
323    // calls must be different even if the allocated size is zero.
324    size = 1;
325  }
326  CHECK(IsPowerOfTwo(alignment));
327  uptr rz_log = ComputeRZLog(size);
328  uptr rz_size = RZLog2Size(rz_log);
329  uptr rounded_size = RoundUpTo(Max(size, kChunkHeader2Size), alignment);
330  uptr needed_size = rounded_size + rz_size;
331  if (alignment > min_alignment)
332    needed_size += alignment;
333  bool using_primary_allocator = true;
334  // If we are allocating from the secondary allocator, there will be no
335  // automatic right redzone, so add the right redzone manually.
336  if (!PrimaryAllocator::CanAllocate(needed_size, alignment)) {
337    needed_size += rz_size;
338    using_primary_allocator = false;
339  }
340  CHECK(IsAligned(needed_size, min_alignment));
341  if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) {
342    Report("WARNING: AddressSanitizer failed to allocate %p bytes\n",
343           (void*)size);
344    return 0;
345  }
346
347  AsanThread *t = GetCurrentThread();
348  void *allocated;
349  if (t) {
350    AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
351    allocated = allocator.Allocate(cache, needed_size, 8, false);
352  } else {
353    SpinMutexLock l(&fallback_mutex);
354    AllocatorCache *cache = &fallback_allocator_cache;
355    allocated = allocator.Allocate(cache, needed_size, 8, false);
356  }
357  uptr alloc_beg = reinterpret_cast<uptr>(allocated);
358  // Clear the first allocated word (an old kMemalignMagic may still be there).
359  reinterpret_cast<uptr *>(alloc_beg)[0] = 0;
360  uptr alloc_end = alloc_beg + needed_size;
361  uptr beg_plus_redzone = alloc_beg + rz_size;
362  uptr user_beg = beg_plus_redzone;
363  if (!IsAligned(user_beg, alignment))
364    user_beg = RoundUpTo(user_beg, alignment);
365  uptr user_end = user_beg + size;
366  CHECK_LE(user_end, alloc_end);
367  uptr chunk_beg = user_beg - kChunkHeaderSize;
368  AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
369  m->alloc_type = alloc_type;
370  m->rz_log = rz_log;
371  u32 alloc_tid = t ? t->tid() : 0;
372  m->alloc_tid = alloc_tid;
373  CHECK_EQ(alloc_tid, m->alloc_tid);  // Does alloc_tid fit into the bitfield?
374  m->free_tid = kInvalidTid;
375  m->from_memalign = user_beg != beg_plus_redzone;
376  if (m->from_memalign) {
377    CHECK_LE(beg_plus_redzone + 2 * sizeof(uptr), user_beg);
378    uptr *memalign_magic = reinterpret_cast<uptr *>(alloc_beg);
379    memalign_magic[0] = kMemalignMagic;
380    memalign_magic[1] = chunk_beg;
381  }
382  if (using_primary_allocator) {
383    CHECK(size);
384    m->user_requested_size = size;
385    CHECK(allocator.FromPrimary(allocated));
386  } else {
387    CHECK(!allocator.FromPrimary(allocated));
388    m->user_requested_size = SizeClassMap::kMaxSize;
389    uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(allocated));
390    meta[0] = size;
391    meta[1] = chunk_beg;
392  }
393
394  if (fl.use_stack_depot) {
395    m->alloc_context_id = StackDepotPut(stack->trace, stack->size);
396  } else {
397    m->alloc_context_id = 0;
398    StackTrace::CompressStack(stack, m->AllocStackBeg(), m->AllocStackSize());
399  }
400
401  uptr size_rounded_down_to_granularity = RoundDownTo(size, SHADOW_GRANULARITY);
402  // Unpoison the bulk of the memory region.
403  if (size_rounded_down_to_granularity)
404    PoisonShadow(user_beg, size_rounded_down_to_granularity, 0);
405  // Deal with the end of the region if size is not aligned to granularity.
406  if (size != size_rounded_down_to_granularity && fl.poison_heap) {
407    u8 *shadow = (u8*)MemToShadow(user_beg + size_rounded_down_to_granularity);
408    *shadow = size & (SHADOW_GRANULARITY - 1);
409  }
410
411  AsanStats &thread_stats = GetCurrentThreadStats();
412  thread_stats.mallocs++;
413  thread_stats.malloced += size;
414  thread_stats.malloced_redzones += needed_size - size;
415  uptr class_id = Min(kNumberOfSizeClasses, SizeClassMap::ClassID(needed_size));
416  thread_stats.malloced_by_size[class_id]++;
417  if (needed_size > SizeClassMap::kMaxSize)
418    thread_stats.malloc_large++;
419
420  void *res = reinterpret_cast<void *>(user_beg);
421  if (can_fill && fl.max_malloc_fill_size) {
422    uptr fill_size = Min(size, (uptr)fl.max_malloc_fill_size);
423    REAL(memset)(res, fl.malloc_fill_byte, fill_size);
424  }
425  // Must be the last mutation of metadata in this function.
426  atomic_store((atomic_uint8_t *)m, CHUNK_ALLOCATED, memory_order_release);
427  ASAN_MALLOC_HOOK(res, size);
428  return res;
429}
430
431static void AtomicallySetQuarantineFlag(AsanChunk *m,
432                                        void *ptr, StackTrace *stack) {
433  u8 old_chunk_state = CHUNK_ALLOCATED;
434  // Flip the chunk_state atomically to avoid race on double-free.
435  if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state,
436                                      CHUNK_QUARANTINE, memory_order_acquire)) {
437    if (old_chunk_state == CHUNK_QUARANTINE)
438      ReportDoubleFree((uptr)ptr, stack);
439    else
440      ReportFreeNotMalloced((uptr)ptr, stack);
441  }
442  CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state);
443}
444
445// Expects the chunk to already be marked as quarantined by using
446// AtomicallySetQuarantineFlag.
447static void QuarantineChunk(AsanChunk *m, void *ptr,
448                            StackTrace *stack, AllocType alloc_type) {
449  CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
450
451  // FIXME: if the free hook produces an ASan report (e.g. due to a bug),
452  // printing the report may crash as the AsanChunk free-related fields have not
453  // been updated yet. We might need to introduce yet another chunk state to
454  // handle this correctly, but don't want to yet.
455  ASAN_FREE_HOOK(ptr);
456
457  if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch)
458    ReportAllocTypeMismatch((uptr)ptr, stack,
459                            (AllocType)m->alloc_type, (AllocType)alloc_type);
460
461  CHECK_GE(m->alloc_tid, 0);
462  if (SANITIZER_WORDSIZE == 64)  // On 32-bits this resides in user area.
463    CHECK_EQ(m->free_tid, kInvalidTid);
464  AsanThread *t = GetCurrentThread();
465  m->free_tid = t ? t->tid() : 0;
466  if (flags()->use_stack_depot) {
467    m->free_context_id = StackDepotPut(stack->trace, stack->size);
468  } else {
469    m->free_context_id = 0;
470    StackTrace::CompressStack(stack, m->FreeStackBeg(), m->FreeStackSize());
471  }
472  // Poison the region.
473  PoisonShadow(m->Beg(),
474               RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
475               kAsanHeapFreeMagic);
476
477  AsanStats &thread_stats = GetCurrentThreadStats();
478  thread_stats.frees++;
479  thread_stats.freed += m->UsedSize();
480
481  // Push into quarantine.
482  if (t) {
483    AsanThreadLocalMallocStorage *ms = &t->malloc_storage();
484    AllocatorCache *ac = GetAllocatorCache(ms);
485    quarantine.Put(GetQuarantineCache(ms), QuarantineCallback(ac),
486                   m, m->UsedSize());
487  } else {
488    SpinMutexLock l(&fallback_mutex);
489    AllocatorCache *ac = &fallback_allocator_cache;
490    quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac),
491                   m, m->UsedSize());
492  }
493}
494
495static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
496  uptr p = reinterpret_cast<uptr>(ptr);
497  if (p == 0) return;
498
499  uptr chunk_beg = p - kChunkHeaderSize;
500  AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
501  // Must mark the chunk as quarantined before any changes to its metadata.
502  AtomicallySetQuarantineFlag(m, ptr, stack);
503  QuarantineChunk(m, ptr, stack, alloc_type);
504}
505
506static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
507  CHECK(old_ptr && new_size);
508  uptr p = reinterpret_cast<uptr>(old_ptr);
509  uptr chunk_beg = p - kChunkHeaderSize;
510  AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
511
512  AsanStats &thread_stats = GetCurrentThreadStats();
513  thread_stats.reallocs++;
514  thread_stats.realloced += new_size;
515
516  // Must mark the chunk as quarantined before any changes to its metadata.
517  // This also ensures that other threads can't deallocate it in the meantime.
518  AtomicallySetQuarantineFlag(m, old_ptr, stack);
519
520  uptr old_size = m->UsedSize();
521  uptr memcpy_size = Min(new_size, old_size);
522  void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true);
523  if (new_ptr) {
524    CHECK_NE(REAL(memcpy), (void*)0);
525    REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
526    QuarantineChunk(m, old_ptr, stack, FROM_MALLOC);
527  }
528  return new_ptr;
529}
530
531static AsanChunk *GetAsanChunkByAddr(uptr p) {
532  void *ptr = reinterpret_cast<void *>(p);
533  uptr alloc_beg = reinterpret_cast<uptr>(allocator.GetBlockBegin(ptr));
534  if (!alloc_beg) return 0;
535  uptr *memalign_magic = reinterpret_cast<uptr *>(alloc_beg);
536  if (memalign_magic[0] == kMemalignMagic) {
537    AsanChunk *m = reinterpret_cast<AsanChunk *>(memalign_magic[1]);
538    CHECK(m->from_memalign);
539    return m;
540  }
541  if (!allocator.FromPrimary(ptr)) {
542    uptr *meta = reinterpret_cast<uptr *>(
543        allocator.GetMetaData(reinterpret_cast<void *>(alloc_beg)));
544    AsanChunk *m = reinterpret_cast<AsanChunk *>(meta[1]);
545    return m;
546  }
547  uptr actual_size = allocator.GetActuallyAllocatedSize(ptr);
548  CHECK_LE(actual_size, SizeClassMap::kMaxSize);
549  // We know the actually allocted size, but we don't know the redzone size.
550  // Just try all possible redzone sizes.
551  for (u32 rz_log = 0; rz_log < 8; rz_log++) {
552    u32 rz_size = RZLog2Size(rz_log);
553    uptr max_possible_size = actual_size - rz_size;
554    if (ComputeRZLog(max_possible_size) != rz_log)
555      continue;
556    return reinterpret_cast<AsanChunk *>(
557        alloc_beg + rz_size - kChunkHeaderSize);
558  }
559  return 0;
560}
561
562static uptr AllocationSize(uptr p) {
563  AsanChunk *m = GetAsanChunkByAddr(p);
564  if (!m) return 0;
565  if (m->chunk_state != CHUNK_ALLOCATED) return 0;
566  if (m->Beg() != p) return 0;
567  return m->UsedSize();
568}
569
570// We have an address between two chunks, and we want to report just one.
571AsanChunk *ChooseChunk(uptr addr,
572                       AsanChunk *left_chunk, AsanChunk *right_chunk) {
573  // Prefer an allocated chunk over freed chunk and freed chunk
574  // over available chunk.
575  if (left_chunk->chunk_state != right_chunk->chunk_state) {
576    if (left_chunk->chunk_state == CHUNK_ALLOCATED)
577      return left_chunk;
578    if (right_chunk->chunk_state == CHUNK_ALLOCATED)
579      return right_chunk;
580    if (left_chunk->chunk_state == CHUNK_QUARANTINE)
581      return left_chunk;
582    if (right_chunk->chunk_state == CHUNK_QUARANTINE)
583      return right_chunk;
584  }
585  // Same chunk_state: choose based on offset.
586  sptr l_offset = 0, r_offset = 0;
587  CHECK(AsanChunkView(left_chunk).AddrIsAtRight(addr, 1, &l_offset));
588  CHECK(AsanChunkView(right_chunk).AddrIsAtLeft(addr, 1, &r_offset));
589  if (l_offset < r_offset)
590    return left_chunk;
591  return right_chunk;
592}
593
594AsanChunkView FindHeapChunkByAddress(uptr addr) {
595  AsanChunk *m1 = GetAsanChunkByAddr(addr);
596  if (!m1) return AsanChunkView(m1);
597  sptr offset = 0;
598  if (AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) {
599    // The address is in the chunk's left redzone, so maybe it is actually
600    // a right buffer overflow from the other chunk to the left.
601    // Search a bit to the left to see if there is another chunk.
602    AsanChunk *m2 = 0;
603    for (uptr l = 1; l < GetPageSizeCached(); l++) {
604      m2 = GetAsanChunkByAddr(addr - l);
605      if (m2 == m1) continue;  // Still the same chunk.
606      break;
607    }
608    if (m2 && AsanChunkView(m2).AddrIsAtRight(addr, 1, &offset))
609      m1 = ChooseChunk(addr, m2, m1);
610  }
611  return AsanChunkView(m1);
612}
613
614void AsanThreadLocalMallocStorage::CommitBack() {
615  AllocatorCache *ac = GetAllocatorCache(this);
616  quarantine.Drain(GetQuarantineCache(this), QuarantineCallback(ac));
617  allocator.SwallowCache(GetAllocatorCache(this));
618}
619
620void PrintInternalAllocatorStats() {
621  allocator.PrintStats();
622}
623
624SANITIZER_INTERFACE_ATTRIBUTE
625void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
626                    AllocType alloc_type) {
627  return Allocate(size, alignment, stack, alloc_type, true);
628}
629
630SANITIZER_INTERFACE_ATTRIBUTE
631void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) {
632  Deallocate(ptr, stack, alloc_type);
633}
634
635SANITIZER_INTERFACE_ATTRIBUTE
636void *asan_malloc(uptr size, StackTrace *stack) {
637  return Allocate(size, 8, stack, FROM_MALLOC, true);
638}
639
640void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
641  if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
642  void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
643  // If the memory comes from the secondary allocator no need to clear it
644  // as it comes directly from mmap.
645  if (ptr && allocator.FromPrimary(ptr))
646    REAL(memset)(ptr, 0, nmemb * size);
647  return ptr;
648}
649
650void *asan_realloc(void *p, uptr size, StackTrace *stack) {
651  if (p == 0)
652    return Allocate(size, 8, stack, FROM_MALLOC, true);
653  if (size == 0) {
654    Deallocate(p, stack, FROM_MALLOC);
655    return 0;
656  }
657  return Reallocate(p, size, stack);
658}
659
660void *asan_valloc(uptr size, StackTrace *stack) {
661  return Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true);
662}
663
664void *asan_pvalloc(uptr size, StackTrace *stack) {
665  uptr PageSize = GetPageSizeCached();
666  size = RoundUpTo(size, PageSize);
667  if (size == 0) {
668    // pvalloc(0) should allocate one page.
669    size = PageSize;
670  }
671  return Allocate(size, PageSize, stack, FROM_MALLOC, true);
672}
673
674int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
675                        StackTrace *stack) {
676  void *ptr = Allocate(size, alignment, stack, FROM_MALLOC, true);
677  CHECK(IsAligned((uptr)ptr, alignment));
678  *memptr = ptr;
679  return 0;
680}
681
682uptr asan_malloc_usable_size(void *ptr, StackTrace *stack) {
683  CHECK(stack);
684  if (ptr == 0) return 0;
685  uptr usable_size = AllocationSize(reinterpret_cast<uptr>(ptr));
686  if (flags()->check_malloc_usable_size && (usable_size == 0))
687    ReportMallocUsableSizeNotOwned((uptr)ptr, stack);
688  return usable_size;
689}
690
691uptr asan_mz_size(const void *ptr) {
692  return AllocationSize(reinterpret_cast<uptr>(ptr));
693}
694
695void asan_mz_force_lock() {
696  allocator.ForceLock();
697  fallback_mutex.Lock();
698}
699
700void asan_mz_force_unlock() {
701  fallback_mutex.Unlock();
702  allocator.ForceUnlock();
703}
704
705}  // namespace __asan
706
707// --- Implementation of LSan-specific functions --- {{{1
708namespace __lsan {
709void LockAllocator() {
710  __asan::allocator.ForceLock();
711}
712
713void UnlockAllocator() {
714  __asan::allocator.ForceUnlock();
715}
716
717void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
718  *begin = (uptr)&__asan::allocator;
719  *end = *begin + sizeof(__asan::allocator);
720}
721
722void *PointsIntoChunk(void* p) {
723  uptr addr = reinterpret_cast<uptr>(p);
724  __asan::AsanChunk *m = __asan::GetAsanChunkByAddr(addr);
725  if (!m) return 0;
726  uptr chunk = m->Beg();
727  if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr))
728    return reinterpret_cast<void *>(chunk);
729  return 0;
730}
731
732void *GetUserBegin(void *p) {
733  __asan::AsanChunk *m = __asan::GetAsanChunkByAddr(reinterpret_cast<uptr>(p));
734  CHECK(m);
735  return reinterpret_cast<void *>(m->Beg());
736}
737
738LsanMetadata::LsanMetadata(void *chunk) {
739  uptr addr = reinterpret_cast<uptr>(chunk);
740  metadata_ = reinterpret_cast<void *>(addr - __asan::kChunkHeaderSize);
741}
742
743bool LsanMetadata::allocated() const {
744  __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
745  return m->chunk_state == __asan::CHUNK_ALLOCATED;
746}
747
748ChunkTag LsanMetadata::tag() const {
749  __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
750  return static_cast<ChunkTag>(m->lsan_tag);
751}
752
753void LsanMetadata::set_tag(ChunkTag value) {
754  __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
755  m->lsan_tag = value;
756}
757
758uptr LsanMetadata::requested_size() const {
759  __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
760  return m->UsedSize();
761}
762
763u32 LsanMetadata::stack_trace_id() const {
764  __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
765  return m->alloc_context_id;
766}
767
768template <typename Callable> void ForEachChunk(Callable const &callback) {
769  __asan::allocator.ForEachChunk(callback);
770}
771#if 0
772template void ForEachChunk<ProcessPlatformSpecificAllocationsCb>(
773    ProcessPlatformSpecificAllocationsCb const &callback);
774template void ForEachChunk<PrintLeakedCb>(PrintLeakedCb const &callback);
775template void ForEachChunk<CollectLeaksCb>(CollectLeaksCb const &callback);
776template void ForEachChunk<MarkIndirectlyLeakedCb>(
777    MarkIndirectlyLeakedCb const &callback);
778template void ForEachChunk<ReportLeakedCb>(ReportLeakedCb const &callback);
779template void ForEachChunk<ClearTagCb>(ClearTagCb const &callback);
780#endif  // CAN_SANITIZE_LEAKS
781}  // namespace __lsan
782
783// ---------------------- Interface ---------------- {{{1
784using namespace __asan;  // NOLINT
785
786// ASan allocator doesn't reserve extra bytes, so normally we would
787// just return "size". We don't want to expose our redzone sizes, etc here.
788uptr __asan_get_estimated_allocated_size(uptr size) {
789  return size;
790}
791
792bool __asan_get_ownership(const void *p) {
793  uptr ptr = reinterpret_cast<uptr>(p);
794  return (AllocationSize(ptr) > 0);
795}
796
797uptr __asan_get_allocated_size(const void *p) {
798  if (p == 0) return 0;
799  uptr ptr = reinterpret_cast<uptr>(p);
800  uptr allocated_size = AllocationSize(ptr);
801  // Die if p is not malloced or if it is already freed.
802  if (allocated_size == 0) {
803    GET_STACK_TRACE_FATAL_HERE;
804    ReportAsanGetAllocatedSizeNotOwned(ptr, &stack);
805  }
806  return allocated_size;
807}
808
809#if !SANITIZER_SUPPORTS_WEAK_HOOKS
810// Provide default (no-op) implementation of malloc hooks.
811extern "C" {
812SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
813void __asan_malloc_hook(void *ptr, uptr size) {
814  (void)ptr;
815  (void)size;
816}
817SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
818void __asan_free_hook(void *ptr) {
819  (void)ptr;
820}
821}  // extern "C"
822#endif
823