1 //===-- asan_allocator.cpp ------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is a part of AddressSanitizer, an address sanity checker.
10 //
11 // Implementation of ASan's memory allocator, 2-nd version.
12 // This variant uses the allocator from sanitizer_common, i.e. the one shared
13 // with ThreadSanitizer and MemorySanitizer.
14 //
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_stack.h"
23 #include "asan_thread.h"
24 #include "lsan/lsan_common.h"
25 #include "sanitizer_common/sanitizer_allocator_checks.h"
26 #include "sanitizer_common/sanitizer_allocator_interface.h"
27 #include "sanitizer_common/sanitizer_errno.h"
28 #include "sanitizer_common/sanitizer_flags.h"
29 #include "sanitizer_common/sanitizer_internal_defs.h"
30 #include "sanitizer_common/sanitizer_list.h"
31 #include "sanitizer_common/sanitizer_quarantine.h"
32 #include "sanitizer_common/sanitizer_stackdepot.h"
33 
34 namespace __asan {
35 
36 // Valid redzone sizes are 16, 32, 64, ... 2048, so we encode them in 3 bits.
37 // We use adaptive redzones: for larger allocation larger redzones are used.
38 static u32 RZLog2Size(u32 rz_log) {
39   CHECK_LT(rz_log, 8);
40   return 16 << rz_log;
41 }
42 
43 static u32 RZSize2Log(u32 rz_size) {
44   CHECK_GE(rz_size, 16);
45   CHECK_LE(rz_size, 2048);
46   CHECK(IsPowerOfTwo(rz_size));
47   u32 res = Log2(rz_size) - 4;
48   CHECK_EQ(rz_size, RZLog2Size(res));
49   return res;
50 }
51 
52 static AsanAllocator &get_allocator();
53 
54 static void AtomicContextStore(volatile atomic_uint64_t *atomic_context,
55                                u32 tid, u32 stack) {
56   u64 context = tid;
57   context <<= 32;
58   context += stack;
59   atomic_store(atomic_context, context, memory_order_relaxed);
60 }
61 
62 static void AtomicContextLoad(const volatile atomic_uint64_t *atomic_context,
63                               u32 &tid, u32 &stack) {
64   u64 context = atomic_load(atomic_context, memory_order_relaxed);
65   stack = context;
66   context >>= 32;
67   tid = context;
68 }
69 
70 // The memory chunk allocated from the underlying allocator looks like this:
71 // L L L L L L H H U U U U U U R R
72 //   L -- left redzone words (0 or more bytes)
73 //   H -- ChunkHeader (16 bytes), which is also a part of the left redzone.
74 //   U -- user memory.
75 //   R -- right redzone (0 or more bytes)
76 // ChunkBase consists of ChunkHeader and other bytes that overlap with user
77 // memory.
78 
79 // If the left redzone is greater than the ChunkHeader size we store a magic
80 // value in the first uptr word of the memory block and store the address of
81 // ChunkBase in the next uptr.
82 // M B L L L L L L L L L  H H U U U U U U
83 //   |                    ^
84 //   ---------------------|
85 //   M -- magic value kAllocBegMagic
86 //   B -- address of ChunkHeader pointing to the first 'H'
87 
88 class ChunkHeader {
89  public:
90   atomic_uint8_t chunk_state;
91   u8 alloc_type : 2;
92   u8 lsan_tag : 2;
93 
94   // align < 8 -> 0
95   // else      -> log2(min(align, 512)) - 2
96   u8 user_requested_alignment_log : 3;
97 
98  private:
99   u16 user_requested_size_hi;
100   u32 user_requested_size_lo;
101   atomic_uint64_t alloc_context_id;
102 
103  public:
104   uptr UsedSize() const {
105     static_assert(sizeof(user_requested_size_lo) == 4,
106                   "Expression below requires this");
107     return FIRST_32_SECOND_64(0, ((uptr)user_requested_size_hi << 32)) +
108            user_requested_size_lo;
109   }
110 
111   void SetUsedSize(uptr size) {
112     user_requested_size_lo = size;
113     static_assert(sizeof(user_requested_size_lo) == 4,
114                   "Expression below requires this");
115     user_requested_size_hi = FIRST_32_SECOND_64(0, size >> 32);
116     CHECK_EQ(UsedSize(), size);
117   }
118 
119   void SetAllocContext(u32 tid, u32 stack) {
120     AtomicContextStore(&alloc_context_id, tid, stack);
121   }
122 
123   void GetAllocContext(u32 &tid, u32 &stack) const {
124     AtomicContextLoad(&alloc_context_id, tid, stack);
125   }
126 };
127 
128 class ChunkBase : public ChunkHeader {
129   atomic_uint64_t free_context_id;
130 
131  public:
132   void SetFreeContext(u32 tid, u32 stack) {
133     AtomicContextStore(&free_context_id, tid, stack);
134   }
135 
136   void GetFreeContext(u32 &tid, u32 &stack) const {
137     AtomicContextLoad(&free_context_id, tid, stack);
138   }
139 };
140 
141 static const uptr kChunkHeaderSize = sizeof(ChunkHeader);
142 static const uptr kChunkHeader2Size = sizeof(ChunkBase) - kChunkHeaderSize;
143 COMPILER_CHECK(kChunkHeaderSize == 16);
144 COMPILER_CHECK(kChunkHeader2Size <= 16);
145 
146 enum {
147   // Either just allocated by underlying allocator, but AsanChunk is not yet
148   // ready, or almost returned to undelying allocator and AsanChunk is already
149   // meaningless.
150   CHUNK_INVALID = 0,
151   // The chunk is allocated and not yet freed.
152   CHUNK_ALLOCATED = 2,
153   // The chunk was freed and put into quarantine zone.
154   CHUNK_QUARANTINE = 3,
155 };
156 
157 class AsanChunk : public ChunkBase {
158  public:
159   uptr Beg() { return reinterpret_cast<uptr>(this) + kChunkHeaderSize; }
160   bool AddrIsInside(uptr addr) {
161     return (addr >= Beg()) && (addr < Beg() + UsedSize());
162   }
163 };
164 
165 class LargeChunkHeader {
166   static constexpr uptr kAllocBegMagic =
167       FIRST_32_SECOND_64(0xCC6E96B9, 0xCC6E96B9CC6E96B9ULL);
168   atomic_uintptr_t magic;
169   AsanChunk *chunk_header;
170 
171  public:
172   AsanChunk *Get() const {
173     return atomic_load(&magic, memory_order_acquire) == kAllocBegMagic
174                ? chunk_header
175                : nullptr;
176   }
177 
178   void Set(AsanChunk *p) {
179     if (p) {
180       chunk_header = p;
181       atomic_store(&magic, kAllocBegMagic, memory_order_release);
182       return;
183     }
184 
185     uptr old = kAllocBegMagic;
186     if (!atomic_compare_exchange_strong(&magic, &old, 0,
187                                         memory_order_release)) {
188       CHECK_EQ(old, kAllocBegMagic);
189     }
190   }
191 };
192 
193 struct QuarantineCallback {
194   QuarantineCallback(AllocatorCache *cache, BufferedStackTrace *stack)
195       : cache_(cache),
196         stack_(stack) {
197   }
198 
199   void Recycle(AsanChunk *m) {
200     void *p = get_allocator().GetBlockBegin(m);
201     if (p != m) {
202       // Clear the magic value, as allocator internals may overwrite the
203       // contents of deallocated chunk, confusing GetAsanChunk lookup.
204       reinterpret_cast<LargeChunkHeader *>(p)->Set(nullptr);
205     }
206 
207     u8 old_chunk_state = CHUNK_QUARANTINE;
208     if (!atomic_compare_exchange_strong(&m->chunk_state, &old_chunk_state,
209                                         CHUNK_INVALID, memory_order_acquire)) {
210       CHECK_EQ(old_chunk_state, CHUNK_QUARANTINE);
211     }
212 
213     PoisonShadow(m->Beg(),
214                  RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
215                  kAsanHeapLeftRedzoneMagic);
216 
217     // Statistics.
218     AsanStats &thread_stats = GetCurrentThreadStats();
219     thread_stats.real_frees++;
220     thread_stats.really_freed += m->UsedSize();
221 
222     get_allocator().Deallocate(cache_, p);
223   }
224 
225   void *Allocate(uptr size) {
226     void *res = get_allocator().Allocate(cache_, size, 1);
227     // TODO(alekseys): Consider making quarantine OOM-friendly.
228     if (UNLIKELY(!res))
229       ReportOutOfMemory(size, stack_);
230     return res;
231   }
232 
233   void Deallocate(void *p) {
234     get_allocator().Deallocate(cache_, p);
235   }
236 
237  private:
238   AllocatorCache* const cache_;
239   BufferedStackTrace* const stack_;
240 };
241 
242 typedef Quarantine<QuarantineCallback, AsanChunk> AsanQuarantine;
243 typedef AsanQuarantine::Cache QuarantineCache;
244 
245 void AsanMapUnmapCallback::OnMap(uptr p, uptr size) const {
246   PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic);
247   // Statistics.
248   AsanStats &thread_stats = GetCurrentThreadStats();
249   thread_stats.mmaps++;
250   thread_stats.mmaped += size;
251 }
252 void AsanMapUnmapCallback::OnUnmap(uptr p, uptr size) const {
253   PoisonShadow(p, size, 0);
254   // We are about to unmap a chunk of user memory.
255   // Mark the corresponding shadow memory as not needed.
256   FlushUnneededASanShadowMemory(p, size);
257   // Statistics.
258   AsanStats &thread_stats = GetCurrentThreadStats();
259   thread_stats.munmaps++;
260   thread_stats.munmaped += size;
261 }
262 
263 // We can not use THREADLOCAL because it is not supported on some of the
264 // platforms we care about (OSX 10.6, Android).
265 // static THREADLOCAL AllocatorCache cache;
266 AllocatorCache *GetAllocatorCache(AsanThreadLocalMallocStorage *ms) {
267   CHECK(ms);
268   return &ms->allocator_cache;
269 }
270 
271 QuarantineCache *GetQuarantineCache(AsanThreadLocalMallocStorage *ms) {
272   CHECK(ms);
273   CHECK_LE(sizeof(QuarantineCache), sizeof(ms->quarantine_cache));
274   return reinterpret_cast<QuarantineCache *>(ms->quarantine_cache);
275 }
276 
277 void AllocatorOptions::SetFrom(const Flags *f, const CommonFlags *cf) {
278   quarantine_size_mb = f->quarantine_size_mb;
279   thread_local_quarantine_size_kb = f->thread_local_quarantine_size_kb;
280   min_redzone = f->redzone;
281   max_redzone = f->max_redzone;
282   may_return_null = cf->allocator_may_return_null;
283   alloc_dealloc_mismatch = f->alloc_dealloc_mismatch;
284   release_to_os_interval_ms = cf->allocator_release_to_os_interval_ms;
285 }
286 
287 void AllocatorOptions::CopyTo(Flags *f, CommonFlags *cf) {
288   f->quarantine_size_mb = quarantine_size_mb;
289   f->thread_local_quarantine_size_kb = thread_local_quarantine_size_kb;
290   f->redzone = min_redzone;
291   f->max_redzone = max_redzone;
292   cf->allocator_may_return_null = may_return_null;
293   f->alloc_dealloc_mismatch = alloc_dealloc_mismatch;
294   cf->allocator_release_to_os_interval_ms = release_to_os_interval_ms;
295 }
296 
297 struct Allocator {
298   static const uptr kMaxAllowedMallocSize =
299       FIRST_32_SECOND_64(3UL << 30, 1ULL << 40);
300 
301   AsanAllocator allocator;
302   AsanQuarantine quarantine;
303   StaticSpinMutex fallback_mutex;
304   AllocatorCache fallback_allocator_cache;
305   QuarantineCache fallback_quarantine_cache;
306 
307   uptr max_user_defined_malloc_size;
308 
309   // ------------------- Options --------------------------
310   atomic_uint16_t min_redzone;
311   atomic_uint16_t max_redzone;
312   atomic_uint8_t alloc_dealloc_mismatch;
313 
314   // ------------------- Initialization ------------------------
315   explicit Allocator(LinkerInitialized)
316       : quarantine(LINKER_INITIALIZED),
317         fallback_quarantine_cache(LINKER_INITIALIZED) {}
318 
319   void CheckOptions(const AllocatorOptions &options) const {
320     CHECK_GE(options.min_redzone, 16);
321     CHECK_GE(options.max_redzone, options.min_redzone);
322     CHECK_LE(options.max_redzone, 2048);
323     CHECK(IsPowerOfTwo(options.min_redzone));
324     CHECK(IsPowerOfTwo(options.max_redzone));
325   }
326 
327   void SharedInitCode(const AllocatorOptions &options) {
328     CheckOptions(options);
329     quarantine.Init((uptr)options.quarantine_size_mb << 20,
330                     (uptr)options.thread_local_quarantine_size_kb << 10);
331     atomic_store(&alloc_dealloc_mismatch, options.alloc_dealloc_mismatch,
332                  memory_order_release);
333     atomic_store(&min_redzone, options.min_redzone, memory_order_release);
334     atomic_store(&max_redzone, options.max_redzone, memory_order_release);
335   }
336 
337   void InitLinkerInitialized(const AllocatorOptions &options) {
338     SetAllocatorMayReturnNull(options.may_return_null);
339     allocator.InitLinkerInitialized(options.release_to_os_interval_ms);
340     SharedInitCode(options);
341     max_user_defined_malloc_size = common_flags()->max_allocation_size_mb
342                                        ? common_flags()->max_allocation_size_mb
343                                              << 20
344                                        : kMaxAllowedMallocSize;
345   }
346 
347   void RePoisonChunk(uptr chunk) {
348     // This could be a user-facing chunk (with redzones), or some internal
349     // housekeeping chunk, like TransferBatch. Start by assuming the former.
350     AsanChunk *ac = GetAsanChunk((void *)chunk);
351     uptr allocated_size = allocator.GetActuallyAllocatedSize((void *)chunk);
352     if (ac && atomic_load(&ac->chunk_state, memory_order_acquire) ==
353                   CHUNK_ALLOCATED) {
354       uptr beg = ac->Beg();
355       uptr end = ac->Beg() + ac->UsedSize();
356       uptr chunk_end = chunk + allocated_size;
357       if (chunk < beg && beg < end && end <= chunk_end) {
358         // Looks like a valid AsanChunk in use, poison redzones only.
359         PoisonShadow(chunk, beg - chunk, kAsanHeapLeftRedzoneMagic);
360         uptr end_aligned_down = RoundDownTo(end, SHADOW_GRANULARITY);
361         FastPoisonShadowPartialRightRedzone(
362             end_aligned_down, end - end_aligned_down,
363             chunk_end - end_aligned_down, kAsanHeapLeftRedzoneMagic);
364         return;
365       }
366     }
367 
368     // This is either not an AsanChunk or freed or quarantined AsanChunk.
369     // In either case, poison everything.
370     PoisonShadow(chunk, allocated_size, kAsanHeapLeftRedzoneMagic);
371   }
372 
373   void ReInitialize(const AllocatorOptions &options) {
374     SetAllocatorMayReturnNull(options.may_return_null);
375     allocator.SetReleaseToOSIntervalMs(options.release_to_os_interval_ms);
376     SharedInitCode(options);
377 
378     // Poison all existing allocation's redzones.
379     if (CanPoisonMemory()) {
380       allocator.ForceLock();
381       allocator.ForEachChunk(
382           [](uptr chunk, void *alloc) {
383             ((Allocator *)alloc)->RePoisonChunk(chunk);
384           },
385           this);
386       allocator.ForceUnlock();
387     }
388   }
389 
390   void GetOptions(AllocatorOptions *options) const {
391     options->quarantine_size_mb = quarantine.GetSize() >> 20;
392     options->thread_local_quarantine_size_kb = quarantine.GetCacheSize() >> 10;
393     options->min_redzone = atomic_load(&min_redzone, memory_order_acquire);
394     options->max_redzone = atomic_load(&max_redzone, memory_order_acquire);
395     options->may_return_null = AllocatorMayReturnNull();
396     options->alloc_dealloc_mismatch =
397         atomic_load(&alloc_dealloc_mismatch, memory_order_acquire);
398     options->release_to_os_interval_ms = allocator.ReleaseToOSIntervalMs();
399   }
400 
401   // -------------------- Helper methods. -------------------------
402   uptr ComputeRZLog(uptr user_requested_size) {
403     u32 rz_log = user_requested_size <= 64 - 16            ? 0
404                  : user_requested_size <= 128 - 32         ? 1
405                  : user_requested_size <= 512 - 64         ? 2
406                  : user_requested_size <= 4096 - 128       ? 3
407                  : user_requested_size <= (1 << 14) - 256  ? 4
408                  : user_requested_size <= (1 << 15) - 512  ? 5
409                  : user_requested_size <= (1 << 16) - 1024 ? 6
410                                                            : 7;
411     u32 hdr_log = RZSize2Log(RoundUpToPowerOfTwo(sizeof(ChunkHeader)));
412     u32 min_log = RZSize2Log(atomic_load(&min_redzone, memory_order_acquire));
413     u32 max_log = RZSize2Log(atomic_load(&max_redzone, memory_order_acquire));
414     return Min(Max(rz_log, Max(min_log, hdr_log)), Max(max_log, hdr_log));
415   }
416 
417   static uptr ComputeUserRequestedAlignmentLog(uptr user_requested_alignment) {
418     if (user_requested_alignment < 8)
419       return 0;
420     if (user_requested_alignment > 512)
421       user_requested_alignment = 512;
422     return Log2(user_requested_alignment) - 2;
423   }
424 
425   static uptr ComputeUserAlignment(uptr user_requested_alignment_log) {
426     if (user_requested_alignment_log == 0)
427       return 0;
428     return 1LL << (user_requested_alignment_log + 2);
429   }
430 
431   // We have an address between two chunks, and we want to report just one.
432   AsanChunk *ChooseChunk(uptr addr, AsanChunk *left_chunk,
433                          AsanChunk *right_chunk) {
434     if (!left_chunk)
435       return right_chunk;
436     if (!right_chunk)
437       return left_chunk;
438     // Prefer an allocated chunk over freed chunk and freed chunk
439     // over available chunk.
440     u8 left_state = atomic_load(&left_chunk->chunk_state, memory_order_relaxed);
441     u8 right_state =
442         atomic_load(&right_chunk->chunk_state, memory_order_relaxed);
443     if (left_state != right_state) {
444       if (left_state == CHUNK_ALLOCATED)
445         return left_chunk;
446       if (right_state == CHUNK_ALLOCATED)
447         return right_chunk;
448       if (left_state == CHUNK_QUARANTINE)
449         return left_chunk;
450       if (right_state == CHUNK_QUARANTINE)
451         return right_chunk;
452     }
453     // Same chunk_state: choose based on offset.
454     sptr l_offset = 0, r_offset = 0;
455     CHECK(AsanChunkView(left_chunk).AddrIsAtRight(addr, 1, &l_offset));
456     CHECK(AsanChunkView(right_chunk).AddrIsAtLeft(addr, 1, &r_offset));
457     if (l_offset < r_offset)
458       return left_chunk;
459     return right_chunk;
460   }
461 
462   bool UpdateAllocationStack(uptr addr, BufferedStackTrace *stack) {
463     AsanChunk *m = GetAsanChunkByAddr(addr);
464     if (!m) return false;
465     if (atomic_load(&m->chunk_state, memory_order_acquire) != CHUNK_ALLOCATED)
466       return false;
467     if (m->Beg() != addr) return false;
468     AsanThread *t = GetCurrentThread();
469     m->SetAllocContext(t ? t->tid() : kMainTid, StackDepotPut(*stack));
470     return true;
471   }
472 
473   // -------------------- Allocation/Deallocation routines ---------------
474   void *Allocate(uptr size, uptr alignment, BufferedStackTrace *stack,
475                  AllocType alloc_type, bool can_fill) {
476     if (UNLIKELY(!asan_inited))
477       AsanInitFromRtl();
478     if (UNLIKELY(IsRssLimitExceeded())) {
479       if (AllocatorMayReturnNull())
480         return nullptr;
481       ReportRssLimitExceeded(stack);
482     }
483     Flags &fl = *flags();
484     CHECK(stack);
485     const uptr min_alignment = SHADOW_GRANULARITY;
486     const uptr user_requested_alignment_log =
487         ComputeUserRequestedAlignmentLog(alignment);
488     if (alignment < min_alignment)
489       alignment = min_alignment;
490     if (size == 0) {
491       // We'd be happy to avoid allocating memory for zero-size requests, but
492       // some programs/tests depend on this behavior and assume that malloc
493       // would not return NULL even for zero-size allocations. Moreover, it
494       // looks like operator new should never return NULL, and results of
495       // consecutive "new" calls must be different even if the allocated size
496       // is zero.
497       size = 1;
498     }
499     CHECK(IsPowerOfTwo(alignment));
500     uptr rz_log = ComputeRZLog(size);
501     uptr rz_size = RZLog2Size(rz_log);
502     uptr rounded_size = RoundUpTo(Max(size, kChunkHeader2Size), alignment);
503     uptr needed_size = rounded_size + rz_size;
504     if (alignment > min_alignment)
505       needed_size += alignment;
506     // If we are allocating from the secondary allocator, there will be no
507     // automatic right redzone, so add the right redzone manually.
508     if (!PrimaryAllocator::CanAllocate(needed_size, alignment))
509       needed_size += rz_size;
510     CHECK(IsAligned(needed_size, min_alignment));
511     if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize ||
512         size > max_user_defined_malloc_size) {
513       if (AllocatorMayReturnNull()) {
514         Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n",
515                size);
516         return nullptr;
517       }
518       uptr malloc_limit =
519           Min(kMaxAllowedMallocSize, max_user_defined_malloc_size);
520       ReportAllocationSizeTooBig(size, needed_size, malloc_limit, stack);
521     }
522 
523     AsanThread *t = GetCurrentThread();
524     void *allocated;
525     if (t) {
526       AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
527       allocated = allocator.Allocate(cache, needed_size, 8);
528     } else {
529       SpinMutexLock l(&fallback_mutex);
530       AllocatorCache *cache = &fallback_allocator_cache;
531       allocated = allocator.Allocate(cache, needed_size, 8);
532     }
533     if (UNLIKELY(!allocated)) {
534       SetAllocatorOutOfMemory();
535       if (AllocatorMayReturnNull())
536         return nullptr;
537       ReportOutOfMemory(size, stack);
538     }
539 
540     if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && CanPoisonMemory()) {
541       // Heap poisoning is enabled, but the allocator provides an unpoisoned
542       // chunk. This is possible if CanPoisonMemory() was false for some
543       // time, for example, due to flags()->start_disabled.
544       // Anyway, poison the block before using it for anything else.
545       uptr allocated_size = allocator.GetActuallyAllocatedSize(allocated);
546       PoisonShadow((uptr)allocated, allocated_size, kAsanHeapLeftRedzoneMagic);
547     }
548 
549     uptr alloc_beg = reinterpret_cast<uptr>(allocated);
550     uptr alloc_end = alloc_beg + needed_size;
551     uptr user_beg = alloc_beg + rz_size;
552     if (!IsAligned(user_beg, alignment))
553       user_beg = RoundUpTo(user_beg, alignment);
554     uptr user_end = user_beg + size;
555     CHECK_LE(user_end, alloc_end);
556     uptr chunk_beg = user_beg - kChunkHeaderSize;
557     AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
558     m->alloc_type = alloc_type;
559     CHECK(size);
560     m->SetUsedSize(size);
561     m->user_requested_alignment_log = user_requested_alignment_log;
562 
563     m->SetAllocContext(t ? t->tid() : kMainTid, StackDepotPut(*stack));
564 
565     uptr size_rounded_down_to_granularity =
566         RoundDownTo(size, SHADOW_GRANULARITY);
567     // Unpoison the bulk of the memory region.
568     if (size_rounded_down_to_granularity)
569       PoisonShadow(user_beg, size_rounded_down_to_granularity, 0);
570     // Deal with the end of the region if size is not aligned to granularity.
571     if (size != size_rounded_down_to_granularity && CanPoisonMemory()) {
572       u8 *shadow =
573           (u8 *)MemToShadow(user_beg + size_rounded_down_to_granularity);
574       *shadow = fl.poison_partial ? (size & (SHADOW_GRANULARITY - 1)) : 0;
575     }
576 
577     AsanStats &thread_stats = GetCurrentThreadStats();
578     thread_stats.mallocs++;
579     thread_stats.malloced += size;
580     thread_stats.malloced_redzones += needed_size - size;
581     if (needed_size > SizeClassMap::kMaxSize)
582       thread_stats.malloc_large++;
583     else
584       thread_stats.malloced_by_size[SizeClassMap::ClassID(needed_size)]++;
585 
586     void *res = reinterpret_cast<void *>(user_beg);
587     if (can_fill && fl.max_malloc_fill_size) {
588       uptr fill_size = Min(size, (uptr)fl.max_malloc_fill_size);
589       REAL(memset)(res, fl.malloc_fill_byte, fill_size);
590     }
591 #if CAN_SANITIZE_LEAKS
592     m->lsan_tag = __lsan::DisabledInThisThread() ? __lsan::kIgnored
593                                                  : __lsan::kDirectlyLeaked;
594 #endif
595     // Must be the last mutation of metadata in this function.
596     atomic_store(&m->chunk_state, CHUNK_ALLOCATED, memory_order_release);
597     if (alloc_beg != chunk_beg) {
598       CHECK_LE(alloc_beg + sizeof(LargeChunkHeader), chunk_beg);
599       reinterpret_cast<LargeChunkHeader *>(alloc_beg)->Set(m);
600     }
601     ASAN_MALLOC_HOOK(res, size);
602     return res;
603   }
604 
605   // Set quarantine flag if chunk is allocated, issue ASan error report on
606   // available and quarantined chunks. Return true on success, false otherwise.
607   bool AtomicallySetQuarantineFlagIfAllocated(AsanChunk *m, void *ptr,
608                                               BufferedStackTrace *stack) {
609     u8 old_chunk_state = CHUNK_ALLOCATED;
610     // Flip the chunk_state atomically to avoid race on double-free.
611     if (!atomic_compare_exchange_strong(&m->chunk_state, &old_chunk_state,
612                                         CHUNK_QUARANTINE,
613                                         memory_order_acquire)) {
614       ReportInvalidFree(ptr, old_chunk_state, stack);
615       // It's not safe to push a chunk in quarantine on invalid free.
616       return false;
617     }
618     CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state);
619     // It was a user data.
620     m->SetFreeContext(kInvalidTid, 0);
621     return true;
622   }
623 
624   // Expects the chunk to already be marked as quarantined by using
625   // AtomicallySetQuarantineFlagIfAllocated.
626   void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack) {
627     CHECK_EQ(atomic_load(&m->chunk_state, memory_order_relaxed),
628              CHUNK_QUARANTINE);
629     AsanThread *t = GetCurrentThread();
630     m->SetFreeContext(t ? t->tid() : 0, StackDepotPut(*stack));
631 
632     Flags &fl = *flags();
633     if (fl.max_free_fill_size > 0) {
634       // We have to skip the chunk header, it contains free_context_id.
635       uptr scribble_start = (uptr)m + kChunkHeaderSize + kChunkHeader2Size;
636       if (m->UsedSize() >= kChunkHeader2Size) {  // Skip Header2 in user area.
637         uptr size_to_fill = m->UsedSize() - kChunkHeader2Size;
638         size_to_fill = Min(size_to_fill, (uptr)fl.max_free_fill_size);
639         REAL(memset)((void *)scribble_start, fl.free_fill_byte, size_to_fill);
640       }
641     }
642 
643     // Poison the region.
644     PoisonShadow(m->Beg(),
645                  RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
646                  kAsanHeapFreeMagic);
647 
648     AsanStats &thread_stats = GetCurrentThreadStats();
649     thread_stats.frees++;
650     thread_stats.freed += m->UsedSize();
651 
652     // Push into quarantine.
653     if (t) {
654       AsanThreadLocalMallocStorage *ms = &t->malloc_storage();
655       AllocatorCache *ac = GetAllocatorCache(ms);
656       quarantine.Put(GetQuarantineCache(ms), QuarantineCallback(ac, stack), m,
657                      m->UsedSize());
658     } else {
659       SpinMutexLock l(&fallback_mutex);
660       AllocatorCache *ac = &fallback_allocator_cache;
661       quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac, stack),
662                      m, m->UsedSize());
663     }
664   }
665 
666   void Deallocate(void *ptr, uptr delete_size, uptr delete_alignment,
667                   BufferedStackTrace *stack, AllocType alloc_type) {
668     uptr p = reinterpret_cast<uptr>(ptr);
669     if (p == 0) return;
670 
671     uptr chunk_beg = p - kChunkHeaderSize;
672     AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
673 
674     // On Windows, uninstrumented DLLs may allocate memory before ASan hooks
675     // malloc. Don't report an invalid free in this case.
676     if (SANITIZER_WINDOWS &&
677         !get_allocator().PointerIsMine(ptr)) {
678       if (!IsSystemHeapAddress(p))
679         ReportFreeNotMalloced(p, stack);
680       return;
681     }
682 
683     ASAN_FREE_HOOK(ptr);
684 
685     // Must mark the chunk as quarantined before any changes to its metadata.
686     // Do not quarantine given chunk if we failed to set CHUNK_QUARANTINE flag.
687     if (!AtomicallySetQuarantineFlagIfAllocated(m, ptr, stack)) return;
688 
689     if (m->alloc_type != alloc_type) {
690       if (atomic_load(&alloc_dealloc_mismatch, memory_order_acquire)) {
691         ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type,
692                                 (AllocType)alloc_type);
693       }
694     } else {
695       if (flags()->new_delete_type_mismatch &&
696           (alloc_type == FROM_NEW || alloc_type == FROM_NEW_BR) &&
697           ((delete_size && delete_size != m->UsedSize()) ||
698            ComputeUserRequestedAlignmentLog(delete_alignment) !=
699                m->user_requested_alignment_log)) {
700         ReportNewDeleteTypeMismatch(p, delete_size, delete_alignment, stack);
701       }
702     }
703 
704     QuarantineChunk(m, ptr, stack);
705   }
706 
707   void *Reallocate(void *old_ptr, uptr new_size, BufferedStackTrace *stack) {
708     CHECK(old_ptr && new_size);
709     uptr p = reinterpret_cast<uptr>(old_ptr);
710     uptr chunk_beg = p - kChunkHeaderSize;
711     AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
712 
713     AsanStats &thread_stats = GetCurrentThreadStats();
714     thread_stats.reallocs++;
715     thread_stats.realloced += new_size;
716 
717     void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true);
718     if (new_ptr) {
719       u8 chunk_state = atomic_load(&m->chunk_state, memory_order_acquire);
720       if (chunk_state != CHUNK_ALLOCATED)
721         ReportInvalidFree(old_ptr, chunk_state, stack);
722       CHECK_NE(REAL(memcpy), nullptr);
723       uptr memcpy_size = Min(new_size, m->UsedSize());
724       // If realloc() races with free(), we may start copying freed memory.
725       // However, we will report racy double-free later anyway.
726       REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
727       Deallocate(old_ptr, 0, 0, stack, FROM_MALLOC);
728     }
729     return new_ptr;
730   }
731 
732   void *Calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
733     if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
734       if (AllocatorMayReturnNull())
735         return nullptr;
736       ReportCallocOverflow(nmemb, size, stack);
737     }
738     void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
739     // If the memory comes from the secondary allocator no need to clear it
740     // as it comes directly from mmap.
741     if (ptr && allocator.FromPrimary(ptr))
742       REAL(memset)(ptr, 0, nmemb * size);
743     return ptr;
744   }
745 
746   void ReportInvalidFree(void *ptr, u8 chunk_state, BufferedStackTrace *stack) {
747     if (chunk_state == CHUNK_QUARANTINE)
748       ReportDoubleFree((uptr)ptr, stack);
749     else
750       ReportFreeNotMalloced((uptr)ptr, stack);
751   }
752 
753   void CommitBack(AsanThreadLocalMallocStorage *ms, BufferedStackTrace *stack) {
754     AllocatorCache *ac = GetAllocatorCache(ms);
755     quarantine.Drain(GetQuarantineCache(ms), QuarantineCallback(ac, stack));
756     allocator.SwallowCache(ac);
757   }
758 
759   // -------------------------- Chunk lookup ----------------------
760 
761   // Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg).
762   // Returns nullptr if AsanChunk is not yet initialized just after
763   // get_allocator().Allocate(), or is being destroyed just before
764   // get_allocator().Deallocate().
765   AsanChunk *GetAsanChunk(void *alloc_beg) {
766     if (!alloc_beg)
767       return nullptr;
768     AsanChunk *p = reinterpret_cast<LargeChunkHeader *>(alloc_beg)->Get();
769     if (!p) {
770       if (!allocator.FromPrimary(alloc_beg))
771         return nullptr;
772       p = reinterpret_cast<AsanChunk *>(alloc_beg);
773     }
774     u8 state = atomic_load(&p->chunk_state, memory_order_relaxed);
775     // It does not guaranty that Chunk is initialized, but it's
776     // definitely not for any other value.
777     if (state == CHUNK_ALLOCATED || state == CHUNK_QUARANTINE)
778       return p;
779     return nullptr;
780   }
781 
782   AsanChunk *GetAsanChunkByAddr(uptr p) {
783     void *alloc_beg = allocator.GetBlockBegin(reinterpret_cast<void *>(p));
784     return GetAsanChunk(alloc_beg);
785   }
786 
787   // Allocator must be locked when this function is called.
788   AsanChunk *GetAsanChunkByAddrFastLocked(uptr p) {
789     void *alloc_beg =
790         allocator.GetBlockBeginFastLocked(reinterpret_cast<void *>(p));
791     return GetAsanChunk(alloc_beg);
792   }
793 
794   uptr AllocationSize(uptr p) {
795     AsanChunk *m = GetAsanChunkByAddr(p);
796     if (!m) return 0;
797     if (atomic_load(&m->chunk_state, memory_order_acquire) != CHUNK_ALLOCATED)
798       return 0;
799     if (m->Beg() != p) return 0;
800     return m->UsedSize();
801   }
802 
803   AsanChunkView FindHeapChunkByAddress(uptr addr) {
804     AsanChunk *m1 = GetAsanChunkByAddr(addr);
805     sptr offset = 0;
806     if (!m1 || AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) {
807       // The address is in the chunk's left redzone, so maybe it is actually
808       // a right buffer overflow from the other chunk to the left.
809       // Search a bit to the left to see if there is another chunk.
810       AsanChunk *m2 = nullptr;
811       for (uptr l = 1; l < GetPageSizeCached(); l++) {
812         m2 = GetAsanChunkByAddr(addr - l);
813         if (m2 == m1) continue;  // Still the same chunk.
814         break;
815       }
816       if (m2 && AsanChunkView(m2).AddrIsAtRight(addr, 1, &offset))
817         m1 = ChooseChunk(addr, m2, m1);
818     }
819     return AsanChunkView(m1);
820   }
821 
822   void Purge(BufferedStackTrace *stack) {
823     AsanThread *t = GetCurrentThread();
824     if (t) {
825       AsanThreadLocalMallocStorage *ms = &t->malloc_storage();
826       quarantine.DrainAndRecycle(GetQuarantineCache(ms),
827                                  QuarantineCallback(GetAllocatorCache(ms),
828                                                     stack));
829     }
830     {
831       SpinMutexLock l(&fallback_mutex);
832       quarantine.DrainAndRecycle(&fallback_quarantine_cache,
833                                  QuarantineCallback(&fallback_allocator_cache,
834                                                     stack));
835     }
836 
837     allocator.ForceReleaseToOS();
838   }
839 
840   void PrintStats() {
841     allocator.PrintStats();
842     quarantine.PrintStats();
843   }
844 
845   void ForceLock() ACQUIRE(fallback_mutex) {
846     allocator.ForceLock();
847     fallback_mutex.Lock();
848   }
849 
850   void ForceUnlock() RELEASE(fallback_mutex) {
851     fallback_mutex.Unlock();
852     allocator.ForceUnlock();
853   }
854 };
855 
856 static Allocator instance(LINKER_INITIALIZED);
857 
858 static AsanAllocator &get_allocator() {
859   return instance.allocator;
860 }
861 
862 bool AsanChunkView::IsValid() const {
863   return chunk_ && atomic_load(&chunk_->chunk_state, memory_order_relaxed) !=
864                        CHUNK_INVALID;
865 }
866 bool AsanChunkView::IsAllocated() const {
867   return chunk_ && atomic_load(&chunk_->chunk_state, memory_order_relaxed) ==
868                        CHUNK_ALLOCATED;
869 }
870 bool AsanChunkView::IsQuarantined() const {
871   return chunk_ && atomic_load(&chunk_->chunk_state, memory_order_relaxed) ==
872                        CHUNK_QUARANTINE;
873 }
874 uptr AsanChunkView::Beg() const { return chunk_->Beg(); }
875 uptr AsanChunkView::End() const { return Beg() + UsedSize(); }
876 uptr AsanChunkView::UsedSize() const { return chunk_->UsedSize(); }
877 u32 AsanChunkView::UserRequestedAlignment() const {
878   return Allocator::ComputeUserAlignment(chunk_->user_requested_alignment_log);
879 }
880 
881 uptr AsanChunkView::AllocTid() const {
882   u32 tid = 0;
883   u32 stack = 0;
884   chunk_->GetAllocContext(tid, stack);
885   return tid;
886 }
887 
888 uptr AsanChunkView::FreeTid() const {
889   if (!IsQuarantined())
890     return kInvalidTid;
891   u32 tid = 0;
892   u32 stack = 0;
893   chunk_->GetFreeContext(tid, stack);
894   return tid;
895 }
896 
897 AllocType AsanChunkView::GetAllocType() const {
898   return (AllocType)chunk_->alloc_type;
899 }
900 
901 u32 AsanChunkView::GetAllocStackId() const {
902   u32 tid = 0;
903   u32 stack = 0;
904   chunk_->GetAllocContext(tid, stack);
905   return stack;
906 }
907 
908 u32 AsanChunkView::GetFreeStackId() const {
909   if (!IsQuarantined())
910     return 0;
911   u32 tid = 0;
912   u32 stack = 0;
913   chunk_->GetFreeContext(tid, stack);
914   return stack;
915 }
916 
917 void InitializeAllocator(const AllocatorOptions &options) {
918   instance.InitLinkerInitialized(options);
919 }
920 
921 void ReInitializeAllocator(const AllocatorOptions &options) {
922   instance.ReInitialize(options);
923 }
924 
925 void GetAllocatorOptions(AllocatorOptions *options) {
926   instance.GetOptions(options);
927 }
928 
929 AsanChunkView FindHeapChunkByAddress(uptr addr) {
930   return instance.FindHeapChunkByAddress(addr);
931 }
932 AsanChunkView FindHeapChunkByAllocBeg(uptr addr) {
933   return AsanChunkView(instance.GetAsanChunk(reinterpret_cast<void*>(addr)));
934 }
935 
936 void AsanThreadLocalMallocStorage::CommitBack() {
937   GET_STACK_TRACE_MALLOC;
938   instance.CommitBack(this, &stack);
939 }
940 
941 void PrintInternalAllocatorStats() {
942   instance.PrintStats();
943 }
944 
945 void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) {
946   instance.Deallocate(ptr, 0, 0, stack, alloc_type);
947 }
948 
949 void asan_delete(void *ptr, uptr size, uptr alignment,
950                  BufferedStackTrace *stack, AllocType alloc_type) {
951   instance.Deallocate(ptr, size, alignment, stack, alloc_type);
952 }
953 
954 void *asan_malloc(uptr size, BufferedStackTrace *stack) {
955   return SetErrnoOnNull(instance.Allocate(size, 8, stack, FROM_MALLOC, true));
956 }
957 
958 void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
959   return SetErrnoOnNull(instance.Calloc(nmemb, size, stack));
960 }
961 
962 void *asan_reallocarray(void *p, uptr nmemb, uptr size,
963                         BufferedStackTrace *stack) {
964   if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
965     errno = errno_ENOMEM;
966     if (AllocatorMayReturnNull())
967       return nullptr;
968     ReportReallocArrayOverflow(nmemb, size, stack);
969   }
970   return asan_realloc(p, nmemb * size, stack);
971 }
972 
973 void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) {
974   if (!p)
975     return SetErrnoOnNull(instance.Allocate(size, 8, stack, FROM_MALLOC, true));
976   if (size == 0) {
977     if (flags()->allocator_frees_and_returns_null_on_realloc_zero) {
978       instance.Deallocate(p, 0, 0, stack, FROM_MALLOC);
979       return nullptr;
980     }
981     // Allocate a size of 1 if we shouldn't free() on Realloc to 0
982     size = 1;
983   }
984   return SetErrnoOnNull(instance.Reallocate(p, size, stack));
985 }
986 
987 void *asan_valloc(uptr size, BufferedStackTrace *stack) {
988   return SetErrnoOnNull(
989       instance.Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true));
990 }
991 
992 void *asan_pvalloc(uptr size, BufferedStackTrace *stack) {
993   uptr PageSize = GetPageSizeCached();
994   if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) {
995     errno = errno_ENOMEM;
996     if (AllocatorMayReturnNull())
997       return nullptr;
998     ReportPvallocOverflow(size, stack);
999   }
1000   // pvalloc(0) should allocate one page.
1001   size = size ? RoundUpTo(size, PageSize) : PageSize;
1002   return SetErrnoOnNull(
1003       instance.Allocate(size, PageSize, stack, FROM_MALLOC, true));
1004 }
1005 
1006 void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
1007                     AllocType alloc_type) {
1008   if (UNLIKELY(!IsPowerOfTwo(alignment))) {
1009     errno = errno_EINVAL;
1010     if (AllocatorMayReturnNull())
1011       return nullptr;
1012     ReportInvalidAllocationAlignment(alignment, stack);
1013   }
1014   return SetErrnoOnNull(
1015       instance.Allocate(size, alignment, stack, alloc_type, true));
1016 }
1017 
1018 void *asan_aligned_alloc(uptr alignment, uptr size, BufferedStackTrace *stack) {
1019   if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) {
1020     errno = errno_EINVAL;
1021     if (AllocatorMayReturnNull())
1022       return nullptr;
1023     ReportInvalidAlignedAllocAlignment(size, alignment, stack);
1024   }
1025   return SetErrnoOnNull(
1026       instance.Allocate(size, alignment, stack, FROM_MALLOC, true));
1027 }
1028 
1029 int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
1030                         BufferedStackTrace *stack) {
1031   if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) {
1032     if (AllocatorMayReturnNull())
1033       return errno_EINVAL;
1034     ReportInvalidPosixMemalignAlignment(alignment, stack);
1035   }
1036   void *ptr = instance.Allocate(size, alignment, stack, FROM_MALLOC, true);
1037   if (UNLIKELY(!ptr))
1038     // OOM error is already taken care of by Allocate.
1039     return errno_ENOMEM;
1040   CHECK(IsAligned((uptr)ptr, alignment));
1041   *memptr = ptr;
1042   return 0;
1043 }
1044 
1045 uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp) {
1046   if (!ptr) return 0;
1047   uptr usable_size = instance.AllocationSize(reinterpret_cast<uptr>(ptr));
1048   if (flags()->check_malloc_usable_size && (usable_size == 0)) {
1049     GET_STACK_TRACE_FATAL(pc, bp);
1050     ReportMallocUsableSizeNotOwned((uptr)ptr, &stack);
1051   }
1052   return usable_size;
1053 }
1054 
1055 uptr asan_mz_size(const void *ptr) {
1056   return instance.AllocationSize(reinterpret_cast<uptr>(ptr));
1057 }
1058 
1059 void asan_mz_force_lock() NO_THREAD_SAFETY_ANALYSIS { instance.ForceLock(); }
1060 
1061 void asan_mz_force_unlock() NO_THREAD_SAFETY_ANALYSIS {
1062   instance.ForceUnlock();
1063 }
1064 
1065 }  // namespace __asan
1066 
1067 // --- Implementation of LSan-specific functions --- {{{1
1068 namespace __lsan {
1069 void LockAllocator() {
1070   __asan::get_allocator().ForceLock();
1071 }
1072 
1073 void UnlockAllocator() {
1074   __asan::get_allocator().ForceUnlock();
1075 }
1076 
1077 void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
1078   *begin = (uptr)&__asan::get_allocator();
1079   *end = *begin + sizeof(__asan::get_allocator());
1080 }
1081 
1082 uptr PointsIntoChunk(void *p) {
1083   uptr addr = reinterpret_cast<uptr>(p);
1084   __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(addr);
1085   if (!m || atomic_load(&m->chunk_state, memory_order_acquire) !=
1086                 __asan::CHUNK_ALLOCATED)
1087     return 0;
1088   uptr chunk = m->Beg();
1089   if (m->AddrIsInside(addr))
1090     return chunk;
1091   if (IsSpecialCaseOfOperatorNew0(chunk, m->UsedSize(), addr))
1092     return chunk;
1093   return 0;
1094 }
1095 
1096 uptr GetUserBegin(uptr chunk) {
1097   __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(chunk);
1098   return m ? m->Beg() : 0;
1099 }
1100 
1101 LsanMetadata::LsanMetadata(uptr chunk) {
1102   metadata_ = chunk ? reinterpret_cast<void *>(chunk - __asan::kChunkHeaderSize)
1103                     : nullptr;
1104 }
1105 
1106 bool LsanMetadata::allocated() const {
1107   if (!metadata_)
1108     return false;
1109   __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
1110   return atomic_load(&m->chunk_state, memory_order_relaxed) ==
1111          __asan::CHUNK_ALLOCATED;
1112 }
1113 
1114 ChunkTag LsanMetadata::tag() const {
1115   __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
1116   return static_cast<ChunkTag>(m->lsan_tag);
1117 }
1118 
1119 void LsanMetadata::set_tag(ChunkTag value) {
1120   __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
1121   m->lsan_tag = value;
1122 }
1123 
1124 uptr LsanMetadata::requested_size() const {
1125   __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
1126   return m->UsedSize();
1127 }
1128 
1129 u32 LsanMetadata::stack_trace_id() const {
1130   __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
1131   u32 tid = 0;
1132   u32 stack = 0;
1133   m->GetAllocContext(tid, stack);
1134   return stack;
1135 }
1136 
1137 void ForEachChunk(ForEachChunkCallback callback, void *arg) {
1138   __asan::get_allocator().ForEachChunk(callback, arg);
1139 }
1140 
1141 IgnoreObjectResult IgnoreObjectLocked(const void *p) {
1142   uptr addr = reinterpret_cast<uptr>(p);
1143   __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddr(addr);
1144   if (!m ||
1145       (atomic_load(&m->chunk_state, memory_order_acquire) !=
1146        __asan::CHUNK_ALLOCATED) ||
1147       !m->AddrIsInside(addr)) {
1148     return kIgnoreObjectInvalid;
1149   }
1150   if (m->lsan_tag == kIgnored)
1151     return kIgnoreObjectAlreadyIgnored;
1152   m->lsan_tag = __lsan::kIgnored;
1153   return kIgnoreObjectSuccess;
1154 }
1155 
1156 void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
1157   // Look for the arg pointer of threads that have been created or are running.
1158   // This is necessary to prevent false positive leaks due to the AsanThread
1159   // holding the only live reference to a heap object.  This can happen because
1160   // the `pthread_create()` interceptor doesn't wait for the child thread to
1161   // start before returning and thus loosing the the only live reference to the
1162   // heap object on the stack.
1163 
1164   __asan::AsanThreadContext *atctx =
1165       reinterpret_cast<__asan::AsanThreadContext *>(tctx);
1166   __asan::AsanThread *asan_thread = atctx->thread;
1167 
1168   // Note ThreadStatusRunning is required because there is a small window where
1169   // the thread status switches to `ThreadStatusRunning` but the `arg` pointer
1170   // still isn't on the stack yet.
1171   if (atctx->status != ThreadStatusCreated &&
1172       atctx->status != ThreadStatusRunning)
1173     return;
1174 
1175   uptr thread_arg = reinterpret_cast<uptr>(asan_thread->get_arg());
1176   if (!thread_arg)
1177     return;
1178 
1179   auto ptrsVec = reinterpret_cast<InternalMmapVector<uptr> *>(ptrs);
1180   ptrsVec->push_back(thread_arg);
1181 }
1182 
1183 }  // namespace __lsan
1184 
1185 // ---------------------- Interface ---------------- {{{1
1186 using namespace __asan;
1187 
1188 // ASan allocator doesn't reserve extra bytes, so normally we would
1189 // just return "size". We don't want to expose our redzone sizes, etc here.
1190 uptr __sanitizer_get_estimated_allocated_size(uptr size) {
1191   return size;
1192 }
1193 
1194 int __sanitizer_get_ownership(const void *p) {
1195   uptr ptr = reinterpret_cast<uptr>(p);
1196   return instance.AllocationSize(ptr) > 0;
1197 }
1198 
1199 uptr __sanitizer_get_allocated_size(const void *p) {
1200   if (!p) return 0;
1201   uptr ptr = reinterpret_cast<uptr>(p);
1202   uptr allocated_size = instance.AllocationSize(ptr);
1203   // Die if p is not malloced or if it is already freed.
1204   if (allocated_size == 0) {
1205     GET_STACK_TRACE_FATAL_HERE;
1206     ReportSanitizerGetAllocatedSizeNotOwned(ptr, &stack);
1207   }
1208   return allocated_size;
1209 }
1210 
1211 void __sanitizer_purge_allocator() {
1212   GET_STACK_TRACE_MALLOC;
1213   instance.Purge(&stack);
1214 }
1215 
1216 int __asan_update_allocation_context(void* addr) {
1217   GET_STACK_TRACE_MALLOC;
1218   return instance.UpdateAllocationStack((uptr)addr, &stack);
1219 }
1220 
1221 #if !SANITIZER_SUPPORTS_WEAK_HOOKS
1222 // Provide default (no-op) implementation of malloc hooks.
1223 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook,
1224                              void *ptr, uptr size) {
1225   (void)ptr;
1226   (void)size;
1227 }
1228 
1229 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook, void *ptr) {
1230   (void)ptr;
1231 }
1232 #endif
1233