From e068de51377450da76ea955923c2dcb4e394591d Mon Sep 17 00:00:00 2001 From: Filipe Cabecinhas Date: Wed, 17 Aug 2016 09:16:08 +0000 Subject: [PATCH] Rename DescribeHeapAddress to DescribeAddressIfHeap and split it into a function to get all the information about the address, and one to print it. Summary: Replacement for part of D23518 This deals with heap addresses, and renames DescribeHeapAddress. Requires D23520, which moves code around to make it accessible in asan_describers.cc (and still accessible in asan_report.cc if needed). Reviewers: kcc, samsonov Subscribers: kubabrecka, llvm-commits Differential Revision: https://reviews.llvm.org/D23569 llvm-svn: 278917 --- compiler-rt/lib/asan/asan_allocator.cc | 3 + compiler-rt/lib/asan/asan_allocator.h | 1 + compiler-rt/lib/asan/asan_descriptions.cc | 120 ++++++++++++++++++++++ compiler-rt/lib/asan/asan_descriptions.h | 31 +++++- compiler-rt/lib/asan/asan_report.cc | 83 ++------------- compiler-rt/lib/asan/asan_report.h | 1 - 6 files changed, 162 insertions(+), 77 deletions(-) diff --git a/compiler-rt/lib/asan/asan_allocator.cc b/compiler-rt/lib/asan/asan_allocator.cc index 6a5d227ca54c..37c883115843 100644 --- a/compiler-rt/lib/asan/asan_allocator.cc +++ b/compiler-rt/lib/asan/asan_allocator.cc @@ -673,6 +673,9 @@ uptr AsanChunkView::End() { return Beg() + UsedSize(); } uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); } uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; } uptr AsanChunkView::FreeTid() { return chunk_->free_tid; } +AllocType AsanChunkView::AllocType() { + return (enum AllocType)chunk_->alloc_type; +} static StackTrace GetStackTraceFromId(u32 id) { CHECK(id); diff --git a/compiler-rt/lib/asan/asan_allocator.h b/compiler-rt/lib/asan/asan_allocator.h index 2f9f7aaf8316..55bbbb52c94c 100644 --- a/compiler-rt/lib/asan/asan_allocator.h +++ b/compiler-rt/lib/asan/asan_allocator.h @@ -62,6 +62,7 @@ class AsanChunkView { u32 GetFreeStackId(); StackTrace GetAllocStack(); StackTrace GetFreeStack(); + AllocType AllocType(); bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) { if (addr >= Beg() && (addr + access_size) <= End()) { *offset = addr - Beg(); diff --git a/compiler-rt/lib/asan/asan_descriptions.cc b/compiler-rt/lib/asan/asan_descriptions.cc index 9b3936071ef4..a909ff82d747 100644 --- a/compiler-rt/lib/asan/asan_descriptions.cc +++ b/compiler-rt/lib/asan/asan_descriptions.cc @@ -101,4 +101,124 @@ bool GetShadowAddressInformation(uptr addr, ShadowAddressDescription *descr) { return true; } +// Heap descriptions +static void GetAccessToHeapChunkInformation(ChunkAccess *descr, + AsanChunkView chunk, uptr addr, + uptr access_size) { + descr->bad_addr = addr; + if (chunk.AddrIsAtLeft(addr, access_size, &descr->offset)) { + descr->access_type = kAccessTypeLeft; + } else if (chunk.AddrIsAtRight(addr, access_size, &descr->offset)) { + descr->access_type = kAccessTypeRight; + if (descr->offset < 0) { + descr->bad_addr -= descr->offset; + descr->offset = 0; + } + } else if (chunk.AddrIsInside(addr, access_size, &descr->offset)) { + descr->access_type = kAccessTypeInside; + } else { + descr->access_type = kAccessTypeUnknown; + } + descr->chunk_begin = chunk.Beg(); + descr->chunk_size = chunk.UsedSize(); + descr->alloc_type = chunk.AllocType(); +} + +static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) { + Decorator d; + InternalScopedString str(4096); + str.append("%s", d.Location()); + switch (descr.access_type) { + case kAccessTypeLeft: + str.append("%p is located %zd bytes to the left of", + (void *)descr.bad_addr, descr.offset); + break; + case kAccessTypeRight: + str.append("%p is located %zd bytes to the right of", + (void *)descr.bad_addr, descr.offset); + break; + case kAccessTypeInside: + str.append("%p is located %zd bytes inside of", (void *)descr.bad_addr, + descr.offset); + break; + case kAccessTypeUnknown: + str.append( + "%p is located somewhere around (this is AddressSanitizer bug!)", + (void *)descr.bad_addr); + } + str.append(" %zu-byte region [%p,%p)\n", descr.chunk_size, + (void *)descr.chunk_begin, + (void *)(descr.chunk_begin + descr.chunk_size)); + str.append("%s", d.EndLocation()); + Printf("%s", str.data()); +} + +bool GetHeapAddressInformation(uptr addr, uptr access_size, + HeapAddressDescription *descr) { + AsanChunkView chunk = FindHeapChunkByAddress(addr); + if (!chunk.IsValid()) { + return false; + } + descr->addr = addr; + GetAccessToHeapChunkInformation(&descr->chunk_access, chunk, addr, + access_size); + CHECK_NE(chunk.AllocTid(), kInvalidTid); + descr->alloc_tid = chunk.AllocTid(); + descr->alloc_stack_id = chunk.GetAllocStackId(); + descr->free_tid = chunk.FreeTid(); + if (descr->free_tid != kInvalidTid) + descr->free_stack_id = chunk.GetFreeStackId(); + return true; +} + +static StackTrace GetStackTraceFromId(u32 id) { + CHECK(id); + StackTrace res = StackDepotGet(id); + CHECK(res.trace); + return res; +} + +bool DescribeAddressIfHeap(uptr addr, uptr access_size) { + HeapAddressDescription descr; + if (!GetHeapAddressInformation(addr, access_size, &descr)) { + Printf( + "AddressSanitizer can not describe address in more detail " + "(wild memory access suspected).\n"); + return false; + } + PrintHeapChunkAccess(addr, descr.chunk_access); + + asanThreadRegistry().CheckLocked(); + AsanThreadContext *alloc_thread = + GetThreadContextByTidLocked(descr.alloc_tid); + StackTrace alloc_stack = GetStackTraceFromId(descr.alloc_stack_id); + + char tname[128]; + Decorator d; + AsanThreadContext *free_thread = nullptr; + if (descr.free_tid != kInvalidTid) { + free_thread = GetThreadContextByTidLocked(descr.free_tid); + Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(), + free_thread->tid, + ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)), + d.EndAllocation()); + StackTrace free_stack = GetStackTraceFromId(descr.free_stack_id); + free_stack.Print(); + Printf("%spreviously allocated by thread T%d%s here:%s\n", d.Allocation(), + alloc_thread->tid, + ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), + d.EndAllocation()); + } else { + Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(), + alloc_thread->tid, + ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), + d.EndAllocation()); + } + alloc_stack.Print(); + DescribeThread(GetCurrentThread()); + if (free_thread) DescribeThread(free_thread); + DescribeThread(alloc_thread); + return true; +} + } // namespace __asan diff --git a/compiler-rt/lib/asan/asan_descriptions.h b/compiler-rt/lib/asan/asan_descriptions.h index e93adec893b9..d64cbb5b541f 100644 --- a/compiler-rt/lib/asan/asan_descriptions.h +++ b/compiler-rt/lib/asan/asan_descriptions.h @@ -13,7 +13,7 @@ // TODO(filcab): Most struct definitions should move to the interface headers. //===----------------------------------------------------------------------===// -#include "asan_internal.h" +#include "asan_allocator.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_report_decorator.h" @@ -94,4 +94,33 @@ struct ShadowAddressDescription { bool GetShadowAddressInformation(uptr addr, ShadowAddressDescription *descr); bool DescribeAddressIfShadow(uptr addr); +enum AccessType { + kAccessTypeLeft, + kAccessTypeRight, + kAccessTypeInside, + kAccessTypeUnknown, // This means we have an AddressSanitizer bug! +}; + +struct ChunkAccess { + uptr bad_addr; + sptr offset; + uptr chunk_begin; + uptr chunk_size; + u32 access_type : 2; + u32 alloc_type : 2; +}; + +struct HeapAddressDescription { + uptr addr; + uptr alloc_tid; + uptr free_tid; + u32 alloc_stack_id; + u32 free_stack_id; + ChunkAccess chunk_access; +}; + +bool GetHeapAddressInformation(uptr addr, uptr access_size, + HeapAddressDescription *descr); +bool DescribeAddressIfHeap(uptr addr, uptr access_size = 1); + } // namespace __asan diff --git a/compiler-rt/lib/asan/asan_report.cc b/compiler-rt/lib/asan/asan_report.cc index 220eba3307ff..16db4af9c43e 100644 --- a/compiler-rt/lib/asan/asan_report.cc +++ b/compiler-rt/lib/asan/asan_report.cc @@ -417,73 +417,6 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) { return true; } -static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr, - uptr access_size) { - sptr offset; - Decorator d; - InternalScopedString str(4096); - str.append("%s", d.Location()); - if (chunk.AddrIsAtLeft(addr, access_size, &offset)) { - str.append("%p is located %zd bytes to the left of", (void *)addr, offset); - } else if (chunk.AddrIsAtRight(addr, access_size, &offset)) { - if (offset < 0) { - addr -= offset; - offset = 0; - } - str.append("%p is located %zd bytes to the right of", (void *)addr, offset); - } else if (chunk.AddrIsInside(addr, access_size, &offset)) { - str.append("%p is located %zd bytes inside of", (void*)addr, offset); - } else { - str.append("%p is located somewhere around (this is AddressSanitizer bug!)", - (void *)addr); - } - str.append(" %zu-byte region [%p,%p)\n", chunk.UsedSize(), - (void *)(chunk.Beg()), (void *)(chunk.End())); - str.append("%s", d.EndLocation()); - Printf("%s", str.data()); -} - -void DescribeHeapAddress(uptr addr, uptr access_size) { - AsanChunkView chunk = FindHeapChunkByAddress(addr); - if (!chunk.IsValid()) { - Printf("AddressSanitizer can not describe address in more detail " - "(wild memory access suspected).\n"); - return; - } - DescribeAccessToHeapChunk(chunk, addr, access_size); - CHECK_NE(chunk.AllocTid(), kInvalidTid); - asanThreadRegistry().CheckLocked(); - AsanThreadContext *alloc_thread = - GetThreadContextByTidLocked(chunk.AllocTid()); - StackTrace alloc_stack = chunk.GetAllocStack(); - char tname[128]; - Decorator d; - AsanThreadContext *free_thread = nullptr; - if (chunk.FreeTid() != kInvalidTid) { - free_thread = GetThreadContextByTidLocked(chunk.FreeTid()); - Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(), - free_thread->tid, - ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)), - d.EndAllocation()); - StackTrace free_stack = chunk.GetFreeStack(); - free_stack.Print(); - Printf("%spreviously allocated by thread T%d%s here:%s\n", - d.Allocation(), alloc_thread->tid, - ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), - d.EndAllocation()); - } else { - Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(), - alloc_thread->tid, - ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), - d.EndAllocation()); - } - alloc_stack.Print(); - DescribeThread(GetCurrentThread()); - if (free_thread) - DescribeThread(free_thread); - DescribeThread(alloc_thread); -} - static void DescribeAddress(uptr addr, uptr access_size, const char *bug_type) { // Check if this is shadow or shadow gap. if (DescribeAddressIfShadow(addr)) @@ -494,7 +427,7 @@ static void DescribeAddress(uptr addr, uptr access_size, const char *bug_type) { if (DescribeAddressIfStack(addr, access_size)) return; // Assume it is a heap address. - DescribeHeapAddress(addr, access_size); + DescribeAddressIfHeap(addr, access_size); } // -------------------- Different kinds of reports ----------------- {{{1 @@ -685,7 +618,7 @@ void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) { ScarinessScore::PrintSimple(42, "double-free"); GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); stack.Print(); - DescribeHeapAddress(addr, 1); + DescribeAddressIfHeap(addr); ReportErrorSummary("double-free", &stack); } @@ -708,7 +641,7 @@ void ReportNewDeleteSizeMismatch(uptr addr, uptr alloc_size, uptr delete_size, ScarinessScore::PrintSimple(10, "new-delete-type-mismatch"); GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); stack.Print(); - DescribeHeapAddress(addr, 1); + DescribeAddressIfHeap(addr); ReportErrorSummary("new-delete-type-mismatch", &stack); Report("HINT: if you don't care about these errors you may set " "ASAN_OPTIONS=new_delete_type_mismatch=0\n"); @@ -728,7 +661,7 @@ void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) { ScarinessScore::PrintSimple(40, "bad-free"); GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); stack.Print(); - DescribeHeapAddress(addr, 1); + DescribeAddressIfHeap(addr); ReportErrorSummary("bad-free", &stack); } @@ -750,7 +683,7 @@ void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack, ScarinessScore::PrintSimple(10, "alloc-dealloc-mismatch"); GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); stack.Print(); - DescribeHeapAddress(addr, 1); + DescribeAddressIfHeap(addr); ReportErrorSummary("alloc-dealloc-mismatch", &stack); Report("HINT: if you don't care about these errors you may set " "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n"); @@ -765,7 +698,7 @@ void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) { "not owned: %p\n", addr); Printf("%s", d.EndWarning()); stack->Print(); - DescribeHeapAddress(addr, 1); + DescribeAddressIfHeap(addr); ReportErrorSummary("bad-malloc_usable_size", stack); } @@ -779,7 +712,7 @@ void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, "not owned: %p\n", addr); Printf("%s", d.EndWarning()); stack->Print(); - DescribeHeapAddress(addr, 1); + DescribeAddressIfHeap(addr); ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack); } @@ -903,7 +836,7 @@ void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name, addr); PrintZoneForPointer(addr, zone_ptr, zone_name); stack->Print(); - DescribeHeapAddress(addr, 1); + DescribeAddressIfHeap(addr); } // -------------- SuppressErrorReport -------------- {{{1 diff --git a/compiler-rt/lib/asan/asan_report.h b/compiler-rt/lib/asan/asan_report.h index 7b7122f78f0e..db044fb96dce 100644 --- a/compiler-rt/lib/asan/asan_report.h +++ b/compiler-rt/lib/asan/asan_report.h @@ -40,7 +40,6 @@ int GetGlobalsForAddress(uptr addr, __asan_global *globals, u32 *reg_sites, bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr); // The following functions prints address description depending // on the memory type (shadow/heap/stack/global). -void DescribeHeapAddress(uptr addr, uptr access_size); bool ParseFrameDescription(const char *frame_descr, InternalMmapVector *vars); bool DescribeAddressIfStack(uptr addr, uptr access_size);