brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.4 KiB · 49940d9 Raw
200 lines · c
1//===-- sanitizer_allocator_combined.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-exception6//7//===----------------------------------------------------------------------===//8//9// Part of the Sanitizer Allocator.10//11//===----------------------------------------------------------------------===//12#ifndef SANITIZER_ALLOCATOR_H13#error This file must be included inside sanitizer_allocator.h14#endif15 16// This class implements a complete memory allocator by using two17// internal allocators:18// PrimaryAllocator is efficient, but may not allocate some sizes (alignments).19//  When allocating 2^x bytes it should return 2^x aligned chunk.20// PrimaryAllocator is used via a local AllocatorCache.21// SecondaryAllocator can allocate anything, but is not efficient.22template <class PrimaryAllocator,23          class LargeMmapAllocatorPtrArray = DefaultLargeMmapAllocatorPtrArray>24class CombinedAllocator {25 public:26  using AllocatorCache = typename PrimaryAllocator::AllocatorCache;27  using SecondaryAllocator =28      LargeMmapAllocator<typename PrimaryAllocator::MapUnmapCallback,29                         LargeMmapAllocatorPtrArray,30                         typename PrimaryAllocator::AddressSpaceView>;31 32  void InitLinkerInitialized(s32 release_to_os_interval_ms,33                             uptr heap_start = 0) {34    primary_.Init(release_to_os_interval_ms, heap_start);35    secondary_.InitLinkerInitialized();36  }37 38  void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) {39    stats_.Init();40    primary_.Init(release_to_os_interval_ms, heap_start);41    secondary_.Init();42  }43 44  void *Allocate(AllocatorCache *cache, uptr size, uptr alignment) {45    // Returning 0 on malloc(0) may break a lot of code.46    if (size == 0)47      size = 1;48    if (size + alignment < size) {49      Report("WARNING: %s: CombinedAllocator allocation overflow: "50             "0x%zx bytes with 0x%zx alignment requested\n",51             SanitizerToolName, size, alignment);52      return nullptr;53    }54    uptr original_size = size;55    // If alignment requirements are to be fulfilled by the frontend allocator56    // rather than by the primary or secondary, passing an alignment lower than57    // or equal to 8 will prevent any further rounding up, as well as the later58    // alignment check.59    if (alignment > 8)60      size = RoundUpTo(size, alignment);61    // The primary allocator should return a 2^x aligned allocation when62    // requested 2^x bytes, hence using the rounded up 'size' when being63    // serviced by the primary (this is no longer true when the primary is64    // using a non-fixed base address). The secondary takes care of the65    // alignment without such requirement, and allocating 'size' would use66    // extraneous memory, so we employ 'original_size'.67    void *res;68    if (primary_.CanAllocate(size, alignment))69      res = cache->Allocate(&primary_, primary_.ClassID(size));70    else71      res = secondary_.Allocate(&stats_, original_size, alignment);72    if (alignment > 8)73      CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);74    return res;75  }76 77  s32 ReleaseToOSIntervalMs() const {78    return primary_.ReleaseToOSIntervalMs();79  }80 81  void SetReleaseToOSIntervalMs(s32 release_to_os_interval_ms) {82    primary_.SetReleaseToOSIntervalMs(release_to_os_interval_ms);83  }84 85  void ForceReleaseToOS() {86    primary_.ForceReleaseToOS();87  }88 89  void Deallocate(AllocatorCache *cache, void *p) {90    if (!p) return;91    if (primary_.PointerIsMine(p))92      cache->Deallocate(&primary_, primary_.GetSizeClass(p), p);93    else94      secondary_.Deallocate(&stats_, p);95  }96 97  void *Reallocate(AllocatorCache *cache, void *p, uptr new_size,98                   uptr alignment) {99    if (!p)100      return Allocate(cache, new_size, alignment);101    if (!new_size) {102      Deallocate(cache, p);103      return nullptr;104    }105    CHECK(PointerIsMine(p));106    uptr old_size = GetActuallyAllocatedSize(p);107    uptr memcpy_size = Min(new_size, old_size);108    void *new_p = Allocate(cache, new_size, alignment);109    if (new_p)110      internal_memcpy(new_p, p, memcpy_size);111    Deallocate(cache, p);112    return new_p;113  }114 115  bool PointerIsMine(const void *p) const {116    if (primary_.PointerIsMine(p))117      return true;118    return secondary_.PointerIsMine(p);119  }120 121  bool FromPrimary(const void *p) const { return primary_.PointerIsMine(p); }122 123  void *GetMetaData(const void *p) {124    if (primary_.PointerIsMine(p))125      return primary_.GetMetaData(p);126    return secondary_.GetMetaData(p);127  }128 129  void *GetBlockBegin(const void *p) {130    if (primary_.PointerIsMine(p))131      return primary_.GetBlockBegin(p);132    return secondary_.GetBlockBegin(p);133  }134 135  // This function does the same as GetBlockBegin, but is much faster.136  // Must be called with the allocator locked.137  void *GetBlockBeginFastLocked(const void *p) {138    if (primary_.PointerIsMine(p))139      return primary_.GetBlockBegin(p);140    return secondary_.GetBlockBeginFastLocked(p);141  }142 143  uptr GetActuallyAllocatedSize(void *p) {144    if (primary_.PointerIsMine(p))145      return primary_.GetActuallyAllocatedSize(p);146    return secondary_.GetActuallyAllocatedSize(p);147  }148 149  uptr TotalMemoryUsed() {150    return primary_.TotalMemoryUsed() + secondary_.TotalMemoryUsed();151  }152 153  void TestOnlyUnmap() { primary_.TestOnlyUnmap(); }154 155  void InitCache(AllocatorCache *cache) {156    cache->Init(&stats_);157  }158 159  void DestroyCache(AllocatorCache *cache) {160    cache->Destroy(&primary_, &stats_);161  }162 163  void SwallowCache(AllocatorCache *cache) {164    cache->Drain(&primary_);165  }166 167  void GetStats(AllocatorStatCounters s) const {168    stats_.Get(s);169  }170 171  void PrintStats() {172    primary_.PrintStats();173    secondary_.PrintStats();174  }175 176  // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone177  // introspection API.178  void ForceLock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS {179    primary_.ForceLock();180    secondary_.ForceLock();181  }182 183  void ForceUnlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS {184    secondary_.ForceUnlock();185    primary_.ForceUnlock();186  }187 188  // Iterate over all existing chunks.189  // The allocator must be locked when calling this function.190  void ForEachChunk(ForEachChunkCallback callback, void *arg) {191    primary_.ForEachChunk(callback, arg);192    secondary_.ForEachChunk(callback, arg);193  }194 195 private:196  PrimaryAllocator primary_;197  SecondaryAllocator secondary_;198  AllocatorGlobalStats stats_;199};200