diff options
Diffstat (limited to 'libsanitizer/asan')
-rw-r--r-- | libsanitizer/asan/Makefile.am | 1 | ||||
-rw-r--r-- | libsanitizer/asan/Makefile.in | 2 | ||||
-rw-r--r-- | libsanitizer/asan/asan_allocator.h | 22 | ||||
-rw-r--r-- | libsanitizer/asan/asan_allocator2.cc | 57 | ||||
-rw-r--r-- | libsanitizer/asan/asan_debugging.cc | 81 | ||||
-rw-r--r-- | libsanitizer/asan/asan_flags.h | 1 | ||||
-rw-r--r-- | libsanitizer/asan/asan_globals.cc | 44 | ||||
-rw-r--r-- | libsanitizer/asan/asan_interface_internal.h | 26 | ||||
-rw-r--r-- | libsanitizer/asan/asan_internal.h | 1 | ||||
-rw-r--r-- | libsanitizer/asan/asan_mac.cc | 2 | ||||
-rw-r--r-- | libsanitizer/asan/asan_mapping.h | 15 | ||||
-rw-r--r-- | libsanitizer/asan/asan_poisoning.cc | 35 | ||||
-rw-r--r-- | libsanitizer/asan/asan_posix.cc | 7 | ||||
-rw-r--r-- | libsanitizer/asan/asan_report.cc | 266 | ||||
-rw-r--r-- | libsanitizer/asan/asan_report.h | 57 | ||||
-rw-r--r-- | libsanitizer/asan/asan_rtl.cc | 6 | ||||
-rw-r--r-- | libsanitizer/asan/asan_stack.h | 28 | ||||
-rw-r--r-- | libsanitizer/asan/asan_thread.cc | 23 | ||||
-rw-r--r-- | libsanitizer/asan/asan_thread.h | 26 |
19 files changed, 502 insertions, 198 deletions
diff --git a/libsanitizer/asan/Makefile.am b/libsanitizer/asan/Makefile.am index d499c725242..b421776b99a 100644 --- a/libsanitizer/asan/Makefile.am +++ b/libsanitizer/asan/Makefile.am @@ -9,6 +9,7 @@ DEFS += -DMAC_INTERPOSE_FUNCTIONS -DMISSING_BLOCKS_SUPPORT endif AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros -fno-ipa-icf AM_CXXFLAGS += $(LIBSTDCXX_RAW_CXX_CXXFLAGS) +AM_CXXFLAGS += -std=c++11 ACLOCAL_AMFLAGS = -I $(top_srcdir) -I $(top_srcdir)/config toolexeclib_LTLIBRARIES = libasan.la diff --git a/libsanitizer/asan/Makefile.in b/libsanitizer/asan/Makefile.in index 00a614b3d69..54ae86a5c49 100644 --- a/libsanitizer/asan/Makefile.in +++ b/libsanitizer/asan/Makefile.in @@ -270,7 +270,7 @@ AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \ -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti \ -fomit-frame-pointer -funwind-tables -fvisibility=hidden \ -Wno-variadic-macros -fno-ipa-icf \ - $(LIBSTDCXX_RAW_CXX_CXXFLAGS) + $(LIBSTDCXX_RAW_CXX_CXXFLAGS) -std=c++11 ACLOCAL_AMFLAGS = -I $(top_srcdir) -I $(top_srcdir)/config toolexeclib_LTLIBRARIES = libasan.la nodist_toolexeclib_HEADERS = libasan_preinit.o diff --git a/libsanitizer/asan/asan_allocator.h b/libsanitizer/asan/asan_allocator.h index 567b36867ab..d2f30af30d6 100644 --- a/libsanitizer/asan/asan_allocator.h +++ b/libsanitizer/asan/asan_allocator.h @@ -43,8 +43,8 @@ class AsanChunkView { uptr AllocTid(); uptr FreeTid(); bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; } - void GetAllocStack(StackTrace *stack); - void GetFreeStack(StackTrace *stack); + StackTrace GetAllocStack(); + StackTrace GetFreeStack(); bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) { if (addr >= Beg() && (addr + access_size) <= End()) { *offset = addr - Beg(); @@ -137,20 +137,20 @@ struct AsanThreadLocalMallocStorage { AsanThreadLocalMallocStorage() {} }; -void *asan_memalign(uptr alignment, uptr size, StackTrace *stack, +void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, AllocType alloc_type); -void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type); -void asan_sized_free(void *ptr, uptr size, StackTrace *stack, +void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type); +void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack, AllocType alloc_type); -void *asan_malloc(uptr size, StackTrace *stack); -void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack); -void *asan_realloc(void *p, uptr size, StackTrace *stack); -void *asan_valloc(uptr size, StackTrace *stack); -void *asan_pvalloc(uptr size, StackTrace *stack); +void *asan_malloc(uptr size, BufferedStackTrace *stack); +void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack); +void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack); +void *asan_valloc(uptr size, BufferedStackTrace *stack); +void *asan_pvalloc(uptr size, BufferedStackTrace *stack); int asan_posix_memalign(void **memptr, uptr alignment, uptr size, - StackTrace *stack); + BufferedStackTrace *stack); uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp); uptr asan_mz_size(const void *ptr); diff --git a/libsanitizer/asan/asan_allocator2.cc b/libsanitizer/asan/asan_allocator2.cc index 78c1ec113a6..33d9fea70cb 100644 --- a/libsanitizer/asan/asan_allocator2.cc +++ b/libsanitizer/asan/asan_allocator2.cc @@ -180,20 +180,19 @@ uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); } uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; } uptr AsanChunkView::FreeTid() { return chunk_->free_tid; } -static void GetStackTraceFromId(u32 id, StackTrace *stack) { +static StackTrace GetStackTraceFromId(u32 id) { CHECK(id); - uptr size = 0; - const uptr *trace = StackDepotGet(id, &size); - CHECK(trace); - stack->CopyFrom(trace, size); + StackTrace res = StackDepotGet(id); + CHECK(res.trace); + return res; } -void AsanChunkView::GetAllocStack(StackTrace *stack) { - GetStackTraceFromId(chunk_->alloc_context_id, stack); +StackTrace AsanChunkView::GetAllocStack() { + return GetStackTraceFromId(chunk_->alloc_context_id); } -void AsanChunkView::GetFreeStack(StackTrace *stack) { - GetStackTraceFromId(chunk_->free_context_id, stack); +StackTrace AsanChunkView::GetFreeStack() { + return GetStackTraceFromId(chunk_->free_context_id); } struct QuarantineCallback; @@ -261,7 +260,7 @@ void ReInitializeAllocator() { quarantine.Init((uptr)flags()->quarantine_size, kMaxThreadLocalQuarantine); } -static void *Allocate(uptr size, uptr alignment, StackTrace *stack, +static void *Allocate(uptr size, uptr alignment, BufferedStackTrace *stack, AllocType alloc_type, bool can_fill) { if (UNLIKELY(!asan_inited)) AsanInitFromRtl(); @@ -353,7 +352,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack, meta[1] = chunk_beg; } - m->alloc_context_id = StackDepotPut(stack->trace, stack->size); + m->alloc_context_id = StackDepotPut(*stack); uptr size_rounded_down_to_granularity = RoundDownTo(size, SHADOW_GRANULARITY); // Unpoison the bulk of the memory region. @@ -389,15 +388,16 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack, return res; } -static void ReportInvalidFree(void *ptr, u8 chunk_state, StackTrace *stack) { +static void ReportInvalidFree(void *ptr, u8 chunk_state, + BufferedStackTrace *stack) { if (chunk_state == CHUNK_QUARANTINE) ReportDoubleFree((uptr)ptr, stack); else ReportFreeNotMalloced((uptr)ptr, stack); } -static void AtomicallySetQuarantineFlag(AsanChunk *m, - void *ptr, StackTrace *stack) { +static void AtomicallySetQuarantineFlag(AsanChunk *m, void *ptr, + BufferedStackTrace *stack) { u8 old_chunk_state = CHUNK_ALLOCATED; // Flip the chunk_state atomically to avoid race on double-free. if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state, @@ -408,8 +408,8 @@ static void AtomicallySetQuarantineFlag(AsanChunk *m, // Expects the chunk to already be marked as quarantined by using // AtomicallySetQuarantineFlag. -static void QuarantineChunk(AsanChunk *m, void *ptr, - StackTrace *stack, AllocType alloc_type) { +static void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack, + AllocType alloc_type) { CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE); if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch) @@ -421,7 +421,7 @@ static void QuarantineChunk(AsanChunk *m, void *ptr, CHECK_EQ(m->free_tid, kInvalidTid); AsanThread *t = GetCurrentThread(); m->free_tid = t ? t->tid() : 0; - m->free_context_id = StackDepotPut(stack->trace, stack->size); + m->free_context_id = StackDepotPut(*stack); // Poison the region. PoisonShadow(m->Beg(), RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY), @@ -445,7 +445,7 @@ static void QuarantineChunk(AsanChunk *m, void *ptr, } } -static void Deallocate(void *ptr, uptr delete_size, StackTrace *stack, +static void Deallocate(void *ptr, uptr delete_size, BufferedStackTrace *stack, AllocType alloc_type) { uptr p = reinterpret_cast<uptr>(ptr); if (p == 0) return; @@ -462,7 +462,8 @@ static void Deallocate(void *ptr, uptr delete_size, StackTrace *stack, QuarantineChunk(m, ptr, stack, alloc_type); } -static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) { +static void *Reallocate(void *old_ptr, uptr new_size, + BufferedStackTrace *stack) { CHECK(old_ptr && new_size); uptr p = reinterpret_cast<uptr>(old_ptr); uptr chunk_beg = p - kChunkHeaderSize; @@ -575,25 +576,25 @@ void PrintInternalAllocatorStats() { allocator.PrintStats(); } -void *asan_memalign(uptr alignment, uptr size, StackTrace *stack, +void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, AllocType alloc_type) { return Allocate(size, alignment, stack, alloc_type, true); } -void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) { +void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) { Deallocate(ptr, 0, stack, alloc_type); } -void asan_sized_free(void *ptr, uptr size, StackTrace *stack, +void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack, AllocType alloc_type) { Deallocate(ptr, size, stack, alloc_type); } -void *asan_malloc(uptr size, StackTrace *stack) { +void *asan_malloc(uptr size, BufferedStackTrace *stack) { return Allocate(size, 8, stack, FROM_MALLOC, true); } -void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) { +void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) { if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return AllocatorReturnNull(); void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false); @@ -604,7 +605,7 @@ void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) { return ptr; } -void *asan_realloc(void *p, uptr size, StackTrace *stack) { +void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) { if (p == 0) return Allocate(size, 8, stack, FROM_MALLOC, true); if (size == 0) { @@ -614,11 +615,11 @@ void *asan_realloc(void *p, uptr size, StackTrace *stack) { return Reallocate(p, size, stack); } -void *asan_valloc(uptr size, StackTrace *stack) { +void *asan_valloc(uptr size, BufferedStackTrace *stack) { return Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true); } -void *asan_pvalloc(uptr size, StackTrace *stack) { +void *asan_pvalloc(uptr size, BufferedStackTrace *stack) { uptr PageSize = GetPageSizeCached(); size = RoundUpTo(size, PageSize); if (size == 0) { @@ -629,7 +630,7 @@ void *asan_pvalloc(uptr size, StackTrace *stack) { } int asan_posix_memalign(void **memptr, uptr alignment, uptr size, - StackTrace *stack) { + BufferedStackTrace *stack) { void *ptr = Allocate(size, alignment, stack, FROM_MALLOC, true); CHECK(IsAligned((uptr)ptr, alignment)); *memptr = ptr; diff --git a/libsanitizer/asan/asan_debugging.cc b/libsanitizer/asan/asan_debugging.cc index 302574d9dd8..3efad658a4c 100644 --- a/libsanitizer/asan/asan_debugging.cc +++ b/libsanitizer/asan/asan_debugging.cc @@ -15,31 +15,88 @@ #include "asan_flags.h" #include "asan_internal.h" #include "asan_mapping.h" +#include "asan_report.h" #include "asan_thread.h" namespace __asan { +void GetInfoForStackVar(uptr addr, AddressDescription *descr, AsanThread *t) { + descr->name[0] = 0; + descr->region_address = 0; + descr->region_size = 0; + descr->region_kind = "stack"; + + AsanThread::StackFrameAccess access; + if (!t->GetStackFrameAccessByAddr(addr, &access)) + return; + InternalMmapVector<StackVarDescr> vars(16); + if (!ParseFrameDescription(access.frame_descr, &vars)) { + return; + } + + for (uptr i = 0; i < vars.size(); i++) { + if (access.offset <= vars[i].beg + vars[i].size) { + internal_strncat(descr->name, vars[i].name_pos, + Min(descr->name_size, vars[i].name_len)); + descr->region_address = addr - (access.offset - vars[i].beg); + descr->region_size = vars[i].size; + return; + } + } +} + +void GetInfoForHeapAddress(uptr addr, AddressDescription *descr) { + AsanChunkView chunk = FindHeapChunkByAddress(addr); + + descr->name[0] = 0; + descr->region_address = 0; + descr->region_size = 0; + + if (!chunk.IsValid()) { + descr->region_kind = "heap-invalid"; + return; + } + + descr->region_address = chunk.Beg(); + descr->region_size = chunk.UsedSize(); + descr->region_kind = "heap"; +} + +void AsanLocateAddress(uptr addr, AddressDescription *descr) { + if (DescribeAddressIfShadow(addr, descr, /* print */ false)) { + return; + } + if (GetInfoForAddressIfGlobal(addr, descr)) { + return; + } + asanThreadRegistry().Lock(); + AsanThread *thread = FindThreadByStackAddress(addr); + asanThreadRegistry().Unlock(); + if (thread) { + GetInfoForStackVar(addr, descr, thread); + return; + } + GetInfoForHeapAddress(addr, descr); +} + uptr AsanGetStack(uptr addr, uptr *trace, uptr size, u32 *thread_id, bool alloc_stack) { AsanChunkView chunk = FindHeapChunkByAddress(addr); if (!chunk.IsValid()) return 0; - StackTrace stack; + StackTrace stack(nullptr, 0); if (alloc_stack) { if (chunk.AllocTid() == kInvalidTid) return 0; - chunk.GetAllocStack(&stack); + stack = chunk.GetAllocStack(); if (thread_id) *thread_id = chunk.AllocTid(); } else { if (chunk.FreeTid() == kInvalidTid) return 0; - chunk.GetFreeStack(&stack); + stack = chunk.GetFreeStack(); if (thread_id) *thread_id = chunk.FreeTid(); } if (trace && size) { - if (size > kStackTraceMax) - size = kStackTraceMax; - if (size > stack.size) - size = stack.size; + size = Min(size, Min(stack.size, kStackTraceMax)); for (uptr i = 0; i < size; i++) trace[i] = StackTrace::GetPreviousInstructionPc(stack.trace[i]); @@ -54,6 +111,16 @@ uptr AsanGetStack(uptr addr, uptr *trace, uptr size, u32 *thread_id, using namespace __asan; SANITIZER_INTERFACE_ATTRIBUTE +const char *__asan_locate_address(uptr addr, char *name, uptr name_size, + uptr *region_address, uptr *region_size) { + AddressDescription descr = { name, name_size, 0, 0, 0 }; + AsanLocateAddress(addr, &descr); + if (region_address) *region_address = descr.region_address; + if (region_size) *region_size = descr.region_size; + return descr.region_kind; +} + +SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) { return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ true); } diff --git a/libsanitizer/asan/asan_flags.h b/libsanitizer/asan/asan_flags.h index 2f155eb5cbc..0b6a9857be0 100644 --- a/libsanitizer/asan/asan_flags.h +++ b/libsanitizer/asan/asan_flags.h @@ -63,6 +63,7 @@ struct Flags { int detect_invalid_pointer_pairs; bool detect_container_overflow; int detect_odr_violation; + bool dump_instruction_bytes; }; extern Flags asan_flags_dont_use_directly; diff --git a/libsanitizer/asan/asan_globals.cc b/libsanitizer/asan/asan_globals.cc index 15c1886af0e..ee2ecdcc957 100644 --- a/libsanitizer/asan/asan_globals.cc +++ b/libsanitizer/asan/asan_globals.cc @@ -69,6 +69,14 @@ ALWAYS_INLINE void PoisonRedZones(const Global &g) { } } +const uptr kMinimalDistanceFromAnotherGlobal = 64; + +bool IsAddressNearGlobal(uptr addr, const __asan_global &g) { + if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false; + if (addr >= g.beg + g.size_with_redzone) return false; + return true; +} + static void ReportGlobal(const Global &g, const char *prefix) { Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n", prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name, @@ -80,19 +88,45 @@ static void ReportGlobal(const Global &g, const char *prefix) { } } -bool DescribeAddressIfGlobal(uptr addr, uptr size) { +static bool DescribeOrGetInfoIfGlobal(uptr addr, uptr size, bool print, + Global *output_global) { if (!flags()->report_globals) return false; BlockingMutexLock lock(&mu_for_globals); bool res = false; for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { const Global &g = *l->g; - if (flags()->report_globals >= 2) - ReportGlobal(g, "Search"); - res |= DescribeAddressRelativeToGlobal(addr, size, g); + if (print) { + if (flags()->report_globals >= 2) + ReportGlobal(g, "Search"); + res |= DescribeAddressRelativeToGlobal(addr, size, g); + } else { + if (IsAddressNearGlobal(addr, g)) { + CHECK(output_global); + *output_global = g; + return true; + } + } } return res; } +bool DescribeAddressIfGlobal(uptr addr, uptr size) { + return DescribeOrGetInfoIfGlobal(addr, size, /* print */ true, + /* output_global */ nullptr); +} + +bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) { + Global g = {}; + if (DescribeOrGetInfoIfGlobal(addr, /* size */ 1, /* print */ false, &g)) { + internal_strncpy(descr->name, g.name, descr->name_size); + descr->region_address = g.beg; + descr->region_size = g.size; + descr->region_kind = "global"; + return true; + } + return false; +} + u32 FindRegistrationSite(const Global *g) { CHECK(global_registration_site_vector); for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) { @@ -181,7 +215,7 @@ using namespace __asan; // NOLINT void __asan_register_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; GET_STACK_TRACE_FATAL_HERE; - u32 stack_id = StackDepotPut(stack.trace, stack.size); + u32 stack_id = StackDepotPut(stack); BlockingMutexLock lock(&mu_for_globals); if (!global_registration_site_vector) global_registration_site_vector = diff --git a/libsanitizer/asan/asan_interface_internal.h b/libsanitizer/asan/asan_interface_internal.h index 1a3b33fed0b..939327eb8a4 100644 --- a/libsanitizer/asan/asan_interface_internal.h +++ b/libsanitizer/asan/asan_interface_internal.h @@ -89,6 +89,28 @@ extern "C" { void __asan_describe_address(uptr addr); SANITIZER_INTERFACE_ATTRIBUTE + int __asan_report_present(); + + SANITIZER_INTERFACE_ATTRIBUTE + uptr __asan_get_report_pc(); + SANITIZER_INTERFACE_ATTRIBUTE + uptr __asan_get_report_bp(); + SANITIZER_INTERFACE_ATTRIBUTE + uptr __asan_get_report_sp(); + SANITIZER_INTERFACE_ATTRIBUTE + uptr __asan_get_report_address(); + SANITIZER_INTERFACE_ATTRIBUTE + int __asan_get_report_access_type(); + SANITIZER_INTERFACE_ATTRIBUTE + uptr __asan_get_report_access_size(); + SANITIZER_INTERFACE_ATTRIBUTE + const char * __asan_get_report_description(); + + SANITIZER_INTERFACE_ATTRIBUTE + const char * __asan_locate_address(uptr addr, char *name, uptr name_size, + uptr *region_address, uptr *region_size); + + SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id); @@ -149,6 +171,10 @@ extern "C" { void __asan_poison_cxx_array_cookie(uptr p); SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_load_cxx_array_cookie(uptr *p); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_poison_intra_object_redzone(uptr p, uptr size); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_unpoison_intra_object_redzone(uptr p, uptr size); } // extern "C" #endif // ASAN_INTERFACE_INTERNAL_H diff --git a/libsanitizer/asan/asan_internal.h b/libsanitizer/asan/asan_internal.h index 9473bf6a2ca..8911575d84a 100644 --- a/libsanitizer/asan/asan_internal.h +++ b/libsanitizer/asan/asan_internal.h @@ -133,6 +133,7 @@ const int kAsanStackUseAfterScopeMagic = 0xf8; const int kAsanGlobalRedzoneMagic = 0xf9; const int kAsanInternalHeapMagic = 0xfe; const int kAsanArrayCookieMagic = 0xac; +const int kAsanIntraObjectRedzone = 0xbb; static const uptr kCurrentStackFrameMagic = 0x41B58AB3; static const uptr kRetiredStackFrameMagic = 0x45E0360E; diff --git a/libsanitizer/asan/asan_mac.cc b/libsanitizer/asan/asan_mac.cc index e4c71cedd31..70823bdef92 100644 --- a/libsanitizer/asan/asan_mac.cc +++ b/libsanitizer/asan/asan_mac.cc @@ -295,7 +295,7 @@ using namespace __asan; // NOLINT // The caller retains control of the allocated context. extern "C" asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func, - StackTrace *stack) { + BufferedStackTrace *stack) { asan_block_context_t *asan_ctxt = (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack); asan_ctxt->block = ctxt; diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h index a1f84e24c46..907704d7fc9 100644 --- a/libsanitizer/asan/asan_mapping.h +++ b/libsanitizer/asan/asan_mapping.h @@ -58,11 +58,11 @@ // || `[0x00000000, 0x1fffffff]` || LowMem || // // Default Linux/MIPS mapping: -// || `[0x2aaa8000, 0xffffffff]` || HighMem || -// || `[0x0fffd000, 0x2aaa7fff]` || HighShadow || -// || `[0x0bffd000, 0x0fffcfff]` || ShadowGap || -// || `[0x0aaa8000, 0x0bffcfff]` || LowShadow || -// || `[0x00000000, 0x0aaa7fff]` || LowMem || +// || `[0x2aaa0000, 0xffffffff]` || HighMem || +// || `[0x0fff4000, 0x2aa9ffff]` || HighShadow || +// || `[0x0bff4000, 0x0fff3fff]` || ShadowGap || +// || `[0x0aaa0000, 0x0bff3fff]` || LowShadow || +// || `[0x00000000, 0x0aa9ffff]` || LowMem || // // Shadow mapping on FreeBSD/x86-64 with SHADOW_OFFSET == 0x400000000000: // || `[0x500000000000, 0x7fffffffffff]` || HighMem || @@ -84,7 +84,8 @@ static const u64 kIosShadowOffset32 = 1ULL << 30; // 0x40000000 static const u64 kDefaultShadowOffset64 = 1ULL << 44; static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000; // < 2G. static const u64 kAArch64_ShadowOffset64 = 1ULL << 36; -static const u64 kMIPS32_ShadowOffset32 = 0x0aaa8000; +static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000; +static const u64 kMIPS64_ShadowOffset64 = 1ULL << 36; static const u64 kPPC64_ShadowOffset64 = 1ULL << 41; static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000 static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000 @@ -114,6 +115,8 @@ static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000 # define SHADOW_OFFSET kFreeBSD_ShadowOffset64 # elif SANITIZER_MAC # define SHADOW_OFFSET kDefaultShadowOffset64 +# elif defined(__mips64) +# define SHADOW_OFFSET kMIPS64_ShadowOffset64 # else # define SHADOW_OFFSET kDefaultShort64bitShadowOffset # endif diff --git a/libsanitizer/asan/asan_poisoning.cc b/libsanitizer/asan/asan_poisoning.cc index 65f6cf0046e..c0f3991c1f3 100644 --- a/libsanitizer/asan/asan_poisoning.cc +++ b/libsanitizer/asan/asan_poisoning.cc @@ -59,6 +59,27 @@ void FlushUnneededASanShadowMemory(uptr p, uptr size) { FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg); } +void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) { + uptr end = ptr + size; + if (common_flags()->verbosity) { + Printf("__asan_%spoison_intra_object_redzone [%p,%p) %zd\n", + poison ? "" : "un", ptr, end, size); + if (common_flags()->verbosity >= 2) + PRINT_CURRENT_STACK(); + } + CHECK(size); + CHECK_LE(size, 4096); + CHECK(IsAligned(end, SHADOW_GRANULARITY)); + if (!IsAligned(ptr, SHADOW_GRANULARITY)) { + *(u8 *)MemToShadow(ptr) = + poison ? static_cast<u8>(ptr % SHADOW_GRANULARITY) : 0; + ptr |= SHADOW_GRANULARITY - 1; + ptr++; + } + for (; ptr < end; ptr += SHADOW_GRANULARITY) + *(u8*)MemToShadow(ptr) = poison ? kAsanIntraObjectRedzone : 0; +} + } // namespace __asan // ---------------------- Interface ---------------- {{{1 @@ -250,7 +271,8 @@ uptr __asan_load_cxx_array_cookie(uptr *p) { "expect a double-free report\n"); return 0; } - // FIXME: apparently it can be something else; need to find a reproducer. + // The cookie may remain unpoisoned if e.g. it comes from a custom + // operator new defined inside a class. return *p; } @@ -372,6 +394,17 @@ int __sanitizer_verify_contiguous_container(const void *beg_p, return 0; return 1; } + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +void __asan_poison_intra_object_redzone(uptr ptr, uptr size) { + AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, true); +} + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +void __asan_unpoison_intra_object_redzone(uptr ptr, uptr size) { + AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, false); +} + // --- Implementation of LSan-specific functions --- {{{1 namespace __lsan { bool WordIsPoisoned(uptr addr) { diff --git a/libsanitizer/asan/asan_posix.cc b/libsanitizer/asan/asan_posix.cc index 4eabb74ba80..06d24d4e0ee 100644 --- a/libsanitizer/asan/asan_posix.cc +++ b/libsanitizer/asan/asan_posix.cc @@ -31,6 +31,7 @@ namespace __asan { void AsanOnSIGSEGV(int, void *siginfo, void *context) { + ScopedDeadlySignal signal_scope(GetCurrentThread()); uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr; int code = (int)((siginfo_t*)siginfo)->si_code; // Write the first message using the bullet-proof write. @@ -39,12 +40,12 @@ void AsanOnSIGSEGV(int, void *siginfo, void *context) { GetPcSpBp(context, &pc, &sp, &bp); // Access at a reasonable offset above SP, or slightly below it (to account - // for x86_64 redzone, ARM push of multiple registers, etc) is probably a - // stack overflow. + // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is + // probably a stack overflow. // We also check si_code to filter out SEGV caused by something else other // then hitting the guard page or unmapped memory, like, for example, // unaligned memory access. - if (addr + 128 > sp && addr < sp + 0xFFFF && + if (addr + 512 > sp && addr < sp + 0xFFFF && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR)) ReportStackOverflow(pc, sp, bp, context, addr); else diff --git a/libsanitizer/asan/asan_report.cc b/libsanitizer/asan/asan_report.cc index 05622a12518..fcccb70ff8b 100644 --- a/libsanitizer/asan/asan_report.cc +++ b/libsanitizer/asan/asan_report.cc @@ -29,6 +29,19 @@ static char *error_message_buffer = 0; static uptr error_message_buffer_pos = 0; static uptr error_message_buffer_size = 0; +struct ReportData { + uptr pc; + uptr sp; + uptr bp; + uptr addr; + bool is_write; + uptr access_size; + const char *description; +}; + +static bool report_happened = false; +static ReportData report_data = {}; + void AppendToErrorMessageBuffer(const char *buffer) { if (error_message_buffer) { uptr length = internal_strlen(buffer); @@ -79,20 +92,31 @@ class Decorator: public __sanitizer::SanitizerCommonDecorator { return Red(); case kAsanInternalHeapMagic: return Yellow(); + case kAsanIntraObjectRedzone: + return Yellow(); default: return Default(); } } const char *EndShadowByte() { return Default(); } + const char *MemoryByte() { return Magenta(); } + const char *EndMemoryByte() { return Default(); } }; // ---------------------- Helper functions ----------------------- {{{1 -static void PrintShadowByte(InternalScopedString *str, const char *before, - u8 byte, const char *after = "\n") { +static void PrintMemoryByte(InternalScopedString *str, const char *before, + u8 byte, bool in_shadow, const char *after = "\n") { Decorator d; - str->append("%s%s%x%x%s%s", before, d.ShadowByte(byte), byte >> 4, byte & 15, - d.EndShadowByte(), after); + str->append("%s%s%x%x%s%s", before, + in_shadow ? d.ShadowByte(byte) : d.MemoryByte(), + byte >> 4, byte & 15, + in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), after); +} + +static void PrintShadowByte(InternalScopedString *str, const char *before, + u8 byte, const char *after = "\n") { + PrintMemoryByte(str, before, byte, /*in_shadow*/true, after); } static void PrintShadowBytes(InternalScopedString *str, const char *before, @@ -144,9 +168,27 @@ static void PrintLegend(InternalScopedString *str) { kAsanContiguousContainerOOBMagic); PrintShadowByte(str, " Array cookie: ", kAsanArrayCookieMagic); + PrintShadowByte(str, " Intra object redzone: ", + kAsanIntraObjectRedzone); PrintShadowByte(str, " ASan internal: ", kAsanInternalHeapMagic); } +void MaybeDumpInstructionBytes(uptr pc) { + if (!flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) + return; + InternalScopedString str(1024); + str.append("First 16 instruction bytes at pc: "); + if (IsAccessibleMemoryRange(pc, 16)) { + for (int i = 0; i < 16; ++i) { + PrintMemoryByte(&str, "", ((u8 *)pc)[i], /*in_shadow*/false, " "); + } + str.append("\n"); + } else { + str.append("unaccessible\n"); + } + Report("%s", str.data()); +} + static void PrintShadowMemoryForAddress(uptr addr) { if (!AddrIsInMem(addr)) return; uptr shadow_addr = MemToShadow(addr); @@ -235,9 +277,7 @@ static void PrintGlobalLocation(InternalScopedString *str, bool DescribeAddressRelativeToGlobal(uptr addr, uptr size, const __asan_global &g) { - static const uptr kMinimalDistanceFromAnotherGlobal = 64; - if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false; - if (addr >= g.beg + g.size_with_redzone) return false; + if (!IsAddressNearGlobal(addr, g)) return false; InternalScopedString str(4096); Decorator d; str.append("%s", d.Location()); @@ -263,21 +303,20 @@ bool DescribeAddressRelativeToGlobal(uptr addr, uptr size, return true; } -bool DescribeAddressIfShadow(uptr addr) { +bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr, bool print) { if (AddrIsInMem(addr)) return false; - static const char kAddrInShadowReport[] = - "Address %p is located in the %s.\n"; - if (AddrIsInShadowGap(addr)) { - Printf(kAddrInShadowReport, addr, "shadow gap area"); - return true; - } - if (AddrIsInHighShadow(addr)) { - Printf(kAddrInShadowReport, addr, "high shadow area"); - return true; - } - if (AddrIsInLowShadow(addr)) { - Printf(kAddrInShadowReport, addr, "low shadow area"); + const char *area_type = nullptr; + if (AddrIsInShadowGap(addr)) area_type = "shadow gap"; + else if (AddrIsInHighShadow(addr)) area_type = "high shadow"; + else if (AddrIsInLowShadow(addr)) area_type = "low shadow"; + if (area_type != nullptr) { + if (print) { + Printf("Address %p is located in the %s area.\n", addr, area_type); + } else { + CHECK(descr); + descr->region_kind = area_type; + } return true; } CHECK(0 && "Address is not in memory and not in shadow?"); @@ -304,16 +343,15 @@ const char *ThreadNameWithParenthesis(u32 tid, char buff[], return ThreadNameWithParenthesis(t, buff, buff_len); } -void PrintAccessAndVarIntersection(const char *var_name, - uptr var_beg, uptr var_size, - uptr addr, uptr access_size, - uptr prev_var_end, uptr next_var_beg) { - uptr var_end = var_beg + var_size; +static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr, + uptr access_size, uptr prev_var_end, + uptr next_var_beg) { + uptr var_end = var.beg + var.size; uptr addr_end = addr + access_size; const char *pos_descr = 0; - // If the variable [var_beg, var_end) is the nearest variable to the + // If the variable [var.beg, var_end) is the nearest variable to the // current memory access, indicate it in the log. - if (addr >= var_beg) { + if (addr >= var.beg) { if (addr_end <= var_end) pos_descr = "is inside"; // May happen if this is a use-after-return. else if (addr < var_end) @@ -322,14 +360,20 @@ void PrintAccessAndVarIntersection(const char *var_name, next_var_beg - addr_end >= addr - var_end) pos_descr = "overflows"; } else { - if (addr_end > var_beg) + if (addr_end > var.beg) pos_descr = "partially underflows"; else if (addr >= prev_var_end && - addr - prev_var_end >= var_beg - addr_end) + addr - prev_var_end >= var.beg - addr_end) pos_descr = "underflows"; } InternalScopedString str(1024); - str.append(" [%zd, %zd) '%s'", var_beg, var_beg + var_size, var_name); + str.append(" [%zd, %zd)", var.beg, var_end); + // Render variable name. + str.append(" '"); + for (uptr i = 0; i < var.name_len; ++i) { + str.append("%c", var.name_pos[i]); + } + str.append("'"); if (pos_descr) { Decorator d; // FIXME: we may want to also print the size of the access here, @@ -344,9 +388,14 @@ void PrintAccessAndVarIntersection(const char *var_name, bool ParseFrameDescription(const char *frame_descr, InternalMmapVector<StackVarDescr> *vars) { + CHECK(frame_descr); char *p; + // This string is created by the compiler and has the following form: + // "n alloc_1 alloc_2 ... alloc_n" + // where alloc_i looks like "offset size len ObjectName". uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10); - CHECK_GT(n_objects, 0); + if (n_objects == 0) + return false; for (uptr i = 0; i < n_objects; i++) { uptr beg = (uptr)internal_simple_strtoll(p, &p, 10); @@ -367,31 +416,21 @@ bool ParseFrameDescription(const char *frame_descr, bool DescribeAddressIfStack(uptr addr, uptr access_size) { AsanThread *t = FindThreadByStackAddress(addr); if (!t) return false; - const uptr kBufSize = 4095; - char buf[kBufSize]; - uptr offset = 0; - uptr frame_pc = 0; - char tname[128]; - const char *frame_descr = t->GetFrameNameByAddr(addr, &offset, &frame_pc); - -#ifdef __powerpc64__ - // On PowerPC64, the address of a function actually points to a - // three-doubleword data structure with the first field containing - // the address of the function's code. - frame_pc = *reinterpret_cast<uptr *>(frame_pc); -#endif - // This string is created by the compiler and has the following form: - // "n alloc_1 alloc_2 ... alloc_n" - // where alloc_i looks like "offset size len ObjectName ". - CHECK(frame_descr); Decorator d; + char tname[128]; Printf("%s", d.Location()); - Printf("Address %p is located in stack of thread T%d%s " - "at offset %zu in frame\n", - addr, t->tid(), - ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)), - offset); + Printf("Address %p is located in stack of thread T%d%s", addr, t->tid(), + ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname))); + + // Try to fetch precise stack frame for this access. + AsanThread::StackFrameAccess access; + if (!t->GetStackFrameAccessByAddr(addr, &access)) { + Printf("%s\n", d.EndLocation()); + return true; + } + Printf(" at offset %zu in frame%s\n", access.offset, d.EndLocation()); + // Now we print the frame where the alloca has happened. // We print this frame as a stack trace with one element. // The symbolizer may print more than one frame if inlining was involved. @@ -399,16 +438,21 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) { // previously. That's unfortunate, but I have no better solution, // especially given that the alloca may be from entirely different place // (e.g. use-after-scope, or different thread's stack). - StackTrace alloca_stack; - alloca_stack.trace[0] = frame_pc + 16; - alloca_stack.size = 1; +#if defined(__powerpc64__) && defined(__BIG_ENDIAN__) + // On PowerPC64 ELFv1, the address of a function actually points to a + // three-doubleword data structure with the first field containing + // the address of the function's code. + access.frame_pc = *reinterpret_cast<uptr *>(access.frame_pc); +#endif + access.frame_pc += 16; Printf("%s", d.EndLocation()); + StackTrace alloca_stack(&access.frame_pc, 1); alloca_stack.Print(); InternalMmapVector<StackVarDescr> vars(16); - if (!ParseFrameDescription(frame_descr, &vars)) { + if (!ParseFrameDescription(access.frame_descr, &vars)) { Printf("AddressSanitizer can't parse the stack frame " - "descriptor: |%s|\n", frame_descr); + "descriptor: |%s|\n", access.frame_descr); // 'addr' is a stack address, so return true even if we can't parse frame return true; } @@ -418,13 +462,9 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) { // Report all objects in this frame. for (uptr i = 0; i < n_objects; i++) { - buf[0] = 0; - internal_strncat(buf, vars[i].name_pos, - static_cast<uptr>(Min(kBufSize, vars[i].name_len))); uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0; uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL); - PrintAccessAndVarIntersection(buf, vars[i].beg, vars[i].size, - offset, access_size, + PrintAccessAndVarIntersection(vars[i], access.offset, access_size, prev_var_end, next_var_beg); } Printf("HINT: this may be a false positive if your program uses " @@ -476,8 +516,7 @@ void DescribeHeapAddress(uptr addr, uptr access_size) { asanThreadRegistry().CheckLocked(); AsanThreadContext *alloc_thread = GetThreadContextByTidLocked(chunk.AllocTid()); - StackTrace alloc_stack; - chunk.GetAllocStack(&alloc_stack); + StackTrace alloc_stack = chunk.GetAllocStack(); char tname[128]; Decorator d; AsanThreadContext *free_thread = 0; @@ -487,8 +526,7 @@ void DescribeHeapAddress(uptr addr, uptr access_size) { free_thread->tid, ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)), d.EndAllocation()); - StackTrace free_stack; - chunk.GetFreeStack(&free_stack); + StackTrace free_stack = chunk.GetFreeStack(); free_stack.Print(); Printf("%spreviously allocated by thread T%d%s here:%s\n", d.Allocation(), alloc_thread->tid, @@ -538,9 +576,7 @@ void DescribeThread(AsanThreadContext *context) { " created by T%d%s here:\n", context->parent_tid, ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname))); Printf("%s", str.data()); - uptr stack_size; - const uptr *stack_trace = StackDepotGet(context->stack_id, &stack_size); - StackTrace::PrintStack(stack_trace, stack_size); + StackDepotGet(context->stack_id).Print(); // Recursively described parent thread if needed. if (flags()->print_full_thread_history) { AsanThreadContext *parent_context = @@ -555,7 +591,7 @@ void DescribeThread(AsanThreadContext *context) { // immediately after printing error report. class ScopedInErrorReport { public: - ScopedInErrorReport() { + explicit ScopedInErrorReport(ReportData *report = nullptr) { static atomic_uint32_t num_calls; static u32 reporting_thread_tid; if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) { @@ -575,6 +611,8 @@ class ScopedInErrorReport { // Die() to bypass any additional checks. internal__exit(flags()->exitcode); } + if (report) report_data = *report; + report_happened = true; ASAN_ON_ERROR(); // Make sure the registry and sanitizer report mutexes are locked while // we're printing an error report. @@ -634,11 +672,12 @@ void ReportSIGSEGV(const char *description, uptr pc, uptr sp, uptr bp, Printf("%s", d.EndWarning()); GET_STACK_TRACE_SIGNAL(pc, bp, context); stack.Print(); + MaybeDumpInstructionBytes(pc); Printf("AddressSanitizer can not provide additional info.\n"); ReportErrorSummary("SEGV", &stack); } -void ReportDoubleFree(uptr addr, StackTrace *free_stack) { +void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) { ScopedInErrorReport in_report; Decorator d; Printf("%s", d.Warning()); @@ -657,7 +696,7 @@ void ReportDoubleFree(uptr addr, StackTrace *free_stack) { } void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, - StackTrace *free_stack) { + BufferedStackTrace *free_stack) { ScopedInErrorReport in_report; Decorator d; Printf("%s", d.Warning()); @@ -680,7 +719,7 @@ void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, "ASAN_OPTIONS=new_delete_type_mismatch=0\n"); } -void ReportFreeNotMalloced(uptr addr, StackTrace *free_stack) { +void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) { ScopedInErrorReport in_report; Decorator d; Printf("%s", d.Warning()); @@ -697,7 +736,7 @@ void ReportFreeNotMalloced(uptr addr, StackTrace *free_stack) { ReportErrorSummary("bad-free", &stack); } -void ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack, +void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack, AllocType alloc_type, AllocType dealloc_type) { static const char *alloc_names[] = @@ -720,7 +759,7 @@ void ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack, "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n"); } -void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) { +void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) { ScopedInErrorReport in_report; Decorator d; Printf("%s", d.Warning()); @@ -733,7 +772,8 @@ void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) { ReportErrorSummary("bad-malloc_usable_size", stack); } -void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) { +void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, + BufferedStackTrace *stack) { ScopedInErrorReport in_report; Decorator d; Printf("%s", d.Warning()); @@ -746,9 +786,10 @@ void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) { ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack); } -void ReportStringFunctionMemoryRangesOverlap( - const char *function, const char *offset1, uptr length1, - const char *offset2, uptr length2, StackTrace *stack) { +void ReportStringFunctionMemoryRangesOverlap(const char *function, + const char *offset1, uptr length1, + const char *offset2, uptr length2, + BufferedStackTrace *stack) { ScopedInErrorReport in_report; Decorator d; char bug_type[100]; @@ -765,7 +806,7 @@ void ReportStringFunctionMemoryRangesOverlap( } void ReportStringFunctionSizeOverflow(uptr offset, uptr size, - StackTrace *stack) { + BufferedStackTrace *stack) { ScopedInErrorReport in_report; Decorator d; const char *bug_type = "negative-size-param"; @@ -779,7 +820,7 @@ void ReportStringFunctionSizeOverflow(uptr offset, uptr size, void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end, uptr old_mid, uptr new_mid, - StackTrace *stack) { + BufferedStackTrace *stack) { ScopedInErrorReport in_report; Report("ERROR: AddressSanitizer: bad parameters to " "__sanitizer_annotate_contiguous_container:\n" @@ -809,12 +850,9 @@ void ReportODRViolation(const __asan_global *g1, u32 stack_id1, if (stack_id1 && stack_id2) { Printf("These globals were registered at these points:\n"); Printf(" [1]:\n"); - uptr stack_size; - const uptr *stack_trace = StackDepotGet(stack_id1, &stack_size); - StackTrace::PrintStack(stack_trace, stack_size); + StackDepotGet(stack_id1).Print(); Printf(" [2]:\n"); - stack_trace = StackDepotGet(stack_id2, &stack_size); - StackTrace::PrintStack(stack_trace, stack_size); + StackDepotGet(stack_id2).Print(); } Report("HINT: if you don't care about these warnings you may set " "ASAN_OPTIONS=detect_odr_violation=0\n"); @@ -854,8 +892,8 @@ static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) { } // ----------------------- Mac-specific reports ----------------- {{{1 -void WarnMacFreeUnallocated( - uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) { +void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name, + BufferedStackTrace *stack) { // Just print a warning here. Printf("free_common(%p) -- attempting to free unallocated memory.\n" "AddressSanitizer is ignoring this error on Mac OS now.\n", @@ -865,8 +903,8 @@ void WarnMacFreeUnallocated( DescribeHeapAddress(addr, 1); } -void ReportMacMzReallocUnknown( - uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) { +void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name, + BufferedStackTrace *stack) { ScopedInErrorReport in_report; Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n" "This is an unrecoverable problem, exiting now.\n", @@ -876,8 +914,8 @@ void ReportMacMzReallocUnknown( DescribeHeapAddress(addr, 1); } -void ReportMacCfReallocUnknown( - uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) { +void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name, + BufferedStackTrace *stack) { ScopedInErrorReport in_report; Printf("cf_realloc(%p) -- attempting to realloc unallocated memory.\n" "This is an unrecoverable problem, exiting now.\n", @@ -894,8 +932,6 @@ using namespace __asan; // NOLINT void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, uptr access_size) { - ScopedInErrorReport in_report; - // Determine the error type. const char *bug_descr = "unknown-crash"; if (AddrIsInMem(addr)) { @@ -941,8 +977,16 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, case kAsanGlobalRedzoneMagic: bug_descr = "global-buffer-overflow"; break; + case kAsanIntraObjectRedzone: + bug_descr = "intra-object-overflow"; + break; } } + + ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size, + bug_descr }; + ScopedInErrorReport in_report(&report); + Decorator d; Printf("%s", d.Warning()); Report("ERROR: AddressSanitizer: %s on address " @@ -984,6 +1028,38 @@ void __asan_describe_address(uptr addr) { asanThreadRegistry().Unlock(); } +int __asan_report_present() { + return report_happened ? 1 : 0; +} + +uptr __asan_get_report_pc() { + return report_data.pc; +} + +uptr __asan_get_report_bp() { + return report_data.bp; +} + +uptr __asan_get_report_sp() { + return report_data.sp; +} + +uptr __asan_get_report_address() { + return report_data.addr; +} + +int __asan_get_report_access_type() { + return report_data.is_write ? 1 : 0; +} + +uptr __asan_get_report_access_size() { + return report_data.access_size; +} + +const char *__asan_get_report_description() { + return report_data.description; +} + extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_ptr_sub(void *a, void *b) { diff --git a/libsanitizer/asan/asan_report.h b/libsanitizer/asan/asan_report.h index 4e81b9ca3a8..b31b86dd08b 100644 --- a/libsanitizer/asan/asan_report.h +++ b/libsanitizer/asan/asan_report.h @@ -23,13 +23,24 @@ struct StackVarDescr { uptr name_len; }; +struct AddressDescription { + char *name; + uptr name_size; + uptr region_address; + uptr region_size; + const char *region_kind; +}; + // The following functions prints address description depending // on the memory type (shadow/heap/stack/global). void DescribeHeapAddress(uptr addr, uptr access_size); bool DescribeAddressIfGlobal(uptr addr, uptr access_size); bool DescribeAddressRelativeToGlobal(uptr addr, uptr access_size, const __asan_global &g); -bool DescribeAddressIfShadow(uptr addr); +bool IsAddressNearGlobal(uptr addr, const __asan_global &g); +bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr); +bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr = nullptr, + bool print = true); bool ParseFrameDescription(const char *frame_descr, InternalMmapVector<StackVarDescr> *vars); bool DescribeAddressIfStack(uptr addr, uptr access_size); @@ -44,35 +55,41 @@ void NORETURN void NORETURN ReportSIGSEGV(const char *description, uptr pc, uptr sp, uptr bp, void *context, uptr addr); void NORETURN ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, - StackTrace *free_stack); -void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack); -void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *free_stack); -void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack, + BufferedStackTrace *free_stack); +void NORETURN ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack); +void NORETURN ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack); +void NORETURN ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack, AllocType alloc_type, AllocType dealloc_type); -void NORETURN ReportMallocUsableSizeNotOwned(uptr addr, - StackTrace *stack); void NORETURN -ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack); -void NORETURN ReportStringFunctionMemoryRangesOverlap( - const char *function, const char *offset1, uptr length1, - const char *offset2, uptr length2, StackTrace *stack); + ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack); +void NORETURN + ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, + BufferedStackTrace *stack); void NORETURN -ReportStringFunctionSizeOverflow(uptr offset, uptr size, StackTrace *stack); + ReportStringFunctionMemoryRangesOverlap(const char *function, + const char *offset1, uptr length1, + const char *offset2, uptr length2, + BufferedStackTrace *stack); +void NORETURN ReportStringFunctionSizeOverflow(uptr offset, uptr size, + BufferedStackTrace *stack); void NORETURN -ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end, uptr old_mid, - uptr new_mid, StackTrace *stack); + ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end, + uptr old_mid, uptr new_mid, + BufferedStackTrace *stack); void NORETURN ReportODRViolation(const __asan_global *g1, u32 stack_id1, const __asan_global *g2, u32 stack_id2); // Mac-specific errors and warnings. -void WarnMacFreeUnallocated( - uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack); -void NORETURN ReportMacMzReallocUnknown( - uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack); -void NORETURN ReportMacCfReallocUnknown( - uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack); +void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name, + BufferedStackTrace *stack); +void NORETURN ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, + const char *zone_name, + BufferedStackTrace *stack); +void NORETURN ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr, + const char *zone_name, + BufferedStackTrace *stack); } // namespace __asan diff --git a/libsanitizer/asan/asan_rtl.cc b/libsanitizer/asan/asan_rtl.cc index 8fccc8da967..2c599047dac 100644 --- a/libsanitizer/asan/asan_rtl.cc +++ b/libsanitizer/asan/asan_rtl.cc @@ -65,7 +65,7 @@ static void AsanCheckFailed(const char *file, int line, const char *cond, Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file, line, cond, (uptr)v1, (uptr)v2); // FIXME: check for infinite recursion without a thread-local counter here. - PRINT_CURRENT_STACK(); + PRINT_CURRENT_STACK_CHECK(); Die(); } @@ -228,6 +228,9 @@ static void ParseFlagsFromString(Flags *f, const char *str) { "If >=2, detect violation of One-Definition-Rule (ODR); " "If ==1, detect ODR-violation only if the two variables " "have different sizes"); + + ParseFlag(str, &f->dump_instruction_bytes, "dump_instruction_bytes", + "If true, dump 16 bytes starting at the instruction that caused SEGV"); } void InitializeFlags(Flags *f, const char *env) { @@ -281,6 +284,7 @@ void InitializeFlags(Flags *f, const char *env) { f->detect_invalid_pointer_pairs = 0; f->detect_container_overflow = true; f->detect_odr_violation = 2; + f->dump_instruction_bytes = false; // Override from compile definition. ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefinition()); diff --git a/libsanitizer/asan/asan_stack.h b/libsanitizer/asan/asan_stack.h index d31c0afa83b..640c4cf4f7b 100644 --- a/libsanitizer/asan/asan_stack.h +++ b/libsanitizer/asan/asan_stack.h @@ -23,8 +23,9 @@ namespace __asan { // The pc will be in the position 0 of the resulting stack trace. // The bp may refer to the current frame or to the caller's frame. ALWAYS_INLINE -void GetStackTraceWithPcBpAndContext(StackTrace *stack, uptr max_depth, uptr pc, - uptr bp, void *context, bool fast) { +void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth, + uptr pc, uptr bp, void *context, + bool fast) { #if SANITIZER_WINDOWS stack->Unwind(max_depth, pc, bp, context, 0, 0, fast); #else @@ -32,6 +33,10 @@ void GetStackTraceWithPcBpAndContext(StackTrace *stack, uptr max_depth, uptr pc, stack->size = 0; if (LIKELY(asan_inited)) { if ((t = GetCurrentThread()) && !t->isUnwinding()) { + // On FreeBSD the slow unwinding that leverages _Unwind_Backtrace() + // yields the call stack of the signal's handler and not of the code + // that raised the signal (as it does on Linux). + if (SANITIZER_FREEBSD && t->isInDeadlySignal()) fast = true; uptr stack_top = t->stack_top(); uptr stack_bottom = t->stack_bottom(); ScopedUnwinding unwind_scope(t); @@ -51,14 +56,14 @@ void GetStackTraceWithPcBpAndContext(StackTrace *stack, uptr max_depth, uptr pc, // don't want stack trace to contain functions from ASan internals. #define GET_STACK_TRACE(max_size, fast) \ - StackTrace stack; \ + BufferedStackTrace stack; \ if (max_size <= 2) { \ stack.size = max_size; \ if (max_size > 0) { \ stack.top_frame_bp = GET_CURRENT_FRAME(); \ - stack.trace[0] = StackTrace::GetCurrentPc(); \ + stack.trace_buffer[0] = StackTrace::GetCurrentPc(); \ if (max_size > 1) \ - stack.trace[1] = GET_CALLER_PC(); \ + stack.trace_buffer[1] = GET_CALLER_PC(); \ } \ } else { \ GetStackTraceWithPcBpAndContext(&stack, max_size, \ @@ -67,18 +72,21 @@ void GetStackTraceWithPcBpAndContext(StackTrace *stack, uptr max_depth, uptr pc, } #define GET_STACK_TRACE_FATAL(pc, bp) \ - StackTrace stack; \ + BufferedStackTrace stack; \ GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, 0, \ common_flags()->fast_unwind_on_fatal) #define GET_STACK_TRACE_SIGNAL(pc, bp, context) \ - StackTrace stack; \ + BufferedStackTrace stack; \ GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context, \ common_flags()->fast_unwind_on_fatal) #define GET_STACK_TRACE_FATAL_HERE \ GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal) +#define GET_STACK_TRACE_CHECK_HERE \ + GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check) + #define GET_STACK_TRACE_THREAD \ GET_STACK_TRACE(kStackTraceMax, true) @@ -94,4 +102,10 @@ void GetStackTraceWithPcBpAndContext(StackTrace *stack, uptr max_depth, uptr pc, stack.Print(); \ } +#define PRINT_CURRENT_STACK_CHECK() \ + { \ + GET_STACK_TRACE_CHECK_HERE; \ + stack.Print(); \ + } + #endif // ASAN_STACK_H diff --git a/libsanitizer/asan/asan_thread.cc b/libsanitizer/asan/asan_thread.cc index 87074065633..95ca6720090 100644 --- a/libsanitizer/asan/asan_thread.cc +++ b/libsanitizer/asan/asan_thread.cc @@ -28,7 +28,7 @@ namespace __asan { void AsanThreadContext::OnCreated(void *arg) { CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg); if (args->stack) - stack_id = StackDepotPut(args->stack->trace, args->stack->size); + stack_id = StackDepotPut(*args->stack); thread = args->thread; thread->set_context(this); } @@ -196,17 +196,18 @@ void AsanThread::ClearShadowForThreadStackAndTLS() { PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0); } -const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset, - uptr *frame_pc) { +bool AsanThread::GetStackFrameAccessByAddr(uptr addr, + StackFrameAccess *access) { uptr bottom = 0; if (AddrIsInStack(addr)) { bottom = stack_bottom(); } else if (has_fake_stack()) { bottom = fake_stack()->AddrIsInFakeStack(addr); CHECK(bottom); - *offset = addr - bottom; - *frame_pc = ((uptr*)bottom)[2]; - return (const char *)((uptr*)bottom)[1]; + access->offset = addr - bottom; + access->frame_pc = ((uptr*)bottom)[2]; + access->frame_descr = (const char *)((uptr*)bottom)[1]; + return true; } uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr. u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr); @@ -223,15 +224,15 @@ const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset, } if (shadow_ptr < shadow_bottom) { - *offset = 0; - return "UNKNOWN"; + return false; } uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1)); CHECK(ptr[0] == kCurrentStackFrameMagic); - *offset = addr - (uptr)ptr; - *frame_pc = ptr[2]; - return (const char*)ptr[1]; + access->offset = addr - (uptr)ptr; + access->frame_pc = ptr[2]; + access->frame_descr = (const char*)ptr[1]; + return true; } static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base, diff --git a/libsanitizer/asan/asan_thread.h b/libsanitizer/asan/asan_thread.h index 33242efabaa..f5ea53d051f 100644 --- a/libsanitizer/asan/asan_thread.h +++ b/libsanitizer/asan/asan_thread.h @@ -69,7 +69,12 @@ class AsanThread { AsanThreadContext *context() { return context_; } void set_context(AsanThreadContext *context) { context_ = context; } - const char *GetFrameNameByAddr(uptr addr, uptr *offset, uptr *frame_pc); + struct StackFrameAccess { + uptr offset; + uptr frame_pc; + const char *frame_descr; + }; + bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access); bool AddrIsInStack(uptr addr) { return addr >= stack_bottom_ && addr < stack_top_; @@ -101,6 +106,10 @@ class AsanThread { bool isUnwinding() const { return unwinding_; } void setUnwinding(bool b) { unwinding_ = b; } + // True if we are in a deadly signal handler. + bool isInDeadlySignal() const { return in_deadly_signal_; } + void setInDeadlySignal(bool b) { in_deadly_signal_ = b; } + AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; } AsanStats &stats() { return stats_; } @@ -126,6 +135,7 @@ class AsanThread { AsanThreadLocalMallocStorage malloc_storage_; AsanStats stats_; bool unwinding_; + bool in_deadly_signal_; }; // ScopedUnwinding is a scope for stacktracing member of a context @@ -140,6 +150,20 @@ class ScopedUnwinding { AsanThread *thread; }; +// ScopedDeadlySignal is a scope for handling deadly signals. +class ScopedDeadlySignal { + public: + explicit ScopedDeadlySignal(AsanThread *t) : thread(t) { + if (thread) thread->setInDeadlySignal(true); + } + ~ScopedDeadlySignal() { + if (thread) thread->setInDeadlySignal(false); + } + + private: + AsanThread *thread; +}; + struct CreateThreadContextArgs { AsanThread *thread; StackTrace *stack; |