Home | History | Annotate | Line # | Download | only in hwasan
      1  1.1  mrg //===-- hwasan_allocator.cpp ------------------------ ---------------------===//
      2  1.1  mrg //
      3  1.1  mrg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4  1.1  mrg // See https://llvm.org/LICENSE.txt for license information.
      5  1.1  mrg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6  1.1  mrg //
      7  1.1  mrg //===----------------------------------------------------------------------===//
      8  1.1  mrg //
      9  1.1  mrg // This file is a part of HWAddressSanitizer.
     10  1.1  mrg //
     11  1.1  mrg // HWAddressSanitizer allocator.
     12  1.1  mrg //===----------------------------------------------------------------------===//
     13  1.1  mrg 
     14  1.1  mrg #include "sanitizer_common/sanitizer_atomic.h"
     15  1.1  mrg #include "sanitizer_common/sanitizer_errno.h"
     16  1.1  mrg #include "sanitizer_common/sanitizer_stackdepot.h"
     17  1.1  mrg #include "hwasan.h"
     18  1.1  mrg #include "hwasan_allocator.h"
     19  1.1  mrg #include "hwasan_checks.h"
     20  1.1  mrg #include "hwasan_mapping.h"
     21  1.1  mrg #include "hwasan_malloc_bisect.h"
     22  1.1  mrg #include "hwasan_thread.h"
     23  1.1  mrg #include "hwasan_report.h"
     24  1.1  mrg 
     25  1.1  mrg namespace __hwasan {
     26  1.1  mrg 
     27  1.1  mrg static Allocator allocator;
     28  1.1  mrg static AllocatorCache fallback_allocator_cache;
     29  1.1  mrg static SpinMutex fallback_mutex;
     30  1.1  mrg static atomic_uint8_t hwasan_allocator_tagging_enabled;
     31  1.1  mrg 
     32  1.1  mrg static constexpr tag_t kFallbackAllocTag = 0xBB & kTagMask;
     33  1.1  mrg static constexpr tag_t kFallbackFreeTag = 0xBC;
     34  1.1  mrg 
     35  1.1  mrg enum RightAlignMode {
     36  1.1  mrg   kRightAlignNever,
     37  1.1  mrg   kRightAlignSometimes,
     38  1.1  mrg   kRightAlignAlways
     39  1.1  mrg };
     40  1.1  mrg 
     41  1.1  mrg // Initialized in HwasanAllocatorInit, an never changed.
     42  1.1  mrg static ALIGNED(16) u8 tail_magic[kShadowAlignment - 1];
     43  1.1  mrg 
     44  1.1  mrg bool HwasanChunkView::IsAllocated() const {
     45  1.1  mrg   return metadata_ && metadata_->alloc_context_id &&
     46  1.1  mrg          metadata_->get_requested_size();
     47  1.1  mrg }
     48  1.1  mrg 
     49  1.1  mrg // Aligns the 'addr' right to the granule boundary.
     50  1.1  mrg static uptr AlignRight(uptr addr, uptr requested_size) {
     51  1.1  mrg   uptr tail_size = requested_size % kShadowAlignment;
     52  1.1  mrg   if (!tail_size) return addr;
     53  1.1  mrg   return addr + kShadowAlignment - tail_size;
     54  1.1  mrg }
     55  1.1  mrg 
     56  1.1  mrg uptr HwasanChunkView::Beg() const {
     57  1.1  mrg   if (metadata_ && metadata_->right_aligned)
     58  1.1  mrg     return AlignRight(block_, metadata_->get_requested_size());
     59  1.1  mrg   return block_;
     60  1.1  mrg }
     61  1.1  mrg uptr HwasanChunkView::End() const {
     62  1.1  mrg   return Beg() + UsedSize();
     63  1.1  mrg }
     64  1.1  mrg uptr HwasanChunkView::UsedSize() const {
     65  1.1  mrg   return metadata_->get_requested_size();
     66  1.1  mrg }
     67  1.1  mrg u32 HwasanChunkView::GetAllocStackId() const {
     68  1.1  mrg   return metadata_->alloc_context_id;
     69  1.1  mrg }
     70  1.1  mrg 
     71  1.1  mrg uptr HwasanChunkView::ActualSize() const {
     72  1.1  mrg   return allocator.GetActuallyAllocatedSize(reinterpret_cast<void *>(block_));
     73  1.1  mrg }
     74  1.1  mrg 
     75  1.1  mrg bool HwasanChunkView::FromSmallHeap() const {
     76  1.1  mrg   return allocator.FromPrimary(reinterpret_cast<void *>(block_));
     77  1.1  mrg }
     78  1.1  mrg 
     79  1.1  mrg void GetAllocatorStats(AllocatorStatCounters s) {
     80  1.1  mrg   allocator.GetStats(s);
     81  1.1  mrg }
     82  1.1  mrg 
     83  1.1  mrg uptr GetAliasRegionStart() {
     84  1.1  mrg #if defined(HWASAN_ALIASING_MODE)
     85  1.1  mrg   constexpr uptr kAliasRegionOffset = 1ULL << (kTaggableRegionCheckShift - 1);
     86  1.1  mrg   uptr AliasRegionStart =
     87  1.1  mrg       __hwasan_shadow_memory_dynamic_address + kAliasRegionOffset;
     88  1.1  mrg 
     89  1.1  mrg   CHECK_EQ(AliasRegionStart >> kTaggableRegionCheckShift,
     90  1.1  mrg            __hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
     91  1.1  mrg   CHECK_EQ(
     92  1.1  mrg       (AliasRegionStart + kAliasRegionOffset - 1) >> kTaggableRegionCheckShift,
     93  1.1  mrg       __hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
     94  1.1  mrg   return AliasRegionStart;
     95  1.1  mrg #else
     96  1.1  mrg   return 0;
     97  1.1  mrg #endif
     98  1.1  mrg }
     99  1.1  mrg 
    100  1.1  mrg void HwasanAllocatorInit() {
    101  1.1  mrg   atomic_store_relaxed(&hwasan_allocator_tagging_enabled,
    102  1.1  mrg                        !flags()->disable_allocator_tagging);
    103  1.1  mrg   SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
    104  1.1  mrg   allocator.Init(common_flags()->allocator_release_to_os_interval_ms,
    105  1.1  mrg                  GetAliasRegionStart());
    106  1.1  mrg   for (uptr i = 0; i < sizeof(tail_magic); i++)
    107  1.1  mrg     tail_magic[i] = GetCurrentThread()->GenerateRandomTag();
    108  1.1  mrg }
    109  1.1  mrg 
    110  1.1  mrg void HwasanAllocatorLock() { allocator.ForceLock(); }
    111  1.1  mrg 
    112  1.1  mrg void HwasanAllocatorUnlock() { allocator.ForceUnlock(); }
    113  1.1  mrg 
    114  1.1  mrg void AllocatorSwallowThreadLocalCache(AllocatorCache *cache) {
    115  1.1  mrg   allocator.SwallowCache(cache);
    116  1.1  mrg }
    117  1.1  mrg 
    118  1.1  mrg static uptr TaggedSize(uptr size) {
    119  1.1  mrg   if (!size) size = 1;
    120  1.1  mrg   uptr new_size = RoundUpTo(size, kShadowAlignment);
    121  1.1  mrg   CHECK_GE(new_size, size);
    122  1.1  mrg   return new_size;
    123  1.1  mrg }
    124  1.1  mrg 
    125  1.1  mrg static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
    126  1.1  mrg                             bool zeroise) {
    127  1.1  mrg   if (orig_size > kMaxAllowedMallocSize) {
    128  1.1  mrg     if (AllocatorMayReturnNull()) {
    129  1.1  mrg       Report("WARNING: HWAddressSanitizer failed to allocate 0x%zx bytes\n",
    130  1.1  mrg              orig_size);
    131  1.1  mrg       return nullptr;
    132  1.1  mrg     }
    133  1.1  mrg     ReportAllocationSizeTooBig(orig_size, kMaxAllowedMallocSize, stack);
    134  1.1  mrg   }
    135  1.1  mrg 
    136  1.1  mrg   alignment = Max(alignment, kShadowAlignment);
    137  1.1  mrg   uptr size = TaggedSize(orig_size);
    138  1.1  mrg   Thread *t = GetCurrentThread();
    139  1.1  mrg   void *allocated;
    140  1.1  mrg   if (t) {
    141  1.1  mrg     allocated = allocator.Allocate(t->allocator_cache(), size, alignment);
    142  1.1  mrg   } else {
    143  1.1  mrg     SpinMutexLock l(&fallback_mutex);
    144  1.1  mrg     AllocatorCache *cache = &fallback_allocator_cache;
    145  1.1  mrg     allocated = allocator.Allocate(cache, size, alignment);
    146  1.1  mrg   }
    147  1.1  mrg   if (UNLIKELY(!allocated)) {
    148  1.1  mrg     SetAllocatorOutOfMemory();
    149  1.1  mrg     if (AllocatorMayReturnNull())
    150  1.1  mrg       return nullptr;
    151  1.1  mrg     ReportOutOfMemory(size, stack);
    152  1.1  mrg   }
    153  1.1  mrg   Metadata *meta =
    154  1.1  mrg       reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));
    155  1.1  mrg   meta->set_requested_size(orig_size);
    156  1.1  mrg   meta->alloc_context_id = StackDepotPut(*stack);
    157  1.1  mrg   meta->right_aligned = false;
    158  1.1  mrg   if (zeroise) {
    159  1.1  mrg     internal_memset(allocated, 0, size);
    160  1.1  mrg   } else if (flags()->max_malloc_fill_size > 0) {
    161  1.1  mrg     uptr fill_size = Min(size, (uptr)flags()->max_malloc_fill_size);
    162  1.1  mrg     internal_memset(allocated, flags()->malloc_fill_byte, fill_size);
    163  1.1  mrg   }
    164  1.1  mrg   if (size != orig_size) {
    165  1.1  mrg     u8 *tail = reinterpret_cast<u8 *>(allocated) + orig_size;
    166  1.1  mrg     uptr tail_length = size - orig_size;
    167  1.1  mrg     internal_memcpy(tail, tail_magic, tail_length - 1);
    168  1.1  mrg     // Short granule is excluded from magic tail, so we explicitly untag.
    169  1.1  mrg     tail[tail_length - 1] = 0;
    170  1.1  mrg   }
    171  1.1  mrg 
    172  1.1  mrg   void *user_ptr = allocated;
    173  1.1  mrg   // Tagging can only be skipped when both tag_in_malloc and tag_in_free are
    174  1.1  mrg   // false. When tag_in_malloc = false and tag_in_free = true malloc needs to
    175  1.1  mrg   // retag to 0.
    176  1.1  mrg   if (InTaggableRegion(reinterpret_cast<uptr>(user_ptr)) &&
    177  1.1  mrg       (flags()->tag_in_malloc || flags()->tag_in_free) &&
    178  1.1  mrg       atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) {
    179  1.1  mrg     if (flags()->tag_in_malloc && malloc_bisect(stack, orig_size)) {
    180  1.1  mrg       tag_t tag = t ? t->GenerateRandomTag() : kFallbackAllocTag;
    181  1.1  mrg       uptr tag_size = orig_size ? orig_size : 1;
    182  1.1  mrg       uptr full_granule_size = RoundDownTo(tag_size, kShadowAlignment);
    183  1.1  mrg       user_ptr =
    184  1.1  mrg           (void *)TagMemoryAligned((uptr)user_ptr, full_granule_size, tag);
    185  1.1  mrg       if (full_granule_size != tag_size) {
    186  1.1  mrg         u8 *short_granule =
    187  1.1  mrg             reinterpret_cast<u8 *>(allocated) + full_granule_size;
    188  1.1  mrg         TagMemoryAligned((uptr)short_granule, kShadowAlignment,
    189  1.1  mrg                          tag_size % kShadowAlignment);
    190  1.1  mrg         short_granule[kShadowAlignment - 1] = tag;
    191  1.1  mrg       }
    192  1.1  mrg     } else {
    193  1.1  mrg       user_ptr = (void *)TagMemoryAligned((uptr)user_ptr, size, 0);
    194  1.1  mrg     }
    195  1.1  mrg   }
    196  1.1  mrg 
    197  1.1  mrg   HWASAN_MALLOC_HOOK(user_ptr, size);
    198  1.1  mrg   return user_ptr;
    199  1.1  mrg }
    200  1.1  mrg 
    201  1.1  mrg static bool PointerAndMemoryTagsMatch(void *tagged_ptr) {
    202  1.1  mrg   CHECK(tagged_ptr);
    203  1.1  mrg   uptr tagged_uptr = reinterpret_cast<uptr>(tagged_ptr);
    204  1.1  mrg   if (!InTaggableRegion(tagged_uptr))
    205  1.1  mrg     return true;
    206  1.1  mrg   tag_t mem_tag = *reinterpret_cast<tag_t *>(
    207  1.1  mrg       MemToShadow(reinterpret_cast<uptr>(UntagPtr(tagged_ptr))));
    208  1.1  mrg   return PossiblyShortTagMatches(mem_tag, tagged_uptr, 1);
    209  1.1  mrg }
    210  1.1  mrg 
    211  1.1  mrg static bool CheckInvalidFree(StackTrace *stack, void *untagged_ptr,
    212  1.1  mrg                              void *tagged_ptr) {
    213  1.1  mrg   // This function can return true if halt_on_error is false.
    214  1.1  mrg   if (!MemIsApp(reinterpret_cast<uptr>(untagged_ptr)) ||
    215  1.1  mrg       !PointerAndMemoryTagsMatch(tagged_ptr)) {
    216  1.1  mrg     ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr));
    217  1.1  mrg     return true;
    218  1.1  mrg   }
    219  1.1  mrg   return false;
    220  1.1  mrg }
    221  1.1  mrg 
    222  1.1  mrg static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
    223  1.1  mrg   CHECK(tagged_ptr);
    224  1.1  mrg   HWASAN_FREE_HOOK(tagged_ptr);
    225  1.1  mrg 
    226  1.1  mrg   bool in_taggable_region =
    227  1.1  mrg       InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr));
    228  1.1  mrg   void *untagged_ptr = in_taggable_region ? UntagPtr(tagged_ptr) : tagged_ptr;
    229  1.1  mrg 
    230  1.1  mrg   if (CheckInvalidFree(stack, untagged_ptr, tagged_ptr))
    231  1.1  mrg     return;
    232  1.1  mrg 
    233  1.1  mrg   void *aligned_ptr = reinterpret_cast<void *>(
    234  1.1  mrg       RoundDownTo(reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment));
    235  1.1  mrg   tag_t pointer_tag = GetTagFromPointer(reinterpret_cast<uptr>(tagged_ptr));
    236  1.1  mrg   Metadata *meta =
    237  1.1  mrg       reinterpret_cast<Metadata *>(allocator.GetMetaData(aligned_ptr));
    238  1.1  mrg   if (!meta) {
    239  1.1  mrg     ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr));
    240  1.1  mrg     return;
    241  1.1  mrg   }
    242  1.1  mrg   uptr orig_size = meta->get_requested_size();
    243  1.1  mrg   u32 free_context_id = StackDepotPut(*stack);
    244  1.1  mrg   u32 alloc_context_id = meta->alloc_context_id;
    245  1.1  mrg 
    246  1.1  mrg   // Check tail magic.
    247  1.1  mrg   uptr tagged_size = TaggedSize(orig_size);
    248  1.1  mrg   if (flags()->free_checks_tail_magic && orig_size &&
    249  1.1  mrg       tagged_size != orig_size) {
    250  1.1  mrg     uptr tail_size = tagged_size - orig_size - 1;
    251  1.1  mrg     CHECK_LT(tail_size, kShadowAlignment);
    252  1.1  mrg     void *tail_beg = reinterpret_cast<void *>(
    253  1.1  mrg         reinterpret_cast<uptr>(aligned_ptr) + orig_size);
    254  1.1  mrg     tag_t short_granule_memtag = *(reinterpret_cast<tag_t *>(
    255  1.1  mrg         reinterpret_cast<uptr>(tail_beg) + tail_size));
    256  1.1  mrg     if (tail_size &&
    257  1.1  mrg         (internal_memcmp(tail_beg, tail_magic, tail_size) ||
    258  1.1  mrg          (in_taggable_region && pointer_tag != short_granule_memtag)))
    259  1.1  mrg       ReportTailOverwritten(stack, reinterpret_cast<uptr>(tagged_ptr),
    260  1.1  mrg                             orig_size, tail_magic);
    261  1.1  mrg   }
    262  1.1  mrg 
    263  1.1  mrg   meta->set_requested_size(0);
    264  1.1  mrg   meta->alloc_context_id = 0;
    265  1.1  mrg   // This memory will not be reused by anyone else, so we are free to keep it
    266  1.1  mrg   // poisoned.
    267  1.1  mrg   Thread *t = GetCurrentThread();
    268  1.1  mrg   if (flags()->max_free_fill_size > 0) {
    269  1.1  mrg     uptr fill_size =
    270  1.1  mrg         Min(TaggedSize(orig_size), (uptr)flags()->max_free_fill_size);
    271  1.1  mrg     internal_memset(aligned_ptr, flags()->free_fill_byte, fill_size);
    272  1.1  mrg   }
    273  1.1  mrg   if (in_taggable_region && flags()->tag_in_free && malloc_bisect(stack, 0) &&
    274  1.1  mrg       atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) {
    275  1.1  mrg     // Always store full 8-bit tags on free to maximize UAF detection.
    276  1.1  mrg     tag_t tag;
    277  1.1  mrg     if (t) {
    278  1.1  mrg       // Make sure we are not using a short granule tag as a poison tag. This
    279  1.1  mrg       // would make us attempt to read the memory on a UaF.
    280  1.1  mrg       // The tag can be zero if tagging is disabled on this thread.
    281  1.1  mrg       do {
    282  1.1  mrg         tag = t->GenerateRandomTag(/*num_bits=*/8);
    283  1.1  mrg       } while (
    284  1.1  mrg           UNLIKELY((tag < kShadowAlignment || tag == pointer_tag) && tag != 0));
    285  1.1  mrg     } else {
    286  1.1  mrg       static_assert(kFallbackFreeTag >= kShadowAlignment,
    287  1.1  mrg                     "fallback tag must not be a short granule tag.");
    288  1.1  mrg       tag = kFallbackFreeTag;
    289  1.1  mrg     }
    290  1.1  mrg     TagMemoryAligned(reinterpret_cast<uptr>(aligned_ptr), TaggedSize(orig_size),
    291  1.1  mrg                      tag);
    292  1.1  mrg   }
    293  1.1  mrg   if (t) {
    294  1.1  mrg     allocator.Deallocate(t->allocator_cache(), aligned_ptr);
    295  1.1  mrg     if (auto *ha = t->heap_allocations())
    296  1.1  mrg       ha->push({reinterpret_cast<uptr>(tagged_ptr), alloc_context_id,
    297  1.1  mrg                 free_context_id, static_cast<u32>(orig_size)});
    298  1.1  mrg   } else {
    299  1.1  mrg     SpinMutexLock l(&fallback_mutex);
    300  1.1  mrg     AllocatorCache *cache = &fallback_allocator_cache;
    301  1.1  mrg     allocator.Deallocate(cache, aligned_ptr);
    302  1.1  mrg   }
    303  1.1  mrg }
    304  1.1  mrg 
    305  1.1  mrg static void *HwasanReallocate(StackTrace *stack, void *tagged_ptr_old,
    306  1.1  mrg                               uptr new_size, uptr alignment) {
    307  1.1  mrg   void *untagged_ptr_old =
    308  1.1  mrg       InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr_old))
    309  1.1  mrg           ? UntagPtr(tagged_ptr_old)
    310  1.1  mrg           : tagged_ptr_old;
    311  1.1  mrg   if (CheckInvalidFree(stack, untagged_ptr_old, tagged_ptr_old))
    312  1.1  mrg     return nullptr;
    313  1.1  mrg   void *tagged_ptr_new =
    314  1.1  mrg       HwasanAllocate(stack, new_size, alignment, false /*zeroise*/);
    315  1.1  mrg   if (tagged_ptr_old && tagged_ptr_new) {
    316  1.1  mrg     Metadata *meta =
    317  1.1  mrg         reinterpret_cast<Metadata *>(allocator.GetMetaData(untagged_ptr_old));
    318  1.1  mrg     internal_memcpy(
    319  1.1  mrg         UntagPtr(tagged_ptr_new), untagged_ptr_old,
    320  1.1  mrg         Min(new_size, static_cast<uptr>(meta->get_requested_size())));
    321  1.1  mrg     HwasanDeallocate(stack, tagged_ptr_old);
    322  1.1  mrg   }
    323  1.1  mrg   return tagged_ptr_new;
    324  1.1  mrg }
    325  1.1  mrg 
    326  1.1  mrg static void *HwasanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
    327  1.1  mrg   if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
    328  1.1  mrg     if (AllocatorMayReturnNull())
    329  1.1  mrg       return nullptr;
    330  1.1  mrg     ReportCallocOverflow(nmemb, size, stack);
    331  1.1  mrg   }
    332  1.1  mrg   return HwasanAllocate(stack, nmemb * size, sizeof(u64), true);
    333  1.1  mrg }
    334  1.1  mrg 
    335  1.1  mrg HwasanChunkView FindHeapChunkByAddress(uptr address) {
    336  1.1  mrg   if (!allocator.PointerIsMine(reinterpret_cast<void *>(address)))
    337  1.1  mrg     return HwasanChunkView();
    338  1.1  mrg   void *block = allocator.GetBlockBegin(reinterpret_cast<void*>(address));
    339  1.1  mrg   if (!block)
    340  1.1  mrg     return HwasanChunkView();
    341  1.1  mrg   Metadata *metadata =
    342  1.1  mrg       reinterpret_cast<Metadata*>(allocator.GetMetaData(block));
    343  1.1  mrg   return HwasanChunkView(reinterpret_cast<uptr>(block), metadata);
    344  1.1  mrg }
    345  1.1  mrg 
    346  1.1  mrg static uptr AllocationSize(const void *tagged_ptr) {
    347  1.1  mrg   const void *untagged_ptr = UntagPtr(tagged_ptr);
    348  1.1  mrg   if (!untagged_ptr) return 0;
    349  1.1  mrg   const void *beg = allocator.GetBlockBegin(untagged_ptr);
    350  1.1  mrg   Metadata *b = (Metadata *)allocator.GetMetaData(untagged_ptr);
    351  1.1  mrg   if (b->right_aligned) {
    352  1.1  mrg     if (beg != reinterpret_cast<void *>(RoundDownTo(
    353  1.1  mrg                    reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment)))
    354  1.1  mrg       return 0;
    355  1.1  mrg   } else {
    356  1.1  mrg     if (beg != untagged_ptr) return 0;
    357  1.1  mrg   }
    358  1.1  mrg   return b->get_requested_size();
    359  1.1  mrg }
    360  1.1  mrg 
    361  1.1  mrg void *hwasan_malloc(uptr size, StackTrace *stack) {
    362  1.1  mrg   return SetErrnoOnNull(HwasanAllocate(stack, size, sizeof(u64), false));
    363  1.1  mrg }
    364  1.1  mrg 
    365  1.1  mrg void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
    366  1.1  mrg   return SetErrnoOnNull(HwasanCalloc(stack, nmemb, size));
    367  1.1  mrg }
    368  1.1  mrg 
    369  1.1  mrg void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack) {
    370  1.1  mrg   if (!ptr)
    371  1.1  mrg     return SetErrnoOnNull(HwasanAllocate(stack, size, sizeof(u64), false));
    372  1.1  mrg   if (size == 0) {
    373  1.1  mrg     HwasanDeallocate(stack, ptr);
    374  1.1  mrg     return nullptr;
    375  1.1  mrg   }
    376  1.1  mrg   return SetErrnoOnNull(HwasanReallocate(stack, ptr, size, sizeof(u64)));
    377  1.1  mrg }
    378  1.1  mrg 
    379  1.1  mrg void *hwasan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack) {
    380  1.1  mrg   if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
    381  1.1  mrg     errno = errno_ENOMEM;
    382  1.1  mrg     if (AllocatorMayReturnNull())
    383  1.1  mrg       return nullptr;
    384  1.1  mrg     ReportReallocArrayOverflow(nmemb, size, stack);
    385  1.1  mrg   }
    386  1.1  mrg   return hwasan_realloc(ptr, nmemb * size, stack);
    387  1.1  mrg }
    388  1.1  mrg 
    389  1.1  mrg void *hwasan_valloc(uptr size, StackTrace *stack) {
    390  1.1  mrg   return SetErrnoOnNull(
    391  1.1  mrg       HwasanAllocate(stack, size, GetPageSizeCached(), false));
    392  1.1  mrg }
    393  1.1  mrg 
    394  1.1  mrg void *hwasan_pvalloc(uptr size, StackTrace *stack) {
    395  1.1  mrg   uptr PageSize = GetPageSizeCached();
    396  1.1  mrg   if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) {
    397  1.1  mrg     errno = errno_ENOMEM;
    398  1.1  mrg     if (AllocatorMayReturnNull())
    399  1.1  mrg       return nullptr;
    400  1.1  mrg     ReportPvallocOverflow(size, stack);
    401  1.1  mrg   }
    402  1.1  mrg   // pvalloc(0) should allocate one page.
    403  1.1  mrg   size = size ? RoundUpTo(size, PageSize) : PageSize;
    404  1.1  mrg   return SetErrnoOnNull(HwasanAllocate(stack, size, PageSize, false));
    405  1.1  mrg }
    406  1.1  mrg 
    407  1.1  mrg void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) {
    408  1.1  mrg   if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) {
    409  1.1  mrg     errno = errno_EINVAL;
    410  1.1  mrg     if (AllocatorMayReturnNull())
    411  1.1  mrg       return nullptr;
    412  1.1  mrg     ReportInvalidAlignedAllocAlignment(size, alignment, stack);
    413  1.1  mrg   }
    414  1.1  mrg   return SetErrnoOnNull(HwasanAllocate(stack, size, alignment, false));
    415  1.1  mrg }
    416  1.1  mrg 
    417  1.1  mrg void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack) {
    418  1.1  mrg   if (UNLIKELY(!IsPowerOfTwo(alignment))) {
    419  1.1  mrg     errno = errno_EINVAL;
    420  1.1  mrg     if (AllocatorMayReturnNull())
    421  1.1  mrg       return nullptr;
    422  1.1  mrg     ReportInvalidAllocationAlignment(alignment, stack);
    423  1.1  mrg   }
    424  1.1  mrg   return SetErrnoOnNull(HwasanAllocate(stack, size, alignment, false));
    425  1.1  mrg }
    426  1.1  mrg 
    427  1.1  mrg int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
    428  1.1  mrg                         StackTrace *stack) {
    429  1.1  mrg   if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) {
    430  1.1  mrg     if (AllocatorMayReturnNull())
    431  1.1  mrg       return errno_EINVAL;
    432  1.1  mrg     ReportInvalidPosixMemalignAlignment(alignment, stack);
    433  1.1  mrg   }
    434  1.1  mrg   void *ptr = HwasanAllocate(stack, size, alignment, false);
    435  1.1  mrg   if (UNLIKELY(!ptr))
    436  1.1  mrg     // OOM error is already taken care of by HwasanAllocate.
    437  1.1  mrg     return errno_ENOMEM;
    438  1.1  mrg   CHECK(IsAligned((uptr)ptr, alignment));
    439  1.1  mrg   *memptr = ptr;
    440  1.1  mrg   return 0;
    441  1.1  mrg }
    442  1.1  mrg 
    443  1.1  mrg void hwasan_free(void *ptr, StackTrace *stack) {
    444  1.1  mrg   return HwasanDeallocate(stack, ptr);
    445  1.1  mrg }
    446  1.1  mrg 
    447  1.1  mrg }  // namespace __hwasan
    448  1.1  mrg 
    449  1.1  mrg using namespace __hwasan;
    450  1.1  mrg 
    451  1.1  mrg void __hwasan_enable_allocator_tagging() {
    452  1.1  mrg   atomic_store_relaxed(&hwasan_allocator_tagging_enabled, 1);
    453  1.1  mrg }
    454  1.1  mrg 
    455  1.1  mrg void __hwasan_disable_allocator_tagging() {
    456  1.1  mrg   atomic_store_relaxed(&hwasan_allocator_tagging_enabled, 0);
    457  1.1  mrg }
    458  1.1  mrg 
    459  1.1  mrg uptr __sanitizer_get_current_allocated_bytes() {
    460  1.1  mrg   uptr stats[AllocatorStatCount];
    461  1.1  mrg   allocator.GetStats(stats);
    462  1.1  mrg   return stats[AllocatorStatAllocated];
    463  1.1  mrg }
    464  1.1  mrg 
    465  1.1  mrg uptr __sanitizer_get_heap_size() {
    466  1.1  mrg   uptr stats[AllocatorStatCount];
    467  1.1  mrg   allocator.GetStats(stats);
    468  1.1  mrg   return stats[AllocatorStatMapped];
    469  1.1  mrg }
    470  1.1  mrg 
    471  1.1  mrg uptr __sanitizer_get_free_bytes() { return 1; }
    472  1.1  mrg 
    473  1.1  mrg uptr __sanitizer_get_unmapped_bytes() { return 1; }
    474  1.1  mrg 
    475  1.1  mrg uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
    476  1.1  mrg 
    477  1.1  mrg int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; }
    478  1.1  mrg 
    479  1.1  mrg uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); }
    480