[compiler-rt] r192885 - [asan] Fix a deadlock between asan's allocator and lsan

Kostya Serebryany kcc at google.com
Thu Oct 17 04:18:11 PDT 2013


Author: kcc
Date: Thu Oct 17 06:18:11 2013
New Revision: 192885

URL: http://llvm.org/viewvc/llvm-project?rev=192885&view=rev
Log:
[asan] Fix a deadlock between asan's allocator and lsan

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

Reviewers: samsonov, earthdok

Reviewed By: earthdok

CC: llvm-commits

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

Added:
    compiler-rt/trunk/lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc
Modified:
    compiler-rt/trunk/lib/asan/asan_allocator2.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator.h
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_mutex.h
    compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_allocator_test.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=192885&r1=192884&r2=192885&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_allocator2.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_allocator2.cc Thu Oct 17 06:18:11 2013
@@ -186,14 +186,19 @@ COMPILER_CHECK(kChunkHeader2Size <= 16);
 
 struct AsanChunk: ChunkBase {
   uptr Beg() { return reinterpret_cast<uptr>(this) + kChunkHeaderSize; }
-  uptr UsedSize() {
+  uptr UsedSize(bool locked_version = false) {
     if (user_requested_size != SizeClassMap::kMaxSize)
       return user_requested_size;
-    return *reinterpret_cast<uptr *>(allocator.GetMetaData(AllocBeg()));
+    return *reinterpret_cast<uptr *>(
+                allocator.GetMetaData(AllocBeg(locked_version)));
   }
-  void *AllocBeg() {
-    if (from_memalign)
+  void *AllocBeg(bool locked_version = false) {
+    if (from_memalign) {
+      if (locked_version)
+        return allocator.GetBlockBeginFastLocked(
+            reinterpret_cast<void *>(this));
       return allocator.GetBlockBegin(reinterpret_cast<void *>(this));
+    }
     return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
   }
   // If we don't use stack depot, we store the alloc/free stack traces
@@ -213,8 +218,8 @@ struct AsanChunk: ChunkBase {
     uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY);
     return (available - kChunkHeader2Size) / sizeof(u32);
   }
-  bool AddrIsInside(uptr addr) {
-    return (addr >= Beg()) && (addr < Beg() + UsedSize());
+  bool AddrIsInside(uptr addr, bool locked_version = false) {
+    return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version));
   }
 };
 
@@ -722,7 +727,8 @@ uptr PointsIntoChunk(void* p) {
   __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->AddrIsInside(addr, /*locked_version=*/true))
     return chunk;
   return 0;
 }
@@ -755,7 +761,7 @@ void LsanMetadata::set_tag(ChunkTag valu
 
 uptr LsanMetadata::requested_size() const {
   __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
-  return m->UsedSize();
+  return m->UsedSize(/*locked_version=*/true);
 }
 
 u32 LsanMetadata::stack_trace_id() const {

Added: compiler-rt/trunk/lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc?rev=192885&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc (added)
+++ compiler-rt/trunk/lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc Thu Oct 17 06:18:11 2013
@@ -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() { }

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator.h?rev=192885&r1=192884&r2=192885&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator.h Thu Oct 17 06:18:11 2013
@@ -1051,6 +1051,7 @@ class LargeMmapAllocator {
   // This function does the same as GetBlockBegin, but is much faster.
   // Must be called with the allocator locked.
   void *GetBlockBeginFastLocked(void *ptr) {
+    mutex_.AssertHeld();
     uptr p = reinterpret_cast<uptr>(ptr);
     uptr n = n_chunks_;
     if (!n) return 0;

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_mutex.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_mutex.h?rev=192885&r1=192884&r2=192885&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_mutex.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_mutex.h Thu Oct 17 06:18:11 2013
@@ -40,6 +40,10 @@ class StaticSpinMutex {
     atomic_store(&state_, 0, memory_order_release);
   }
 
+  void AssertHeld() {
+    CHECK_EQ(atomic_load(&state_, memory_order_relaxed), 1);
+  }
+
  private:
   atomic_uint8_t state_;
 

Modified: compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_allocator_test.cc?rev=192885&r1=192884&r2=192885&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_allocator_test.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_allocator_test.cc Thu Oct 17 06:18:11 2013
@@ -742,6 +742,7 @@ TEST(SanitizerCommon, LargeMmapAllocator
     allocated[i] = (char *)a.Allocate(&stats, size, 1);
   }
 
+  a.ForceLock();
   for (uptr i = 0; i < kNumAllocs  * kNumAllocs; i++) {
     // if ((i & (i - 1)) == 0) fprintf(stderr, "[%zd]\n", i);
     char *p1 = allocated[i % kNumAllocs];
@@ -757,6 +758,7 @@ TEST(SanitizerCommon, LargeMmapAllocator
     p = reinterpret_cast<void *>(~0L - (i % 1024));
     EXPECT_EQ((void *)0, a.GetBlockBeginFastLocked(p));
   }
+  a.ForceUnlock();
 
   for (uptr i = 0; i < kNumAllocs; i++)
     a.Deallocate(&stats, allocated[i]);





More information about the llvm-commits mailing list