summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/asan/asan_allocator.cc129
-rw-r--r--lib/asan/asan_allocator.h20
-rw-r--r--lib/asan/asan_report.cc48
3 files changed, 117 insertions, 80 deletions
diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc
index dcec1ec78..de3713756 100644
--- a/lib/asan/asan_allocator.cc
+++ b/lib/asan/asan_allocator.cc
@@ -199,50 +199,50 @@ struct AsanChunk: public ChunkBase {
if (REDZONE < sizeof(ChunkBase)) return 0;
return (REDZONE) / sizeof(u32);
}
+};
- bool AddrIsInside(uptr addr, uptr access_size, uptr *offset) {
- if (addr >= Beg() && (addr + access_size) <= (Beg() + used_size)) {
- *offset = addr - Beg();
- return true;
- }
- return false;
- }
+uptr AsanChunkView::Beg() { return chunk_->Beg(); }
+uptr AsanChunkView::End() { return Beg() + UsedSize(); }
+uptr AsanChunkView::UsedSize() { return chunk_->used_size; }
+uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; }
+uptr AsanChunkView::FreeTid() { return chunk_->free_tid; }
- bool AddrIsAtLeft(uptr addr, uptr access_size, uptr *offset) {
- if (addr < Beg()) {
- *offset = Beg() - addr;
- return true;
- }
- return false;
+void AsanChunkView::GetAllocStack(StackTrace *stack) {
+ StackTrace::UncompressStack(stack, chunk_->compressed_alloc_stack(),
+ chunk_->compressed_alloc_stack_size());
+}
+
+void AsanChunkView::GetFreeStack(StackTrace *stack) {
+ StackTrace::UncompressStack(stack, chunk_->compressed_free_stack(),
+ chunk_->compressed_free_stack_size());
+}
+
+bool AsanChunkView::AddrIsInside(uptr addr, uptr access_size, uptr *offset) {
+ if (addr >= Beg() && (addr + access_size) <= End()) {
+ *offset = addr - Beg();
+ return true;
}
+ return false;
+}
- bool AddrIsAtRight(uptr addr, uptr access_size, uptr *offset) {
- if (addr + access_size >= Beg() + used_size) {
- if (addr <= Beg() + used_size)
- *offset = 0;
- else
- *offset = addr - (Beg() + used_size);
- return true;
- }
- return false;
+bool AsanChunkView::AddrIsAtLeft(uptr addr, uptr access_size, uptr *offset) {
+ if (addr < Beg()) {
+ *offset = Beg() - addr;
+ return true;
}
+ return false;
+}
- void DescribeAddress(uptr addr, uptr access_size) {
- uptr offset;
- Printf("%p is located ", (void*)addr);
- if (AddrIsInside(addr, access_size, &offset)) {
- Printf("%zu bytes inside of", offset);
- } else if (AddrIsAtLeft(addr, access_size, &offset)) {
- Printf("%zu bytes to the left of", offset);
- } else if (AddrIsAtRight(addr, access_size, &offset)) {
- Printf("%zu bytes to the right of", offset);
- } else {
- Printf(" somewhere around (this is AddressSanitizer bug!)");
- }
- Printf(" %zu-byte region [%p,%p)\n",
- used_size, (void*)Beg(), (void*)(Beg() + used_size));
+bool AsanChunkView::AddrIsAtRight(uptr addr, uptr access_size, uptr *offset) {
+ if (addr + access_size >= End()) {
+ if (addr <= End())
+ *offset = 0;
+ else
+ *offset = addr - End();
+ return true;
}
-};
+ return false;
+}
static AsanChunk *PtrToChunk(uptr ptr) {
AsanChunk *m = (AsanChunk*)(ptr - REDZONE);
@@ -252,7 +252,6 @@ static AsanChunk *PtrToChunk(uptr ptr) {
return m;
}
-
void AsanChunkFifoList::PushList(AsanChunkFifoList *q) {
CHECK(q->size() > 0);
if (last_) {
@@ -368,9 +367,9 @@ class MallocInfo {
quarantine_.Push(chunk);
}
- AsanChunk *FindMallocedOrFreed(uptr addr, uptr access_size) {
+ AsanChunk *FindChunkByAddr(uptr addr) {
ScopedLock lock(&mu_);
- return FindChunkByAddr(addr);
+ return FindChunkByAddrUnlocked(addr);
}
uptr AllocationSize(uptr ptr) {
@@ -379,7 +378,7 @@ class MallocInfo {
// Make sure this is our chunk and |ptr| actually points to the beginning
// of the allocated memory.
- AsanChunk *m = FindChunkByAddr(ptr);
+ AsanChunk *m = FindChunkByAddrUnlocked(ptr);
if (!m || m->Beg() != ptr) return 0;
if (m->chunk_state == CHUNK_ALLOCATED) {
@@ -463,14 +462,14 @@ class MallocInfo {
return left_chunk;
// Choose based on offset.
uptr l_offset = 0, r_offset = 0;
- CHECK(left_chunk->AddrIsAtRight(addr, 1, &l_offset));
- CHECK(right_chunk->AddrIsAtLeft(addr, 1, &r_offset));
+ CHECK(AsanChunkView(left_chunk).AddrIsAtRight(addr, 1, &l_offset));
+ CHECK(AsanChunkView(right_chunk).AddrIsAtLeft(addr, 1, &r_offset));
if (l_offset < r_offset)
return left_chunk;
return right_chunk;
}
- AsanChunk *FindChunkByAddr(uptr addr) {
+ AsanChunk *FindChunkByAddrUnlocked(uptr addr) {
PageGroup *g = FindPageGroupUnlocked(addr);
if (!g) return 0;
CHECK(g->size_of_chunk);
@@ -483,17 +482,18 @@ class MallocInfo {
m->chunk_state == CHUNK_AVAILABLE ||
m->chunk_state == CHUNK_QUARANTINE);
uptr offset = 0;
- if (m->AddrIsInside(addr, 1, &offset))
+ AsanChunkView m_view(m);
+ if (m_view.AddrIsInside(addr, 1, &offset))
return m;
- if (m->AddrIsAtRight(addr, 1, &offset)) {
+ if (m_view.AddrIsAtRight(addr, 1, &offset)) {
if (this_chunk_addr == g->last_chunk) // rightmost chunk
return m;
uptr right_chunk_addr = this_chunk_addr + g->size_of_chunk;
CHECK(g->InRange(right_chunk_addr));
return ChooseChunk(addr, m, (AsanChunk*)right_chunk_addr);
} else {
- CHECK(m->AddrIsAtLeft(addr, 1, &offset));
+ CHECK(m_view.AddrIsAtLeft(addr, 1, &offset));
if (this_chunk_addr == g->beg) // leftmost chunk
return m;
uptr left_chunk_addr = this_chunk_addr - g->size_of_chunk;
@@ -585,39 +585,8 @@ void AsanThreadLocalMallocStorage::CommitBack() {
malloc_info.SwallowThreadLocalMallocStorage(this, true);
}
-void DescribeHeapAddress(uptr addr, uptr access_size) {
- AsanChunk *m = malloc_info.FindMallocedOrFreed(addr, access_size);
- if (!m) return;
- m->DescribeAddress(addr, access_size);
- CHECK(m->alloc_tid >= 0);
- AsanThreadSummary *alloc_thread =
- asanThreadRegistry().FindByTid(m->alloc_tid);
- StackTrace alloc_stack;
- StackTrace::UncompressStack(&alloc_stack, m->compressed_alloc_stack(),
- m->compressed_alloc_stack_size());
- AsanThread *t = asanThreadRegistry().GetCurrent();
- CHECK(t);
- if (m->free_tid != kInvalidTid) {
- AsanThreadSummary *free_thread =
- asanThreadRegistry().FindByTid(m->free_tid);
- Printf("freed by thread T%d here:\n", free_thread->tid());
- StackTrace free_stack;
- StackTrace::UncompressStack(&free_stack, m->compressed_free_stack(),
- m->compressed_free_stack_size());
- PrintStack(&free_stack);
- Printf("previously allocated by thread T%d here:\n",
- alloc_thread->tid());
-
- PrintStack(&alloc_stack);
- DescribeThread(t->summary());
- DescribeThread(free_thread);
- DescribeThread(alloc_thread);
- } else {
- Printf("allocated by thread T%d here:\n", alloc_thread->tid());
- PrintStack(&alloc_stack);
- DescribeThread(t->summary());
- DescribeThread(alloc_thread);
- }
+AsanChunkView FindHeapChunkByAddress(uptr address) {
+ return AsanChunkView(malloc_info.FindChunkByAddr(address));
}
static u8 *Allocate(uptr alignment, uptr size, StackTrace *stack) {
diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h
index c5e1aabbb..1c6c30b22 100644
--- a/lib/asan/asan_allocator.h
+++ b/lib/asan/asan_allocator.h
@@ -23,6 +23,26 @@ namespace __asan {
static const uptr kNumberOfSizeClasses = 255;
struct AsanChunk;
+class AsanChunkView {
+ public:
+ explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
+ bool IsValid() { return chunk_ != 0; }
+ uptr Beg(); // first byte of user memory.
+ uptr End(); // last byte of user memory.
+ uptr UsedSize(); // size requested by the user.
+ uptr AllocTid();
+ uptr FreeTid();
+ void GetAllocStack(StackTrace *stack);
+ void GetFreeStack(StackTrace *stack);
+ bool AddrIsInside(uptr addr, uptr access_size, uptr *offset);
+ bool AddrIsAtLeft(uptr addr, uptr access_size, uptr *offset);
+ bool AddrIsAtRight(uptr addr, uptr access_size, uptr *offset);
+ private:
+ AsanChunk *const chunk_;
+};
+
+AsanChunkView FindHeapChunkByAddress(uptr address);
+
class AsanChunkFifoList {
public:
explicit AsanChunkFifoList(LinkerInitialized) { }
diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index d31c97ff3..5baba4580 100644
--- a/lib/asan/asan_report.cc
+++ b/lib/asan/asan_report.cc
@@ -188,6 +188,54 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
return true;
}
+static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
+ uptr access_size) {
+ uptr offset;
+ Printf("%p is located ", (void*)addr);
+ if (chunk.AddrIsInside(addr, access_size, &offset)) {
+ Printf("%zu bytes inside of", offset);
+ } else if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
+ Printf("%zu bytes to the left of", offset);
+ } else if (chunk.AddrIsAtRight(addr, access_size, &offset)) {
+ Printf("%zu bytes to the right of", offset);
+ } else {
+ Printf(" somewhere around (this is AddressSanitizer bug!)");
+ }
+ Printf(" %zu-byte region [%p,%p)\n", chunk.UsedSize(),
+ (void*)(chunk.Beg()), (void*)(chunk.End()));
+}
+
+void DescribeHeapAddress(uptr addr, uptr access_size) {
+ AsanChunkView chunk = FindHeapChunkByAddress(addr);
+ if (!chunk.IsValid()) return;
+ DescribeAccessToHeapChunk(chunk, addr, access_size);
+ CHECK(chunk.AllocTid() != kInvalidTid);
+ AsanThreadSummary *alloc_thread =
+ asanThreadRegistry().FindByTid(chunk.AllocTid());
+ StackTrace alloc_stack;
+ chunk.GetAllocStack(&alloc_stack);
+ AsanThread *t = asanThreadRegistry().GetCurrent();
+ CHECK(t);
+ if (chunk.FreeTid() != kInvalidTid) {
+ AsanThreadSummary *free_thread =
+ asanThreadRegistry().FindByTid(chunk.FreeTid());
+ Printf("freed by thread T%d here:\n", free_thread->tid());
+ StackTrace free_stack;
+ chunk.GetFreeStack(&free_stack);
+ PrintStack(&free_stack);
+ Printf("previously allocated by thread T%d here:\n", alloc_thread->tid());
+ PrintStack(&alloc_stack);
+ DescribeThread(t->summary());
+ DescribeThread(free_thread);
+ DescribeThread(alloc_thread);
+ } else {
+ Printf("allocated by thread T%d here:\n", alloc_thread->tid());
+ PrintStack(&alloc_stack);
+ DescribeThread(t->summary());
+ DescribeThread(alloc_thread);
+ }
+}
+
void DescribeAddress(uptr addr, uptr access_size) {
// Check if this is shadow or shadow gap.
if (DescribeAddressIfShadow(addr))