summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/asan/asan_allocator.cc12
-rw-r--r--lib/asan/asan_allocator.h1
-rw-r--r--lib/asan/asan_flags.cc10
-rw-r--r--lib/asan/asan_flags.inc6
-rw-r--r--lib/asan/asan_rtl.cc2
-rw-r--r--lib/sanitizer_common/sanitizer_quarantine.h1
-rw-r--r--test/asan/TestCases/Linux/thread_local_quarantine_size_kb.cc40
7 files changed, 64 insertions, 8 deletions
diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc
index 1055a8dca..36bd04689 100644
--- a/lib/asan/asan_allocator.cc
+++ b/lib/asan/asan_allocator.cc
@@ -207,6 +207,7 @@ QuarantineCache *GetQuarantineCache(AsanThreadLocalMallocStorage *ms) {
void AllocatorOptions::SetFrom(const Flags *f, const CommonFlags *cf) {
quarantine_size_mb = f->quarantine_size_mb;
+ thread_local_quarantine_size_kb = f->thread_local_quarantine_size_kb;
min_redzone = f->redzone;
max_redzone = f->max_redzone;
may_return_null = cf->allocator_may_return_null;
@@ -216,6 +217,7 @@ void AllocatorOptions::SetFrom(const Flags *f, const CommonFlags *cf) {
void AllocatorOptions::CopyTo(Flags *f, CommonFlags *cf) {
f->quarantine_size_mb = quarantine_size_mb;
+ f->thread_local_quarantine_size_kb = thread_local_quarantine_size_kb;
f->redzone = min_redzone;
f->max_redzone = max_redzone;
cf->allocator_may_return_null = may_return_null;
@@ -226,13 +228,6 @@ void AllocatorOptions::CopyTo(Flags *f, CommonFlags *cf) {
struct Allocator {
static const uptr kMaxAllowedMallocSize =
FIRST_32_SECOND_64(3UL << 30, 1ULL << 40);
- static const uptr kMaxThreadLocalQuarantine =
- // It is not advised to go lower than 64Kb, otherwise quarantine batches
- // pushed from thread local quarantine to global one will create too much
- // overhead. One quarantine batch size is 8Kb and it holds up to 1021
- // chunk, which amounts to 1/8 memory overhead per batch when thread local
- // quarantine is set to 64Kb.
- (ASAN_LOW_MEMORY) ? 1 << 16 : FIRST_32_SECOND_64(1 << 18, 1 << 20);
AsanAllocator allocator;
AsanQuarantine quarantine;
@@ -261,7 +256,7 @@ struct Allocator {
void SharedInitCode(const AllocatorOptions &options) {
CheckOptions(options);
quarantine.Init((uptr)options.quarantine_size_mb << 20,
- kMaxThreadLocalQuarantine);
+ (uptr)options.thread_local_quarantine_size_kb << 10);
atomic_store(&alloc_dealloc_mismatch, options.alloc_dealloc_mismatch,
memory_order_release);
atomic_store(&min_redzone, options.min_redzone, memory_order_release);
@@ -315,6 +310,7 @@ struct Allocator {
void GetOptions(AllocatorOptions *options) const {
options->quarantine_size_mb = quarantine.GetSize() >> 20;
+ options->thread_local_quarantine_size_kb = quarantine.GetCacheSize() >> 10;
options->min_redzone = atomic_load(&min_redzone, memory_order_acquire);
options->max_redzone = atomic_load(&max_redzone, memory_order_acquire);
options->may_return_null = allocator.MayReturnNull();
diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h
index 62415f33e..51de67858 100644
--- a/lib/asan/asan_allocator.h
+++ b/lib/asan/asan_allocator.h
@@ -33,6 +33,7 @@ struct AsanChunk;
struct AllocatorOptions {
u32 quarantine_size_mb;
+ u32 thread_local_quarantine_size_kb;
u16 min_redzone;
u16 max_redzone;
u8 may_return_null;
diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc
index 369ef0a70..4db407d45 100644
--- a/lib/asan/asan_flags.cc
+++ b/lib/asan/asan_flags.cc
@@ -159,6 +159,16 @@ void InitializeFlags() {
(ASAN_LOW_MEMORY) ? 1UL << 4 : 1UL << 8;
f->quarantine_size_mb = kDefaultQuarantineSizeMb;
}
+ if (f->thread_local_quarantine_size_kb < 0) {
+ const u32 kDefaultThreadLocalQuarantineSizeKb =
+ // It is not advised to go lower than 64Kb, otherwise quarantine batches
+ // pushed from thread local quarantine to global one will create too
+ // much overhead. One quarantine batch size is 8Kb and it holds up to
+ // 1021 chunk, which amounts to 1/8 memory overhead per batch when
+ // thread local quarantine is set to 64Kb.
+ (ASAN_LOW_MEMORY) ? 1 << 6 : FIRST_32_SECOND_64(1 << 8, 1 << 10);
+ f->thread_local_quarantine_size_kb = kDefaultThreadLocalQuarantineSizeKb;
+ }
if (!f->replace_str && common_flags()->intercept_strlen) {
Report("WARNING: strlen interceptor is enabled even though replace_str=0. "
"Use intercept_strlen=0 to disable it.");
diff --git a/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc
index 5272477a6..4712efb86 100644
--- a/lib/asan/asan_flags.inc
+++ b/lib/asan/asan_flags.inc
@@ -23,6 +23,12 @@ ASAN_FLAG(int, quarantine_size_mb, -1,
"Size (in Mb) of quarantine used to detect use-after-free "
"errors. Lower value may reduce memory usage but increase the "
"chance of false negatives.")
+ASAN_FLAG(int, thread_local_quarantine_size_kb, -1,
+ "Size (in Kb) of thread local quarantine used to detect "
+ "use-after-free errors. Lower value may reduce memory usage but "
+ "increase the chance of false negatives. It is not advised to go "
+ "lower than 64Kb, otherwise frequent transfers to global quarantine "
+ "might affect performance.")
ASAN_FLAG(int, redzone, 16,
"Minimal size (in bytes) of redzones around heap objects. "
"Requirement: redzone >= 16, is a power of two.")
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index 5c191feb1..fee7b8a2d 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -410,6 +410,8 @@ static void PrintAddressSpaceLayout() {
Printf("redzone=%zu\n", (uptr)flags()->redzone);
Printf("max_redzone=%zu\n", (uptr)flags()->max_redzone);
Printf("quarantine_size_mb=%zuM\n", (uptr)flags()->quarantine_size_mb);
+ Printf("thread_local_quarantine_size_kb=%zuK\n",
+ (uptr)flags()->thread_local_quarantine_size_kb);
Printf("malloc_context_size=%zu\n",
(uptr)common_flags()->malloc_context_size);
diff --git a/lib/sanitizer_common/sanitizer_quarantine.h b/lib/sanitizer_common/sanitizer_quarantine.h
index ccc22bf01..ff8f3fa30 100644
--- a/lib/sanitizer_common/sanitizer_quarantine.h
+++ b/lib/sanitizer_common/sanitizer_quarantine.h
@@ -56,6 +56,7 @@ class Quarantine {
}
uptr GetSize() const { return atomic_load(&max_size_, memory_order_acquire); }
+ uptr GetCacheSize() const { return max_cache_size_; }
void Put(Cache *c, Callback cb, Node *ptr, uptr size) {
c->Enqueue(cb, ptr, size);
diff --git a/test/asan/TestCases/Linux/thread_local_quarantine_size_kb.cc b/test/asan/TestCases/Linux/thread_local_quarantine_size_kb.cc
new file mode 100644
index 000000000..7176484ed
--- /dev/null
+++ b/test/asan/TestCases/Linux/thread_local_quarantine_size_kb.cc
@@ -0,0 +1,40 @@
+// Test thread_local_quarantine_size_kb
+
+// RUN: %clangxx_asan %s -o %t
+// RUN: %env_asan_opts=thread_local_quarantine_size_kb=256:verbosity=1 %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK-VALUE
+// RUN: %env_asan_opts=thread_local_quarantine_size_kb=64:quarantine_size_mb=64 %run %t 2>&1 | \
+// RUN: FileCheck %s --allow-empty --check-prefix=CHECK-SMALL-LOCAL-CACHE-SMALL-OVERHEAD
+// RUN: %env_asan_opts=thread_local_quarantine_size_kb=0:quarantine_size_mb=64 %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK-NO-LOCAL-CACHE-HUGE-OVERHEAD
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sanitizer/allocator_interface.h>
+
+// The idea is allocate a lot of small blocks, totaling 5Mb of user memory
+// total, and verify that quarantine does not incur too much memory overhead.
+// There's always an overhead for red zones, shadow memory and such, but
+// quarantine accounting should not significantly contribute to that.
+static const int kNumAllocs = 20000;
+static const int kAllocSize = 256;
+static const size_t kHeapSizeLimit = 12 << 20;
+
+int main() {
+ size_t old_heap_size = __sanitizer_get_heap_size();
+ for (int i = 0; i < kNumAllocs; i++) {
+ char *g = new char[kAllocSize];
+ memset(g, -1, kAllocSize);
+ delete [] (g);
+ }
+ size_t new_heap_size = __sanitizer_get_heap_size();
+ fprintf(stderr, "heap size: new: %zd old: %zd\n", new_heap_size,
+ old_heap_size);
+ if (new_heap_size - old_heap_size > kHeapSizeLimit)
+ fprintf(stderr, "Heap size limit exceeded");
+}
+
+// CHECK-VALUE: thread_local_quarantine_size_kb=256K
+// CHECK-SMALL-LOCAL-CACHE-SMALL-OVERHEAD-NOT: Heap size limit exceeded
+// CHECK-NO-LOCAL-CACHE-HUGE-OVERHEAD: Heap size limit exceeded