Skip to content

Commit 37db58e

Browse files
committed
Expose thread local quarantine size as ASAN option.
Summary: Make thread local quarantine size an option so it can be turned off to save memory. Reviewers: eugenis Patch by Alex Shlyapnikov. Subscribers: kubabrecka, llvm-commits Differential Revision: https://reviews.llvm.org/D28027 llvm-svn: 290373
1 parent 0b26e47 commit 37db58e

File tree

7 files changed

+64
-8
lines changed

7 files changed

+64
-8
lines changed

compiler-rt/lib/asan/asan_allocator.cc

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ QuarantineCache *GetQuarantineCache(AsanThreadLocalMallocStorage *ms) {
207207

208208
void AllocatorOptions::SetFrom(const Flags *f, const CommonFlags *cf) {
209209
quarantine_size_mb = f->quarantine_size_mb;
210+
thread_local_quarantine_size_kb = f->thread_local_quarantine_size_kb;
210211
min_redzone = f->redzone;
211212
max_redzone = f->max_redzone;
212213
may_return_null = cf->allocator_may_return_null;
@@ -216,6 +217,7 @@ void AllocatorOptions::SetFrom(const Flags *f, const CommonFlags *cf) {
216217

217218
void AllocatorOptions::CopyTo(Flags *f, CommonFlags *cf) {
218219
f->quarantine_size_mb = quarantine_size_mb;
220+
f->thread_local_quarantine_size_kb = thread_local_quarantine_size_kb;
219221
f->redzone = min_redzone;
220222
f->max_redzone = max_redzone;
221223
cf->allocator_may_return_null = may_return_null;
@@ -226,13 +228,6 @@ void AllocatorOptions::CopyTo(Flags *f, CommonFlags *cf) {
226228
struct Allocator {
227229
static const uptr kMaxAllowedMallocSize =
228230
FIRST_32_SECOND_64(3UL << 30, 1ULL << 40);
229-
static const uptr kMaxThreadLocalQuarantine =
230-
// It is not advised to go lower than 64Kb, otherwise quarantine batches
231-
// pushed from thread local quarantine to global one will create too much
232-
// overhead. One quarantine batch size is 8Kb and it holds up to 1021
233-
// chunk, which amounts to 1/8 memory overhead per batch when thread local
234-
// quarantine is set to 64Kb.
235-
(ASAN_LOW_MEMORY) ? 1 << 16 : FIRST_32_SECOND_64(1 << 18, 1 << 20);
236231

237232
AsanAllocator allocator;
238233
AsanQuarantine quarantine;
@@ -261,7 +256,7 @@ struct Allocator {
261256
void SharedInitCode(const AllocatorOptions &options) {
262257
CheckOptions(options);
263258
quarantine.Init((uptr)options.quarantine_size_mb << 20,
264-
kMaxThreadLocalQuarantine);
259+
(uptr)options.thread_local_quarantine_size_kb << 10);
265260
atomic_store(&alloc_dealloc_mismatch, options.alloc_dealloc_mismatch,
266261
memory_order_release);
267262
atomic_store(&min_redzone, options.min_redzone, memory_order_release);
@@ -315,6 +310,7 @@ struct Allocator {
315310

316311
void GetOptions(AllocatorOptions *options) const {
317312
options->quarantine_size_mb = quarantine.GetSize() >> 20;
313+
options->thread_local_quarantine_size_kb = quarantine.GetCacheSize() >> 10;
318314
options->min_redzone = atomic_load(&min_redzone, memory_order_acquire);
319315
options->max_redzone = atomic_load(&max_redzone, memory_order_acquire);
320316
options->may_return_null = allocator.MayReturnNull();

compiler-rt/lib/asan/asan_allocator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ struct AsanChunk;
3333

3434
struct AllocatorOptions {
3535
u32 quarantine_size_mb;
36+
u32 thread_local_quarantine_size_kb;
3637
u16 min_redzone;
3738
u16 max_redzone;
3839
u8 may_return_null;

compiler-rt/lib/asan/asan_flags.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,16 @@ void InitializeFlags() {
159159
(ASAN_LOW_MEMORY) ? 1UL << 4 : 1UL << 8;
160160
f->quarantine_size_mb = kDefaultQuarantineSizeMb;
161161
}
162+
if (f->thread_local_quarantine_size_kb < 0) {
163+
const u32 kDefaultThreadLocalQuarantineSizeKb =
164+
// It is not advised to go lower than 64Kb, otherwise quarantine batches
165+
// pushed from thread local quarantine to global one will create too
166+
// much overhead. One quarantine batch size is 8Kb and it holds up to
167+
// 1021 chunk, which amounts to 1/8 memory overhead per batch when
168+
// thread local quarantine is set to 64Kb.
169+
(ASAN_LOW_MEMORY) ? 1 << 6 : FIRST_32_SECOND_64(1 << 8, 1 << 10);
170+
f->thread_local_quarantine_size_kb = kDefaultThreadLocalQuarantineSizeKb;
171+
}
162172
if (!f->replace_str && common_flags()->intercept_strlen) {
163173
Report("WARNING: strlen interceptor is enabled even though replace_str=0. "
164174
"Use intercept_strlen=0 to disable it.");

compiler-rt/lib/asan/asan_flags.inc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ ASAN_FLAG(int, quarantine_size_mb, -1,
2323
"Size (in Mb) of quarantine used to detect use-after-free "
2424
"errors. Lower value may reduce memory usage but increase the "
2525
"chance of false negatives.")
26+
ASAN_FLAG(int, thread_local_quarantine_size_kb, -1,
27+
"Size (in Kb) of thread local quarantine used to detect "
28+
"use-after-free errors. Lower value may reduce memory usage but "
29+
"increase the chance of false negatives. It is not advised to go "
30+
"lower than 64Kb, otherwise frequent transfers to global quarantine "
31+
"might affect performance.")
2632
ASAN_FLAG(int, redzone, 16,
2733
"Minimal size (in bytes) of redzones around heap objects. "
2834
"Requirement: redzone >= 16, is a power of two.")

compiler-rt/lib/asan/asan_rtl.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,8 @@ static void PrintAddressSpaceLayout() {
410410
Printf("redzone=%zu\n", (uptr)flags()->redzone);
411411
Printf("max_redzone=%zu\n", (uptr)flags()->max_redzone);
412412
Printf("quarantine_size_mb=%zuM\n", (uptr)flags()->quarantine_size_mb);
413+
Printf("thread_local_quarantine_size_kb=%zuK\n",
414+
(uptr)flags()->thread_local_quarantine_size_kb);
413415
Printf("malloc_context_size=%zu\n",
414416
(uptr)common_flags()->malloc_context_size);
415417

compiler-rt/lib/sanitizer_common/sanitizer_quarantine.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class Quarantine {
5656
}
5757

5858
uptr GetSize() const { return atomic_load(&max_size_, memory_order_acquire); }
59+
uptr GetCacheSize() const { return max_cache_size_; }
5960

6061
void Put(Cache *c, Callback cb, Node *ptr, uptr size) {
6162
c->Enqueue(cb, ptr, size);
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Test thread_local_quarantine_size_kb
2+
3+
// RUN: %clangxx_asan %s -o %t
4+
// RUN: %env_asan_opts=thread_local_quarantine_size_kb=256:verbosity=1 %run %t 2>&1 | \
5+
// RUN: FileCheck %s --check-prefix=CHECK-VALUE
6+
// RUN: %env_asan_opts=thread_local_quarantine_size_kb=64:quarantine_size_mb=64 %run %t 2>&1 | \
7+
// RUN: FileCheck %s --allow-empty --check-prefix=CHECK-SMALL-LOCAL-CACHE-SMALL-OVERHEAD
8+
// RUN: %env_asan_opts=thread_local_quarantine_size_kb=0:quarantine_size_mb=64 %run %t 2>&1 | \
9+
// RUN: FileCheck %s --check-prefix=CHECK-NO-LOCAL-CACHE-HUGE-OVERHEAD
10+
11+
#include <stdio.h>
12+
#include <stdlib.h>
13+
#include <string.h>
14+
#include <sanitizer/allocator_interface.h>
15+
16+
// The idea is allocate a lot of small blocks, totaling 5Mb of user memory
17+
// total, and verify that quarantine does not incur too much memory overhead.
18+
// There's always an overhead for red zones, shadow memory and such, but
19+
// quarantine accounting should not significantly contribute to that.
20+
static const int kNumAllocs = 20000;
21+
static const int kAllocSize = 256;
22+
static const size_t kHeapSizeLimit = 12 << 20;
23+
24+
int main() {
25+
size_t old_heap_size = __sanitizer_get_heap_size();
26+
for (int i = 0; i < kNumAllocs; i++) {
27+
char *g = new char[kAllocSize];
28+
memset(g, -1, kAllocSize);
29+
delete [] (g);
30+
}
31+
size_t new_heap_size = __sanitizer_get_heap_size();
32+
fprintf(stderr, "heap size: new: %zd old: %zd\n", new_heap_size,
33+
old_heap_size);
34+
if (new_heap_size - old_heap_size > kHeapSizeLimit)
35+
fprintf(stderr, "Heap size limit exceeded");
36+
}
37+
38+
// CHECK-VALUE: thread_local_quarantine_size_kb=256K
39+
// CHECK-SMALL-LOCAL-CACHE-SMALL-OVERHEAD-NOT: Heap size limit exceeded
40+
// CHECK-NO-LOCAL-CACHE-HUGE-OVERHEAD: Heap size limit exceeded

0 commit comments

Comments
 (0)