[llvm-commits] [compiler-rt] r170315 - /compiler-rt/trunk/lib/asan/asan_allocator2.cc

Kostya Serebryany kcc at google.com
Mon Dec 17 01:06:25 PST 2012


Author: kcc
Date: Mon Dec 17 03:06:25 2012
New Revision: 170315

URL: http://llvm.org/viewvc/llvm-project?rev=170315&view=rev
Log:
[asan] asan_alocator2: implement quarantine and Reallocate

Modified:
    compiler-rt/trunk/lib/asan/asan_allocator2.cc

Modified: compiler-rt/trunk/lib/asan/asan_allocator2.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_allocator2.cc?rev=170315&r1=170314&r2=170315&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_allocator2.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_allocator2.cc Mon Dec 17 03:06:25 2012
@@ -19,11 +19,13 @@
 #if ASAN_ALLOCATOR_VERSION == 2
 
 #include "asan_mapping.h"
+#include "asan_report.h"
 #include "asan_thread.h"
 #include "asan_thread_registry.h"
 #include "sanitizer/asan_interface.h"
 #include "sanitizer_common/sanitizer_allocator.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_list.h"
 
 namespace __asan {
 
@@ -56,7 +58,12 @@
 static Allocator allocator;
 
 static const uptr kMaxAllowedMallocSize =
-    (SANITIZER_WORDSIZE == 32) ? 3UL << 30 : 8UL << 30;
+  FIRST_32_SECOND_64(3UL << 30, 8UL << 30);
+
+static const uptr kMaxThreadLocalQuarantine =
+  FIRST_32_SECOND_64(1 << 18, 1 << 21);
+
+static const uptr kReturnOnZeroMalloc = 0x0123;  // Zero page is protected.
 
 static int inited = 0;
 
@@ -163,7 +170,71 @@
                               chunk_->FreeStackSize());
 }
 
-static const uptr kReturnOnZeroMalloc = 0x0123;  // Zero page is protected.
+class Quarantine: public AsanChunkFifoList {
+ public:
+  void SwallowThreadLocalQuarantine(AsanChunkFifoList *q) {
+    if (!q->size()) return;
+    // Printf("SwallowThreadLocalQuarantine %zd\n", q->size());
+    SpinMutexLock l(&mutex_);
+    PushList(q);
+    PopAndDeallocateLoop();
+  }
+  void BypassThreadLocalQuarantine(AsanChunk *m) {
+    SpinMutexLock l(&mutex_);
+    Push(m);
+    PopAndDeallocateLoop();
+  }
+
+ private:
+  void PopAndDeallocateLoop() {
+    while (size() > (uptr)flags()->quarantine_size) {
+      PopAndDeallocate();
+    }
+  }
+  void PopAndDeallocate() {
+    CHECK_GT(size(), 0);
+    AsanChunk *m = Pop();
+    CHECK(m);
+    CHECK(m->chunk_state == CHUNK_QUARANTINE);
+    m->chunk_state = CHUNK_AVAILABLE;
+    CHECK_NE(m->alloc_tid, kInvalidTid);
+    CHECK_NE(m->free_tid, kInvalidTid);
+    PoisonShadow(m->Beg(),
+                 RoundUpTo(m->user_requested_size, SHADOW_GRANULARITY),
+                 kAsanHeapLeftRedzoneMagic);
+    uptr alloc_beg = m->Beg() - ComputeRZSize(m->user_requested_size);
+    void *p = reinterpret_cast<void *>(alloc_beg);
+    if (m->from_memalign)
+      p = allocator.GetBlockBegin(p);
+    allocator.Deallocate(&cache, p);
+  }
+  SpinMutex mutex_;
+};
+
+static Quarantine quarantine;
+
+void AsanChunkFifoList::PushList(AsanChunkFifoList *q) {
+  CHECK(q->size() > 0);
+  size_ += q->size();
+  append_back(q);
+  q->clear();
+}
+
+void AsanChunkFifoList::Push(AsanChunk *n) {
+  push_back(n);
+  size_ += n->UsedSize();
+}
+
+// Interesting performance observation: this function takes up to 15% of overal
+// allocator time. That's because *first_ has been evicted from cache long time
+// ago. Not sure if we can or want to do anything with this.
+AsanChunk *AsanChunkFifoList::Pop() {
+  CHECK(first_);
+  AsanChunk *res = front();
+  size_ -= res->UsedSize();
+  pop_front();
+  return res;
+}
 
 static void *Allocate(uptr size, uptr alignment, StackTrace *stack) {
   Init();
@@ -195,8 +266,6 @@
   uptr user_end = user_beg + size;
   CHECK_LE(user_end, alloc_end);
   uptr chunk_beg = user_beg - kChunkHeaderSize;
-//  Printf("allocated: %p beg_plus_redzone %p chunk_beg %p\n",
-//         allocated, beg_plus_redzone, chunk_beg);
   AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
   m->chunk_state = CHUNK_ALLOCATED;
   u32 alloc_tid = t ? t->tid() : 0;
@@ -227,24 +296,65 @@
   if (p == 0 || p == kReturnOnZeroMalloc) return;
   uptr chunk_beg = p - kChunkHeaderSize;
   AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+
+  // Flip the chunk_state atomically to avoid race on double-free.
+  u8 old_chunk_state = atomic_exchange((atomic_uint8_t*)m, CHUNK_QUARANTINE,
+                                       memory_order_acq_rel);
+
+  if (old_chunk_state == CHUNK_QUARANTINE)
+    ReportDoubleFree((uptr)ptr, stack);
+  else if (old_chunk_state != CHUNK_ALLOCATED)
+    ReportFreeNotMalloced((uptr)ptr, stack);
+  CHECK(old_chunk_state == CHUNK_ALLOCATED);
+
   CHECK_GE(m->alloc_tid, 0);
   CHECK_EQ(m->free_tid, kInvalidTid);
   AsanThread *t = asanThreadRegistry().GetCurrent();
   m->free_tid = t ? t->tid() : 0;
   StackTrace::CompressStack(stack, m->FreeStackBeg(), m->FreeStackSize());
-  uptr alloc_beg = p - ComputeRZSize(m->user_requested_size);
-  if (m->from_memalign)
-    alloc_beg = reinterpret_cast<uptr>(allocator.GetBlockBegin(ptr));
+  CHECK(m->chunk_state == CHUNK_QUARANTINE);
   // Poison the region.
-  PoisonShadow(m->Beg(), RoundUpTo(m->user_requested_size, SHADOW_GRANULARITY),
+  PoisonShadow(m->Beg(),
+               RoundUpTo(m->user_requested_size, SHADOW_GRANULARITY),
                kAsanHeapFreeMagic);
+
+  // Push into quarantine.
+  if (t) {
+    AsanChunkFifoList &q = t->malloc_storage().quarantine_;
+    q.Push(m);
+
+    if (q.size() > kMaxThreadLocalQuarantine)
+      quarantine.SwallowThreadLocalQuarantine(&q);
+  } else {
+    quarantine.BypassThreadLocalQuarantine(m);
+  }
+
   ASAN_FREE_HOOK(ptr);
-  if (!p)
-  allocator.Deallocate(&cache, reinterpret_cast<void *>(alloc_beg));
 }
 
+static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
+  CHECK(old_ptr && new_size);
+  uptr p = reinterpret_cast<uptr>(old_ptr);
+  uptr chunk_beg = p - kChunkHeaderSize;
+  AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+
+  CHECK(m->chunk_state == CHUNK_ALLOCATED);
+  uptr old_size = m->UsedSize();
+  uptr memcpy_size = Min(new_size, old_size);
+  void *new_ptr = Allocate(new_size, 8, stack);
+  if (new_ptr) {
+    CHECK(REAL(memcpy) != 0);
+    REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
+    Deallocate(old_ptr, stack);
+  }
+  return new_ptr;
+}
+
+
+
 AsanChunkView FindHeapChunkByAddress(uptr address) {
   uptr alloc_beg = (uptr)allocator.GetBlockBegin((void*)address);
+  // FIXME: this does not take into account memalign.
   return AsanChunkView((AsanChunk *)(alloc_beg + ComputeRZSize(0)
                                      - kChunkHeaderSize));
 }
@@ -282,8 +392,7 @@
     Deallocate(p, stack);
     return 0;
   }
-  UNIMPLEMENTED();
-  // return Reallocate((u8*)p, size, stack);
+  return Reallocate(p, size, stack);
 }
 
 void *asan_valloc(uptr size, StackTrace *stack) {





More information about the llvm-commits mailing list