mirror of
https://github.com/intel/llvm.git
synced 2026-01-17 06:40:01 +08:00
[ASan] Introduce AllocatorOptions to configure allocator behavior.
Summary: Reduce the dependency of allocator code on runtime flags. Instead, pass a bunch of options that configure allocator behavior at initialization or re-initialization. That would allow us to cleaner modify allocator behavior during a program execution when ASan is activated or de-activated. Test Plan: regression test suite Reviewers: kcc Subscribers: llvm-commits, eugenis Differential Revision: http://reviews.llvm.org/D6711 llvm-svn: 224605
This commit is contained in:
@@ -23,20 +23,14 @@
|
||||
namespace __asan {
|
||||
|
||||
static struct AsanDeactivatedFlags {
|
||||
int quarantine_size;
|
||||
int max_redzone;
|
||||
AllocatorOptions allocator_options;
|
||||
int malloc_context_size;
|
||||
bool poison_heap;
|
||||
bool alloc_dealloc_mismatch;
|
||||
bool allocator_may_return_null;
|
||||
|
||||
void CopyFrom(const Flags *f, const CommonFlags *cf) {
|
||||
quarantine_size = f->quarantine_size;
|
||||
max_redzone = f->max_redzone;
|
||||
allocator_options.SetFrom(f, cf);
|
||||
malloc_context_size = cf->malloc_context_size;
|
||||
poison_heap = f->poison_heap;
|
||||
alloc_dealloc_mismatch = f->alloc_dealloc_mismatch;
|
||||
allocator_may_return_null = cf->allocator_may_return_null;
|
||||
}
|
||||
|
||||
void OverrideFromActivationFlags() {
|
||||
@@ -44,12 +38,14 @@ static struct AsanDeactivatedFlags {
|
||||
CommonFlags cf;
|
||||
|
||||
// Copy the current activation flags.
|
||||
f.quarantine_size = quarantine_size;
|
||||
f.max_redzone = max_redzone;
|
||||
f.quarantine_size = allocator_options.quarantine_size_mb << 20;
|
||||
f.redzone = allocator_options.min_redzone;
|
||||
f.max_redzone = allocator_options.max_redzone;
|
||||
cf.allocator_may_return_null = allocator_options.may_return_null;
|
||||
f.alloc_dealloc_mismatch = allocator_options.alloc_dealloc_mismatch;
|
||||
|
||||
cf.malloc_context_size = malloc_context_size;
|
||||
f.poison_heap = poison_heap;
|
||||
f.alloc_dealloc_mismatch = alloc_dealloc_mismatch;
|
||||
cf.allocator_may_return_null = allocator_may_return_null;
|
||||
|
||||
// Check if activation flags need to be overriden.
|
||||
// FIXME: Add diagnostic to check that activation flags string doesn't
|
||||
@@ -63,11 +59,13 @@ static struct AsanDeactivatedFlags {
|
||||
}
|
||||
|
||||
void Print() {
|
||||
Report("quarantine_size %d, max_redzone %d, poison_heap %d, "
|
||||
Report("quarantine_size_mb %d, max_redzone %d, poison_heap %d, "
|
||||
"malloc_context_size %d, alloc_dealloc_mismatch %d, "
|
||||
"allocator_may_return_null %d\n",
|
||||
quarantine_size, max_redzone, poison_heap, malloc_context_size,
|
||||
alloc_dealloc_mismatch, allocator_may_return_null);
|
||||
allocator_options.quarantine_size_mb, allocator_options.max_redzone,
|
||||
poison_heap, malloc_context_size,
|
||||
allocator_options.alloc_dealloc_mismatch,
|
||||
allocator_options.may_return_null);
|
||||
}
|
||||
} asan_deactivated_flags;
|
||||
|
||||
@@ -97,16 +95,9 @@ void AsanActivate() {
|
||||
|
||||
asan_deactivated_flags.OverrideFromActivationFlags();
|
||||
|
||||
// Restore flag values.
|
||||
// FIXME: this is not atomic, and there may be other threads alive.
|
||||
flags()->max_redzone = asan_deactivated_flags.max_redzone;
|
||||
flags()->alloc_dealloc_mismatch =
|
||||
asan_deactivated_flags.alloc_dealloc_mismatch;
|
||||
|
||||
SetCanPoisonMemory(asan_deactivated_flags.poison_heap);
|
||||
SetMallocContextSize(asan_deactivated_flags.malloc_context_size);
|
||||
ReInitializeAllocator(asan_deactivated_flags.allocator_may_return_null,
|
||||
asan_deactivated_flags.quarantine_size);
|
||||
ReInitializeAllocator(asan_deactivated_flags.allocator_options);
|
||||
|
||||
asan_is_deactivated = false;
|
||||
if (common_flags()->verbosity) {
|
||||
|
||||
@@ -205,6 +205,14 @@ QuarantineCache *GetQuarantineCache(AsanThreadLocalMallocStorage *ms) {
|
||||
return reinterpret_cast<QuarantineCache *>(ms->quarantine_cache);
|
||||
}
|
||||
|
||||
void AllocatorOptions::SetFrom(const Flags *f, const CommonFlags *cf) {
|
||||
quarantine_size_mb = f->quarantine_size >> 20;
|
||||
min_redzone = f->redzone;
|
||||
max_redzone = f->max_redzone;
|
||||
may_return_null = cf->allocator_may_return_null;
|
||||
alloc_dealloc_mismatch = f->alloc_dealloc_mismatch;
|
||||
}
|
||||
|
||||
struct Allocator {
|
||||
static const uptr kMaxAllowedMallocSize =
|
||||
FIRST_32_SECOND_64(3UL << 30, 64UL << 30);
|
||||
@@ -217,19 +225,42 @@ struct Allocator {
|
||||
AllocatorCache fallback_allocator_cache;
|
||||
QuarantineCache fallback_quarantine_cache;
|
||||
|
||||
// ------------------- Options --------------------------
|
||||
atomic_uint16_t min_redzone;
|
||||
atomic_uint16_t max_redzone;
|
||||
atomic_uint8_t alloc_dealloc_mismatch;
|
||||
|
||||
// ------------------- Initialization ------------------------
|
||||
explicit Allocator(LinkerInitialized)
|
||||
: quarantine(LINKER_INITIALIZED),
|
||||
fallback_quarantine_cache(LINKER_INITIALIZED) {}
|
||||
|
||||
// ------------------- Initialization ------------------------
|
||||
void Initialize(bool may_return_null, uptr quarantine_size) {
|
||||
allocator.Init(may_return_null);
|
||||
quarantine.Init(quarantine_size, kMaxThreadLocalQuarantine);
|
||||
void CheckOptions(const AllocatorOptions &options) const {
|
||||
CHECK_GE(options.min_redzone, 16);
|
||||
CHECK_GE(options.max_redzone, options.min_redzone);
|
||||
CHECK_LE(options.max_redzone, 2048);
|
||||
CHECK(IsPowerOfTwo(options.min_redzone));
|
||||
CHECK(IsPowerOfTwo(options.max_redzone));
|
||||
}
|
||||
|
||||
void ReInitialize(bool may_return_null, uptr quarantine_size) {
|
||||
allocator.SetMayReturnNull(may_return_null);
|
||||
quarantine.Init(quarantine_size, kMaxThreadLocalQuarantine);
|
||||
void SharedInitCode(const AllocatorOptions &options) {
|
||||
CheckOptions(options);
|
||||
quarantine.Init((uptr)options.quarantine_size_mb << 20,
|
||||
kMaxThreadLocalQuarantine);
|
||||
atomic_store(&alloc_dealloc_mismatch, options.alloc_dealloc_mismatch,
|
||||
memory_order_release);
|
||||
atomic_store(&min_redzone, options.min_redzone, memory_order_release);
|
||||
atomic_store(&max_redzone, options.max_redzone, memory_order_release);
|
||||
}
|
||||
|
||||
void Initialize(const AllocatorOptions &options) {
|
||||
allocator.Init(options.may_return_null);
|
||||
SharedInitCode(options);
|
||||
}
|
||||
|
||||
void ReInitialize(const AllocatorOptions &options) {
|
||||
allocator.SetMayReturnNull(options.may_return_null);
|
||||
SharedInitCode(options);
|
||||
}
|
||||
|
||||
// -------------------- Helper methods. -------------------------
|
||||
@@ -242,8 +273,9 @@ struct Allocator {
|
||||
user_requested_size <= (1 << 14) - 256 ? 4 :
|
||||
user_requested_size <= (1 << 15) - 512 ? 5 :
|
||||
user_requested_size <= (1 << 16) - 1024 ? 6 : 7;
|
||||
return Min(Max(rz_log, RZSize2Log(flags()->redzone)),
|
||||
RZSize2Log(flags()->max_redzone));
|
||||
u32 min_rz = atomic_load(&min_redzone, memory_order_acquire);
|
||||
u32 max_rz = atomic_load(&max_redzone, memory_order_acquire);
|
||||
return Min(Max(rz_log, RZSize2Log(min_rz)), RZSize2Log(max_rz));
|
||||
}
|
||||
|
||||
// We have an address between two chunks, and we want to report just one.
|
||||
@@ -419,9 +451,12 @@ struct Allocator {
|
||||
AllocType alloc_type) {
|
||||
CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
|
||||
|
||||
if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch)
|
||||
ReportAllocTypeMismatch((uptr)ptr, stack,
|
||||
(AllocType)m->alloc_type, (AllocType)alloc_type);
|
||||
if (m->alloc_type != alloc_type) {
|
||||
if (atomic_load(&alloc_dealloc_mismatch, memory_order_acquire)) {
|
||||
ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type,
|
||||
(AllocType)alloc_type);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_GE(m->alloc_tid, 0);
|
||||
if (SANITIZER_WORDSIZE == 64) // On 32-bits this resides in user area.
|
||||
@@ -619,12 +654,12 @@ StackTrace AsanChunkView::GetFreeStack() {
|
||||
return GetStackTraceFromId(chunk_->free_context_id);
|
||||
}
|
||||
|
||||
void InitializeAllocator(bool may_return_null, uptr quarantine_size) {
|
||||
instance.Initialize(may_return_null, quarantine_size);
|
||||
void InitializeAllocator(const AllocatorOptions &options) {
|
||||
instance.Initialize(options);
|
||||
}
|
||||
|
||||
void ReInitializeAllocator(bool may_return_null, uptr quarantine_size) {
|
||||
instance.ReInitialize(may_return_null, quarantine_size);
|
||||
void ReInitializeAllocator(const AllocatorOptions &options) {
|
||||
instance.ReInitialize(options);
|
||||
}
|
||||
|
||||
AsanChunkView FindHeapChunkByAddress(uptr addr) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef ASAN_ALLOCATOR_H
|
||||
#define ASAN_ALLOCATOR_H
|
||||
|
||||
#include "asan_flags.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_interceptors.h"
|
||||
#include "sanitizer_common/sanitizer_allocator.h"
|
||||
@@ -31,8 +32,18 @@ enum AllocType {
|
||||
static const uptr kNumberOfSizeClasses = 255;
|
||||
struct AsanChunk;
|
||||
|
||||
void InitializeAllocator(bool may_return_null, uptr quarantine_size);
|
||||
void ReInitializeAllocator(bool may_return_null, uptr quarantine_size);
|
||||
struct AllocatorOptions {
|
||||
u32 quarantine_size_mb;
|
||||
u16 min_redzone;
|
||||
u16 max_redzone;
|
||||
u8 may_return_null;
|
||||
u8 alloc_dealloc_mismatch;
|
||||
|
||||
void SetFrom(const Flags *f, const CommonFlags *cf);
|
||||
};
|
||||
|
||||
void InitializeAllocator(const AllocatorOptions &options);
|
||||
void ReInitializeAllocator(const AllocatorOptions &options);
|
||||
|
||||
class AsanChunkView {
|
||||
public:
|
||||
|
||||
@@ -391,8 +391,9 @@ static void AsanInitInternal() {
|
||||
AsanTSDInit(PlatformTSDDtor);
|
||||
InstallDeadlySignalHandlers(AsanOnSIGSEGV);
|
||||
|
||||
InitializeAllocator(common_flags()->allocator_may_return_null,
|
||||
flags()->quarantine_size);
|
||||
AllocatorOptions allocator_options;
|
||||
allocator_options.SetFrom(flags(), common_flags());
|
||||
InitializeAllocator(allocator_options);
|
||||
|
||||
MaybeStartBackgroudThread();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user