Home | History | Annotate | Line # | Download | only in hwasan
      1 //===-- hwasan_allocator.h --------------------------------------*- C++ -*-===//
      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 HWAddressSanitizer.
     10 //
     11 //===----------------------------------------------------------------------===//
     12 
     13 #ifndef HWASAN_ALLOCATOR_H
     14 #define HWASAN_ALLOCATOR_H
     15 
     16 #include "hwasan.h"
     17 #include "hwasan_interface_internal.h"
     18 #include "hwasan_mapping.h"
     19 #include "hwasan_poisoning.h"
     20 #include "sanitizer_common/sanitizer_allocator.h"
     21 #include "sanitizer_common/sanitizer_allocator_checks.h"
     22 #include "sanitizer_common/sanitizer_allocator_interface.h"
     23 #include "sanitizer_common/sanitizer_allocator_report.h"
     24 #include "sanitizer_common/sanitizer_common.h"
     25 #include "sanitizer_common/sanitizer_ring_buffer.h"
     26 
     27 #if !defined(__aarch64__) && !defined(__x86_64__)
     28 #error Unsupported platform
     29 #endif
     30 
     31 namespace __hwasan {
     32 
     33 struct Metadata {
     34   u32 requested_size_low;
     35   u32 requested_size_high : 31;
     36   u32 right_aligned : 1;
     37   u32 alloc_context_id;
     38   u64 get_requested_size() {
     39     return (static_cast<u64>(requested_size_high) << 32) + requested_size_low;
     40   }
     41   void set_requested_size(u64 size) {
     42     requested_size_low = size & ((1ul << 32) - 1);
     43     requested_size_high = size >> 32;
     44   }
     45 };
     46 
     47 struct HwasanMapUnmapCallback {
     48   void OnMap(uptr p, uptr size) const { UpdateMemoryUsage(); }
     49   void OnUnmap(uptr p, uptr size) const {
     50     // We are about to unmap a chunk of user memory.
     51     // It can return as user-requested mmap() or another thread stack.
     52     // Make it accessible with zero-tagged pointer.
     53     TagMemory(p, size, 0);
     54   }
     55 };
     56 
     57 static const uptr kMaxAllowedMallocSize = 1UL << 40;  // 1T
     58 
     59 struct AP64 {
     60   static const uptr kSpaceBeg = ~0ULL;
     61 
     62 #if defined(HWASAN_ALIASING_MODE)
     63   static const uptr kSpaceSize = 1ULL << kAddressTagShift;
     64 #else
     65   static const uptr kSpaceSize = 0x2000000000ULL;
     66 #endif
     67   static const uptr kMetadataSize = sizeof(Metadata);
     68   typedef __sanitizer::VeryDenseSizeClassMap SizeClassMap;
     69   using AddressSpaceView = LocalAddressSpaceView;
     70   typedef HwasanMapUnmapCallback MapUnmapCallback;
     71   static const uptr kFlags = 0;
     72 };
     73 typedef SizeClassAllocator64<AP64> PrimaryAllocator;
     74 typedef CombinedAllocator<PrimaryAllocator> Allocator;
     75 typedef Allocator::AllocatorCache AllocatorCache;
     76 
     77 void AllocatorSwallowThreadLocalCache(AllocatorCache *cache);
     78 
     79 class HwasanChunkView {
     80  public:
     81   HwasanChunkView() : block_(0), metadata_(nullptr) {}
     82   HwasanChunkView(uptr block, Metadata *metadata)
     83       : block_(block), metadata_(metadata) {}
     84   bool IsAllocated() const;    // Checks if the memory is currently allocated
     85   uptr Beg() const;            // First byte of user memory
     86   uptr End() const;            // Last byte of user memory
     87   uptr UsedSize() const;       // Size requested by the user
     88   uptr ActualSize() const;     // Size allocated by the allocator.
     89   u32 GetAllocStackId() const;
     90   bool FromSmallHeap() const;
     91  private:
     92   uptr block_;
     93   Metadata *const metadata_;
     94 };
     95 
     96 HwasanChunkView FindHeapChunkByAddress(uptr address);
     97 
     98 // Information about one (de)allocation that happened in the past.
     99 // These are recorded in a thread-local ring buffer.
    100 // TODO: this is currently 24 bytes (20 bytes + alignment).
    101 // Compress it to 16 bytes or extend it to be more useful.
    102 struct HeapAllocationRecord {
    103   uptr tagged_addr;
    104   u32  alloc_context_id;
    105   u32  free_context_id;
    106   u32  requested_size;
    107 };
    108 
    109 typedef RingBuffer<HeapAllocationRecord> HeapAllocationsRingBuffer;
    110 
    111 void GetAllocatorStats(AllocatorStatCounters s);
    112 
    113 inline bool InTaggableRegion(uptr addr) {
    114 #if defined(HWASAN_ALIASING_MODE)
    115   // Aliases are mapped next to shadow so that the upper bits match the shadow
    116   // base.
    117   return (addr >> kTaggableRegionCheckShift) ==
    118          (GetShadowOffset() >> kTaggableRegionCheckShift);
    119 #endif
    120   return true;
    121 }
    122 
    123 } // namespace __hwasan
    124 
    125 #endif // HWASAN_ALLOCATOR_H
    126