Files
llvm-project/compiler-rt/lib/memprof/memprof_allocator.h
Thurston Dang 1b5b4eebb6 [memprof] Move allocator base to avoid conflict with high-entropy ASLR (#85834)
memprof often fails when ASLR entropy is too high ('sudo sysctl
vm.mmap_rnd_bits=32; ninja check-memprof'), which is the default setting
for newer versions of Ubuntu
(https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/jammy/commit/?h=hwe-6.5-next--2024.03.04-1--auto&id=6b522637c6a7dabd8530026ae933fb5ff17e877f).
This patch fixes the issue by moving the allocator base, analogously to
ASan (https://reviews.llvm.org/D148280).

Explanation from the ASan patch: when CONFIG_ARCH_MMAP_RND_BITS == 32,
it will frequently conflict with memprof's allocator, because the PIE
program segment base address of 0x555555555554 plus an ASLR shift of up
to ((2**32) * 4K == 0x100000000000) will sometimes exceed memprof's
hardcoded base address of 0x600000000000. We fix this by simply moving
the allocator base to 0x500000000000, which is below the PIE program
segment base address. This is cleaner than trying to move it to another
location that is sandwiched between the PIE program and library
segments, because if either of those grow too large, it will collide
with the allocator region.

Note that we will never need to change this base address again (unless
we want to increase the size of the allocator), because ASLR cannot be
set above 32-bits for x86-64 Linux (the PIE program segment and library
segments would collide with each other; see also ARCH_MMAP_RND_BITS_MAX
in https://github.com/torvalds/linux/blob/master/arch/x86/Kconfig).
2024-03-20 09:19:20 -07:00

112 lines
3.9 KiB
C++

//===-- memprof_allocator.h ------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of MemProfiler, a memory profiler.
//
// MemProf-private header for memprof_allocator.cpp.
//===----------------------------------------------------------------------===//
#ifndef MEMPROF_ALLOCATOR_H
#define MEMPROF_ALLOCATOR_H
#include "memprof_flags.h"
#include "memprof_interceptors.h"
#include "memprof_internal.h"
#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_list.h"
#if !defined(__x86_64__)
#error Unsupported platform
#endif
#if !SANITIZER_CAN_USE_ALLOCATOR64
#error Only 64-bit allocator supported
#endif
namespace __memprof {
enum AllocType {
FROM_MALLOC = 1, // Memory block came from malloc, calloc, realloc, etc.
FROM_NEW = 2, // Memory block came from operator new.
FROM_NEW_BR = 3 // Memory block came from operator new [ ]
};
void InitializeAllocator();
struct MemprofMapUnmapCallback {
void OnMap(uptr p, uptr size) const;
void OnMapSecondary(uptr p, uptr size, uptr user_begin,
uptr user_size) const {
OnMap(p, size);
}
void OnUnmap(uptr p, uptr size) const;
};
#if SANITIZER_APPLE
constexpr uptr kAllocatorSpace = 0x600000000000ULL;
#else
constexpr uptr kAllocatorSpace = 0x500000000000ULL;
#endif
constexpr uptr kAllocatorSize = 0x40000000000ULL; // 4T.
typedef DefaultSizeClassMap SizeClassMap;
template <typename AddressSpaceViewTy>
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
static const uptr kSpaceBeg = kAllocatorSpace;
static const uptr kSpaceSize = kAllocatorSize;
static const uptr kMetadataSize = 0;
typedef __memprof::SizeClassMap SizeClassMap;
typedef MemprofMapUnmapCallback MapUnmapCallback;
static const uptr kFlags = 0;
using AddressSpaceView = AddressSpaceViewTy;
};
template <typename AddressSpaceView>
using PrimaryAllocatorASVT = SizeClassAllocator64<AP64<AddressSpaceView>>;
using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
static const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses;
template <typename AddressSpaceView>
using MemprofAllocatorASVT =
CombinedAllocator<PrimaryAllocatorASVT<AddressSpaceView>>;
using MemprofAllocator = MemprofAllocatorASVT<LocalAddressSpaceView>;
using AllocatorCache = MemprofAllocator::AllocatorCache;
struct MemprofThreadLocalMallocStorage {
AllocatorCache allocator_cache;
void CommitBack();
private:
// These objects are allocated via mmap() and are zero-initialized.
MemprofThreadLocalMallocStorage() {}
};
void *memprof_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
AllocType alloc_type);
void memprof_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type);
void memprof_delete(void *ptr, uptr size, uptr alignment,
BufferedStackTrace *stack, AllocType alloc_type);
void *memprof_malloc(uptr size, BufferedStackTrace *stack);
void *memprof_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack);
void *memprof_realloc(void *p, uptr size, BufferedStackTrace *stack);
void *memprof_reallocarray(void *p, uptr nmemb, uptr size,
BufferedStackTrace *stack);
void *memprof_valloc(uptr size, BufferedStackTrace *stack);
void *memprof_pvalloc(uptr size, BufferedStackTrace *stack);
void *memprof_aligned_alloc(uptr alignment, uptr size,
BufferedStackTrace *stack);
int memprof_posix_memalign(void **memptr, uptr alignment, uptr size,
BufferedStackTrace *stack);
uptr memprof_malloc_usable_size(const void *ptr);
void PrintInternalAllocatorStats();
} // namespace __memprof
#endif // MEMPROF_ALLOCATOR_H