[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