[PATCH] [asan] Fix a deadlock between asan's allocator and lsan
Kostya Serebryany
kcc at google.com
Thu Oct 17 03:44:53 PDT 2013
- Removed AssertLockHeld from allocateor, instead called mutex_.AssertHeld
directly in GetBlockBeginFastLocked
- Deduplicate code in asan/asan_allocator2.cc
Hi samsonov, earthdok,
http://llvm-reviews.chandlerc.com/D1957
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D1957?vs=4986&id=4991#toc
Files:
lib/sanitizer_common/sanitizer_allocator.h
lib/sanitizer_common/tests/sanitizer_allocator_test.cc
lib/sanitizer_common/sanitizer_mutex.h
lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc
lib/asan/asan_allocator2.cc
Index: lib/sanitizer_common/sanitizer_allocator.h
===================================================================
--- lib/sanitizer_common/sanitizer_allocator.h
+++ lib/sanitizer_common/sanitizer_allocator.h
@@ -1051,6 +1051,7 @@
// 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;
Index: lib/sanitizer_common/tests/sanitizer_allocator_test.cc
===================================================================
--- lib/sanitizer_common/tests/sanitizer_allocator_test.cc
+++ lib/sanitizer_common/tests/sanitizer_allocator_test.cc
@@ -742,6 +742,7 @@
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 @@
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]);
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/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
@@ -186,14 +186,19 @@
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 @@
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 @@
__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 @@
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 {
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D1957.2.patch
Type: text/x-patch
Size: 4200 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20131017/ec3fb5b1/attachment.bin>
More information about the llvm-commits
mailing list