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