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