asan_allocator2.cc revision 87bd39a72b65f1ef5c5a33fc8ba3aebae998903e
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  if (t && t->lsan_disabled())
426    m->lsan_tag = __lsan::kSuppressed;
427  else
428    m->lsan_tag = __lsan::kDirectlyLeaked;
429  // Must be the last mutation of metadata in this function.
430  atomic_store((atomic_uint8_t *)m, CHUNK_ALLOCATED, memory_order_release);
431  ASAN_MALLOC_HOOK(res, size);
432  return res;
433}
434
435static void AtomicallySetQuarantineFlag(AsanChunk *m,
436                                        void *ptr, StackTrace *stack) {
437  u8 old_chunk_state = CHUNK_ALLOCATED;
438  // Flip the chunk_state atomically to avoid race on double-free.
439  if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state,
440                                      CHUNK_QUARANTINE, memory_order_acquire)) {
441    if (old_chunk_state == CHUNK_QUARANTINE)
442      ReportDoubleFree((uptr)ptr, stack);
443    else
444      ReportFreeNotMalloced((uptr)ptr, stack);
445  }
446  CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state);
447}
448
449// Expects the chunk to already be marked as quarantined by using
450// AtomicallySetQuarantineFlag.
451static void QuarantineChunk(AsanChunk *m, void *ptr,
452                            StackTrace *stack, AllocType alloc_type) {
453  CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
454
455  if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch)
456    ReportAllocTypeMismatch((uptr)ptr, stack,
457                            (AllocType)m->alloc_type, (AllocType)alloc_type);
458
459  CHECK_GE(m->alloc_tid, 0);
460  if (SANITIZER_WORDSIZE == 64)  // On 32-bits this resides in user area.
461    CHECK_EQ(m->free_tid, kInvalidTid);
462  AsanThread *t = GetCurrentThread();
463  m->free_tid = t ? t->tid() : 0;
464  if (flags()->use_stack_depot) {
465    m->free_context_id = StackDepotPut(stack->trace, stack->size);
466  } else {
467    m->free_context_id = 0;
468    StackTrace::CompressStack(stack, m->FreeStackBeg(), m->FreeStackSize());
469  }
470  // Poison the region.
471  PoisonShadow(m->Beg(),
472               RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
473               kAsanHeapFreeMagic);
474
475  AsanStats &thread_stats = GetCurrentThreadStats();
476  thread_stats.frees++;
477  thread_stats.freed += m->UsedSize();
478
479  // Push into quarantine.
480  if (t) {
481    AsanThreadLocalMallocStorage *ms = &t->malloc_storage();
482    AllocatorCache *ac = GetAllocatorCache(ms);
483    quarantine.Put(GetQuarantineCache(ms), QuarantineCallback(ac),
484                   m, m->UsedSize());
485  } else {
486    SpinMutexLock l(&fallback_mutex);
487    AllocatorCache *ac = &fallback_allocator_cache;
488    quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac),
489                   m, m->UsedSize());
490  }
491}
492
493static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
494  uptr p = reinterpret_cast<uptr>(ptr);
495  if (p == 0) return;
496
497  uptr chunk_beg = p - kChunkHeaderSize;
498  AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
499  ASAN_FREE_HOOK(ptr);
500  // Must mark the chunk as quarantined before any changes to its metadata.
501  AtomicallySetQuarantineFlag(m, ptr, stack);
502  QuarantineChunk(m, ptr, stack, alloc_type);
503}
504
505static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
506  CHECK(old_ptr && new_size);
507  uptr p = reinterpret_cast<uptr>(old_ptr);
508  uptr chunk_beg = p - kChunkHeaderSize;
509  AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
510
511  AsanStats &thread_stats = GetCurrentThreadStats();
512  thread_stats.reallocs++;
513  thread_stats.realloced += new_size;
514
515  void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true);
516  if (new_ptr) {
517    CHECK_NE(REAL(memcpy), (void*)0);
518    uptr memcpy_size = Min(new_size, m->UsedSize());
519    // If realloc() races with free(), we may start copying freed memory.
520    // However, we will report racy double-free later anyway.
521    REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
522    Deallocate(old_ptr, stack, FROM_MALLOC);
523  }
524  return new_ptr;
525}
526
527// Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg).
528static AsanChunk *GetAsanChunk(void *alloc_beg) {
529  if (!alloc_beg) return 0;
530  uptr *memalign_magic = reinterpret_cast<uptr *>(alloc_beg);
531  if (memalign_magic[0] == kMemalignMagic) {
532    AsanChunk *m = reinterpret_cast<AsanChunk *>(memalign_magic[1]);
533    CHECK(m->from_memalign);
534    return m;
535  }
536  if (!allocator.FromPrimary(alloc_beg)) {
537    uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(alloc_beg));
538    AsanChunk *m = reinterpret_cast<AsanChunk *>(meta[1]);
539    return m;
540  }
541  uptr actual_size =
542      allocator.GetActuallyAllocatedSize(alloc_beg);
543  CHECK_LE(actual_size, SizeClassMap::kMaxSize);
544  // We know the actually allocted size, but we don't know the redzone size.
545  // Just try all possible redzone sizes.
546  for (u32 rz_log = 0; rz_log < 8; rz_log++) {
547    u32 rz_size = RZLog2Size(rz_log);
548    uptr max_possible_size = actual_size - rz_size;
549    if (ComputeRZLog(max_possible_size) != rz_log)
550      continue;
551    return reinterpret_cast<AsanChunk *>(
552        reinterpret_cast<uptr>(alloc_beg) + rz_size - kChunkHeaderSize);
553  }
554  return 0;
555}
556
557static AsanChunk *GetAsanChunkByAddr(uptr p) {
558  void *alloc_beg = allocator.GetBlockBegin(reinterpret_cast<void *>(p));
559  return GetAsanChunk(alloc_beg);
560}
561
562// Allocator must be locked when this function is called.
563static AsanChunk *GetAsanChunkByAddrFastLocked(uptr p) {
564  void *alloc_beg =
565      allocator.GetBlockBeginFastLocked(reinterpret_cast<void *>(p));
566  return GetAsanChunk(alloc_beg);
567}
568
569static uptr AllocationSize(uptr p) {
570  AsanChunk *m = GetAsanChunkByAddr(p);
571  if (!m) return 0;
572  if (m->chunk_state != CHUNK_ALLOCATED) return 0;
573  if (m->Beg() != p) return 0;
574  return m->UsedSize();
575}
576
577// We have an address between two chunks, and we want to report just one.
578AsanChunk *ChooseChunk(uptr addr,
579                       AsanChunk *left_chunk, AsanChunk *right_chunk) {
580  // Prefer an allocated chunk over freed chunk and freed chunk
581  // over available chunk.
582  if (left_chunk->chunk_state != right_chunk->chunk_state) {
583    if (left_chunk->chunk_state == CHUNK_ALLOCATED)
584      return left_chunk;
585    if (right_chunk->chunk_state == CHUNK_ALLOCATED)
586      return right_chunk;
587    if (left_chunk->chunk_state == CHUNK_QUARANTINE)
588      return left_chunk;
589    if (right_chunk->chunk_state == CHUNK_QUARANTINE)
590      return right_chunk;
591  }
592  // Same chunk_state: choose based on offset.
593  sptr l_offset = 0, r_offset = 0;
594  CHECK(AsanChunkView(left_chunk).AddrIsAtRight(addr, 1, &l_offset));
595  CHECK(AsanChunkView(right_chunk).AddrIsAtLeft(addr, 1, &r_offset));
596  if (l_offset < r_offset)
597    return left_chunk;
598  return right_chunk;
599}
600
601AsanChunkView FindHeapChunkByAddress(uptr addr) {
602  AsanChunk *m1 = GetAsanChunkByAddr(addr);
603  if (!m1) return AsanChunkView(m1);
604  sptr offset = 0;
605  if (AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) {
606    // The address is in the chunk's left redzone, so maybe it is actually
607    // a right buffer overflow from the other chunk to the left.
608    // Search a bit to the left to see if there is another chunk.
609    AsanChunk *m2 = 0;
610    for (uptr l = 1; l < GetPageSizeCached(); l++) {
611      m2 = GetAsanChunkByAddr(addr - l);
612      if (m2 == m1) continue;  // Still the same chunk.
613      break;
614    }
615    if (m2 && AsanChunkView(m2).AddrIsAtRight(addr, 1, &offset))
616      m1 = ChooseChunk(addr, m2, m1);
617  }
618  return AsanChunkView(m1);
619}
620
621void AsanThreadLocalMallocStorage::CommitBack() {
622  AllocatorCache *ac = GetAllocatorCache(this);
623  quarantine.Drain(GetQuarantineCache(this), QuarantineCallback(ac));
624  allocator.SwallowCache(GetAllocatorCache(this));
625}
626
627void PrintInternalAllocatorStats() {
628  allocator.PrintStats();
629}
630
631SANITIZER_INTERFACE_ATTRIBUTE
632void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
633                    AllocType alloc_type) {
634  return Allocate(size, alignment, stack, alloc_type, true);
635}
636
637SANITIZER_INTERFACE_ATTRIBUTE
638void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) {
639  Deallocate(ptr, stack, alloc_type);
640}
641
642SANITIZER_INTERFACE_ATTRIBUTE
643void *asan_malloc(uptr size, StackTrace *stack) {
644  return Allocate(size, 8, stack, FROM_MALLOC, true);
645}
646
647void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
648  if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
649  void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
650  // If the memory comes from the secondary allocator no need to clear it
651  // as it comes directly from mmap.
652  if (ptr && allocator.FromPrimary(ptr))
653    REAL(memset)(ptr, 0, nmemb * size);
654  return ptr;
655}
656
657void *asan_realloc(void *p, uptr size, StackTrace *stack) {
658  if (p == 0)
659    return Allocate(size, 8, stack, FROM_MALLOC, true);
660  if (size == 0) {
661    Deallocate(p, stack, FROM_MALLOC);
662    return 0;
663  }
664  return Reallocate(p, size, stack);
665}
666
667void *asan_valloc(uptr size, StackTrace *stack) {
668  return Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true);
669}
670
671void *asan_pvalloc(uptr size, StackTrace *stack) {
672  uptr PageSize = GetPageSizeCached();
673  size = RoundUpTo(size, PageSize);
674  if (size == 0) {
675    // pvalloc(0) should allocate one page.
676    size = PageSize;
677  }
678  return Allocate(size, PageSize, stack, FROM_MALLOC, true);
679}
680
681int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
682                        StackTrace *stack) {
683  void *ptr = Allocate(size, alignment, stack, FROM_MALLOC, true);
684  CHECK(IsAligned((uptr)ptr, alignment));
685  *memptr = ptr;
686  return 0;
687}
688
689uptr asan_malloc_usable_size(void *ptr, StackTrace *stack) {
690  CHECK(stack);
691  if (ptr == 0) return 0;
692  uptr usable_size = AllocationSize(reinterpret_cast<uptr>(ptr));
693  if (flags()->check_malloc_usable_size && (usable_size == 0))
694    ReportMallocUsableSizeNotOwned((uptr)ptr, stack);
695  return usable_size;
696}
697
698uptr asan_mz_size(const void *ptr) {
699  return AllocationSize(reinterpret_cast<uptr>(ptr));
700}
701
702void asan_mz_force_lock() {
703  allocator.ForceLock();
704  fallback_mutex.Lock();
705}
706
707void asan_mz_force_unlock() {
708  fallback_mutex.Unlock();
709  allocator.ForceUnlock();
710}
711
712}  // namespace __asan
713
714// --- Implementation of LSan-specific functions --- {{{1
715namespace __lsan {
716void LockAllocator() {
717  __asan::allocator.ForceLock();
718}
719
720void UnlockAllocator() {
721  __asan::allocator.ForceUnlock();
722}
723
724void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
725  *begin = (uptr)&__asan::allocator;
726  *end = *begin + sizeof(__asan::allocator);
727}
728
729void *PointsIntoChunk(void* p) {
730  uptr addr = reinterpret_cast<uptr>(p);
731  __asan::AsanChunk *m = __asan::GetAsanChunkByAddrFastLocked(addr);
732  if (!m) return 0;
733  uptr chunk = m->Beg();
734  if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr))
735    return reinterpret_cast<void *>(chunk);
736  return 0;
737}
738
739void *GetUserBegin(void *p) {
740  __asan::AsanChunk *m =
741      __asan::GetAsanChunkByAddrFastLocked(reinterpret_cast<uptr>(p));
742  CHECK(m);
743  return reinterpret_cast<void *>(m->Beg());
744}
745
746LsanMetadata::LsanMetadata(void *chunk) {
747  uptr addr = reinterpret_cast<uptr>(chunk);
748  metadata_ = reinterpret_cast<void *>(addr - __asan::kChunkHeaderSize);
749}
750
751bool LsanMetadata::allocated() const {
752  __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
753  return m->chunk_state == __asan::CHUNK_ALLOCATED;
754}
755
756ChunkTag LsanMetadata::tag() const {
757  __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
758  return static_cast<ChunkTag>(m->lsan_tag);
759}
760
761void LsanMetadata::set_tag(ChunkTag value) {
762  __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
763  m->lsan_tag = value;
764}
765
766uptr LsanMetadata::requested_size() const {
767  __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
768  return m->UsedSize();
769}
770
771u32 LsanMetadata::stack_trace_id() const {
772  __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
773  return m->alloc_context_id;
774}
775
776template <typename Callable> void ForEachChunk(Callable const &callback) {
777  __asan::allocator.ForEachChunk(callback);
778}
779#if CAN_SANITIZE_LEAKS
780template void ForEachChunk<ProcessPlatformSpecificAllocationsCb>(
781    ProcessPlatformSpecificAllocationsCb const &callback);
782template void ForEachChunk<PrintLeakedCb>(PrintLeakedCb const &callback);
783template void ForEachChunk<CollectLeaksCb>(CollectLeaksCb const &callback);
784template void ForEachChunk<MarkIndirectlyLeakedCb>(
785    MarkIndirectlyLeakedCb const &callback);
786template void ForEachChunk<CollectSuppressedCb>(
787    CollectSuppressedCb const &callback);
788#endif  // CAN_SANITIZE_LEAKS
789}  // namespace __lsan
790
791extern "C" {
792void __lsan_disable() {
793  __asan_init();
794  __asan::AsanThread *t = __asan::GetCurrentThread();
795  CHECK(t);
796  t->disable_lsan();
797}
798
799void __lsan_enable() {
800  __asan_init();
801  __asan::AsanThread *t = __asan::GetCurrentThread();
802  CHECK(t);
803  t->enable_lsan();
804}
805}  // extern "C"
806
807// ---------------------- Interface ---------------- {{{1
808using namespace __asan;  // NOLINT
809
810// ASan allocator doesn't reserve extra bytes, so normally we would
811// just return "size". We don't want to expose our redzone sizes, etc here.
812uptr __asan_get_estimated_allocated_size(uptr size) {
813  return size;
814}
815
816bool __asan_get_ownership(const void *p) {
817  uptr ptr = reinterpret_cast<uptr>(p);
818  return (AllocationSize(ptr) > 0);
819}
820
821uptr __asan_get_allocated_size(const void *p) {
822  if (p == 0) return 0;
823  uptr ptr = reinterpret_cast<uptr>(p);
824  uptr allocated_size = AllocationSize(ptr);
825  // Die if p is not malloced or if it is already freed.
826  if (allocated_size == 0) {
827    GET_STACK_TRACE_FATAL_HERE;
828    ReportAsanGetAllocatedSizeNotOwned(ptr, &stack);
829  }
830  return allocated_size;
831}
832
833#if !SANITIZER_SUPPORTS_WEAK_HOOKS
834// Provide default (no-op) implementation of malloc hooks.
835extern "C" {
836SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
837void __asan_malloc_hook(void *ptr, uptr size) {
838  (void)ptr;
839  (void)size;
840}
841SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
842void __asan_free_hook(void *ptr) {
843  (void)ptr;
844}
845}  // extern "C"
846#endif
847