Commit 7904bd94 authored by Matt Morehouse's avatar Matt Morehouse
Browse files

[sanitizer_common] Create max_allocation_size_mb flag.

Summary:
The flag allows the user to specify a maximum allocation size that the
sanitizers will honor.  Any larger allocations will return nullptr or
crash depending on allocator_may_return_null.

Reviewers: kcc, eugenis

Reviewed By: kcc, eugenis

Subscribers: #sanitizers, llvm-commits

Tags: #sanitizers, #llvm

Differential Revision: https://reviews.llvm.org/D69576
parent e4779883
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -246,6 +246,7 @@ struct Allocator {
  AllocatorCache fallback_allocator_cache;
  QuarantineCache fallback_quarantine_cache;

  uptr max_user_defined_malloc_size;
  atomic_uint8_t rss_limit_exceeded;

  // ------------------- Options --------------------------
@@ -280,6 +281,10 @@ struct Allocator {
    SetAllocatorMayReturnNull(options.may_return_null);
    allocator.InitLinkerInitialized(options.release_to_os_interval_ms);
    SharedInitCode(options);
    max_user_defined_malloc_size = common_flags()->max_allocation_size_mb
                                       ? common_flags()->max_allocation_size_mb
                                             << 20
                                       : kMaxAllowedMallocSize;
  }

  bool RssLimitExceeded() {
@@ -435,14 +440,16 @@ struct Allocator {
      using_primary_allocator = false;
    }
    CHECK(IsAligned(needed_size, min_alignment));
    if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) {
    if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize ||
        size > max_user_defined_malloc_size) {
      if (AllocatorMayReturnNull()) {
        Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n",
               (void*)size);
        return nullptr;
      }
      ReportAllocationSizeTooBig(size, needed_size, kMaxAllowedMallocSize,
                                 stack);
      uptr malloc_limit =
          Min(kMaxAllowedMallocSize, max_user_defined_malloc_size);
      ReportAllocationSizeTooBig(size, needed_size, malloc_limit, stack);
    }

    AsanThread *t = GetCurrentThread();
+10 −3
Original line number Diff line number Diff line
@@ -36,10 +36,17 @@ static const uptr kMaxAllowedMallocSize = 8UL << 30;

static Allocator allocator;

static uptr max_malloc_size;

void InitializeAllocator() {
  SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
  allocator.InitLinkerInitialized(
      common_flags()->allocator_release_to_os_interval_ms);
  if (common_flags()->max_allocation_size_mb)
    max_malloc_size = Min(common_flags()->max_allocation_size_mb << 20,
                          kMaxAllowedMallocSize);
  else
    max_malloc_size = kMaxAllowedMallocSize;
}

void AllocatorThreadFinish() {
@@ -72,14 +79,14 @@ static void *ReportAllocationSizeTooBig(uptr size, const StackTrace &stack) {
    Report("WARNING: LeakSanitizer failed to allocate 0x%zx bytes\n", size);
    return nullptr;
  }
  ReportAllocationSizeTooBig(size, kMaxAllowedMallocSize, &stack);
  ReportAllocationSizeTooBig(size, max_malloc_size, &stack);
}

void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
               bool cleared) {
  if (size == 0)
    size = 1;
  if (size > kMaxAllowedMallocSize)
  if (size > max_malloc_size)
    return ReportAllocationSizeTooBig(size, stack);
  void *p = allocator.Allocate(GetAllocatorCache(), size, alignment);
  if (UNLIKELY(!p)) {
@@ -117,7 +124,7 @@ void Deallocate(void *p) {
void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
                 uptr alignment) {
  RegisterDeallocation(p);
  if (new_size > kMaxAllowedMallocSize) {
  if (new_size > max_malloc_size) {
    allocator.Deallocate(GetAllocatorCache(), p);
    return ReportAllocationSizeTooBig(new_size, stack);
  }
+9 −2
Original line number Diff line number Diff line
@@ -115,9 +115,16 @@ static Allocator allocator;
static AllocatorCache fallback_allocator_cache;
static StaticSpinMutex fallback_mutex;

static uptr max_malloc_size;

void MsanAllocatorInit() {
  SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
  allocator.Init(common_flags()->allocator_release_to_os_interval_ms);
  if (common_flags()->max_allocation_size_mb)
    max_malloc_size = Min(common_flags()->max_allocation_size_mb << 20,
                          kMaxAllowedMallocSize);
  else
    max_malloc_size = kMaxAllowedMallocSize;
}

AllocatorCache *GetAllocatorCache(MsanThreadLocalMallocStorage *ms) {
@@ -132,12 +139,12 @@ void MsanThreadLocalMallocStorage::CommitBack() {

static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment,
                          bool zeroise) {
  if (size > kMaxAllowedMallocSize) {
  if (size > max_malloc_size) {
    if (AllocatorMayReturnNull()) {
      Report("WARNING: MemorySanitizer failed to allocate 0x%zx bytes\n", size);
      return nullptr;
    }
    ReportAllocationSizeTooBig(size, kMaxAllowedMallocSize, stack);
    ReportAllocationSizeTooBig(size, max_malloc_size, stack);
  }
  MsanThread *t = GetCurrentThread();
  void *allocated;
+3 −0
Original line number Diff line number Diff line
@@ -132,6 +132,9 @@ COMMON_FLAG(uptr, soft_rss_limit_mb, 0,
            " until the RSS goes below the soft limit."
            " This limit does not affect memory allocations other than"
            " malloc/new.")
COMMON_FLAG(uptr, max_allocation_size_mb, 0,
            "If non-zero, malloc/new calls larger than this size will return "
            "nullptr (or crash if allocator_may_return_null=false).")
COMMON_FLAG(bool, heap_profile, false, "Experimental heap profiler, asan-only")
COMMON_FLAG(s32, allocator_release_to_os_interval_ms,
            ((bool)SANITIZER_FUCHSIA || (bool)SANITIZER_WINDOWS) ? -1 : 5000,
+12 −3
Original line number Diff line number Diff line
@@ -113,9 +113,16 @@ ScopedGlobalProcessor::~ScopedGlobalProcessor() {
  gp->mtx.Unlock();
}

static constexpr uptr kMaxAllowedMallocSize = 1ull << 40;
static uptr max_user_defined_malloc_size;

void InitializeAllocator() {
  SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
  allocator()->Init(common_flags()->allocator_release_to_os_interval_ms);
  max_user_defined_malloc_size = common_flags()->max_allocation_size_mb
                                     ? common_flags()->max_allocation_size_mb
                                           << 20
                                     : kMaxAllowedMallocSize;
}

void InitializeAllocatorLate() {
@@ -150,15 +157,17 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
  OutputReport(thr, rep);
}

static constexpr uptr kMaxAllowedMallocSize = 1ull << 40;

void *user_alloc_internal(ThreadState *thr, uptr pc, uptr sz, uptr align,
                          bool signal) {
  if (sz >= kMaxAllowedMallocSize || align >= kMaxAllowedMallocSize) {
  if (sz >= kMaxAllowedMallocSize || align >= kMaxAllowedMallocSize ||
      sz > max_user_defined_malloc_size) {
    if (AllocatorMayReturnNull())
      return nullptr;
    uptr malloc_limit =
        Min(kMaxAllowedMallocSize, max_user_defined_malloc_size);
    GET_STACK_TRACE_FATAL(thr, pc);
    ReportAllocationSizeTooBig(sz, kMaxAllowedMallocSize, &stack);
    ReportAllocationSizeTooBig(sz, malloc_limit, &stack);
  }
  void *p = allocator()->Allocate(&thr->proc()->alloc_cache, sz, align);
  if (UNLIKELY(!p)) {
Loading