[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:
Alexey Samsonov
2014-12-19 19:35:11 +00:00
parent cc09d1ccc5
commit d6b24fa1e2
4 changed files with 81 additions and 43 deletions

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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:

View File

@@ -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();