[PATCH] [asan] Fix a deadlock between asan's allocator and lsan

Kostya Serebryany kcc at google.com
Thu Oct 17 02:25:08 PDT 2013


Hi samsonov, earthdok,

This fixes a deadlock which happens in lsan
on a large memalign-allocated chunk that resides in lsan's root set.

http://llvm-reviews.chandlerc.com/D1957

Files:
  lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc
  lib/asan/asan_allocator2.cc
  lib/sanitizer_common/sanitizer_mutex.h
  lib/sanitizer_common/sanitizer_allocator.h

Index: lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc
===================================================================
--- /dev/null
+++ lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc
@@ -0,0 +1,5 @@
+// Make sure we don't report a leak nor hang.
+// RUN: %clangxx_asan -O3 %s -o %t && %t
+#include <malloc.h>
+int *p = (int*)valloc(1 << 20);
+int main() { }
Index: lib/asan/asan_allocator2.cc
===================================================================
--- lib/asan/asan_allocator2.cc
+++ lib/asan/asan_allocator2.cc
@@ -216,6 +216,25 @@
   bool AddrIsInside(uptr addr) {
     return (addr >= Beg()) && (addr < Beg() + UsedSize());
   }
+  // Must be called when holding the allocator lock.
+  void *AllocBegLocked() {
+    if (!from_memalign)
+      return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
+    allocator.AssertLockHeld();
+    return allocator.GetBlockBeginFastLocked(reinterpret_cast<void *>(this));
+  }
+  // Must be called when holding the allocator lock.
+  uptr UsedSizeLocked() {
+    if (user_requested_size != SizeClassMap::kMaxSize)
+      return user_requested_size;
+    return *reinterpret_cast<uptr *>(allocator.GetMetaData(AllocBegLocked()));
+  }
+  // Must be called when holding the allocator lock.
+  bool AddrIsInsideLocked(uptr addr) {
+    uptr used_size = UsedSizeLocked();
+    uptr beg = reinterpret_cast<uptr>(AllocBegLocked()) + kChunkHeaderSize;
+    return (addr >= beg) && (addr < beg + used_size);
+  }
 };
 
 bool AsanChunkView::IsValid() {
@@ -722,7 +741,8 @@
   __asan::AsanChunk *m = __asan::GetAsanChunkByAddrFastLocked(addr);
   if (!m) return 0;
   uptr chunk = m->Beg();
-  if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr))
+  if ((m->chunk_state == __asan::CHUNK_ALLOCATED) &&
+      m->AddrIsInsideLocked(addr))
     return chunk;
   return 0;
 }
@@ -755,7 +775,7 @@
 
 uptr LsanMetadata::requested_size() const {
   __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
-  return m->UsedSize();
+  return m->UsedSizeLocked();
 }
 
 u32 LsanMetadata::stack_trace_id() const {
Index: lib/sanitizer_common/sanitizer_mutex.h
===================================================================
--- lib/sanitizer_common/sanitizer_mutex.h
+++ lib/sanitizer_common/sanitizer_mutex.h
@@ -40,6 +40,10 @@
     atomic_store(&state_, 0, memory_order_release);
   }
 
+  void AssertHeld() {
+    CHECK_EQ(atomic_load(&state_, memory_order_relaxed), 1);
+  }
+
  private:
   atomic_uint8_t state_;
 
Index: lib/sanitizer_common/sanitizer_allocator.h
===================================================================
--- lib/sanitizer_common/sanitizer_allocator.h
+++ lib/sanitizer_common/sanitizer_allocator.h
@@ -1120,6 +1120,10 @@
       callback(reinterpret_cast<uptr>(GetUser(chunks_[i])), arg);
   }
 
+  void AssertLockHeld() {
+    mutex_.AssertHeld();
+  }
+
  private:
   static const int kMaxNumChunks = 1 << FIRST_32_SECOND_64(15, 18);
   struct Header {
@@ -1302,6 +1306,10 @@
     secondary_.ForEachChunk(callback, arg);
   }
 
+  void AssertLockHeld() {
+    secondary_.AssertLockHeld();
+  }
+
  private:
   PrimaryAllocator primary_;
   SecondaryAllocator secondary_;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D1957.1.patch
Type: text/x-patch
Size: 3220 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20131017/65db798b/attachment.bin>


More information about the llvm-commits mailing list