Index: lib/asan/asan_allocator.cc =================================================================== --- lib/asan/asan_allocator.cc +++ lib/asan/asan_allocator.cc @@ -530,7 +530,7 @@ if (delete_size && flags()->new_delete_type_mismatch && delete_size != m->UsedSize()) { - ReportNewDeleteSizeMismatch(p, m->UsedSize(), delete_size, stack); + ReportNewDeleteSizeMismatch(p, delete_size, stack); } QuarantineChunk(m, ptr, stack, alloc_type); Index: lib/asan/asan_errors.h =================================================================== --- lib/asan/asan_errors.h +++ lib/asan/asan_errors.h @@ -16,9 +16,20 @@ #include "asan_descriptions.h" #include "asan_scariness_score.h" +#include "sanitizer_common/sanitizer_common.h" namespace __asan { +static inline 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, + in_shadow ? d.ShadowByte(byte) : d.MemoryByte(), byte >> 4, + byte & 15, in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), + after); +} + struct ErrorBase { ScarinessScoreBase scariness; }; @@ -44,6 +55,46 @@ void Print(); }; +struct ErrorDeadlySignal : ErrorBase { + u32 tid; + uptr addr, pc, bp, sp; + int signo; + SignalContext::WriteFlag write_flag; + bool is_memory_access; + // ErrorDeadlySignal never owns the context. + void *context; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorDeadlySignal() = default; + ErrorDeadlySignal(int signo_, const SignalContext &sig, u32 tid_) + : tid(tid_), + addr(sig.addr), + pc(sig.pc), + bp(sig.bp), + sp(sig.sp), + signo(signo_), + write_flag(sig.write_flag), + is_memory_access(sig.is_memory_access), + context(sig.context) { + if (is_memory_access) { + if (addr < GetPageSizeCached()) { + scariness.Scare(10, "null-deref"); + } else if (addr == pc) { + scariness.Scare(60, "wild-jump"); + } else if (write_flag == SignalContext::WRITE) { + scariness.Scare(30, "wild-addr-write"); + } else if (write_flag == SignalContext::READ) { + scariness.Scare(20, "wild-addr-read"); + } else { + scariness.Scare(25, "wild-addr"); + } + } else { + scariness.Scare(10, "signal"); + } + } + void Print(); +}; + struct ErrorDoubleFree : ErrorBase { u32 tid; HeapAddressDescription addr_description; @@ -61,10 +112,27 @@ void Print(); }; +struct ErrorNewDeleteSizeMismatch : ErrorBase { + u32 tid; + HeapAddressDescription addr_description; + uptr delete_size; + // ErrorNewDeleteSizeMismatch doesn't own the stack trace. + BufferedStackTrace *free_stack; + ErrorNewDeleteSizeMismatch(uptr addr, u32 tid_, uptr delete_size_, + BufferedStackTrace *stack) + : tid(tid_), delete_size(delete_size_), free_stack(stack) { + GetHeapAddressInformation(addr, 1, &addr_description); + scariness.Scare(10, "new-delete-type-mismatch"); + } + void Print(); +}; + enum ErrorKind { kErrorKindInvalid = 0, kErrorKindStackOverflow, + kErrorKindDeadlySignal, kErrorKindDoubleFree, + kErrorKindNewDeleteSizeMismatch, }; struct ErrorDescription { @@ -76,15 +144,23 @@ // add a lot of code and the benefit wouldn't be that big. union { ErrorStackOverflow stack_overflow; + ErrorDeadlySignal deadly_signal; ErrorDoubleFree double_free; + ErrorNewDeleteSizeMismatch new_delete_size_mismatch; }; ErrorDescription() { internal_memset(this, 0, sizeof(*this)); } ErrorDescription(const ErrorStackOverflow &e) // NOLINT : kind(kErrorKindStackOverflow), stack_overflow(e) {} + ErrorDescription(const ErrorDeadlySignal &e) // NOLINT + : kind(kErrorKindDeadlySignal), + deadly_signal(e) {} ErrorDescription(const ErrorDoubleFree &e) // NOLINT : kind(kErrorKindDoubleFree), double_free(e) {} + ErrorDescription(const ErrorNewDeleteSizeMismatch &e) // NOLINT + : kind(kErrorKindNewDeleteSizeMismatch), + new_delete_size_mismatch(e) {} bool IsValid() { return kind != kErrorKindInvalid; } void Print() { @@ -92,9 +168,15 @@ case kErrorKindStackOverflow: stack_overflow.Print(); return; + case kErrorKindDeadlySignal: + deadly_signal.Print(); + return; case kErrorKindDoubleFree: double_free.Print(); return; + case kErrorKindNewDeleteSizeMismatch: + new_delete_size_mismatch.Print(); + return; case kErrorKindInvalid: CHECK(0); } Index: lib/asan/asan_errors.cc =================================================================== --- lib/asan/asan_errors.cc +++ lib/asan/asan_errors.cc @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "asan_errors.h" +#include #include "asan_descriptions.h" #include "asan_stack.h" @@ -34,6 +35,50 @@ ReportErrorSummary("stack-overflow", &stack); } +static 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()); +} + +void ErrorDeadlySignal::Print() { + Decorator d; + Printf("%s", d.Warning()); + const char *description = DescribeSignalOrException(signo); + Report( + "ERROR: AddressSanitizer: %s on unknown address %p (pc %p bp %p sp %p " + "T%d)\n", + description, (void *)addr, (void *)pc, (void *)bp, (void *)sp, tid); + Printf("%s", d.EndWarning()); + if (pc < GetPageSizeCached()) Report("Hint: pc points to the zero page.\n"); + if (is_memory_access) { + const char *access_type = + write_flag == SignalContext::WRITE + ? "WRITE" + : (write_flag == SignalContext::READ ? "READ" : "UNKNOWN"); + Report("The signal is caused by a %s memory access.\n", access_type); + if (addr < GetPageSizeCached()) + Report("Hint: address points to the zero page.\n"); + } + scariness.Print(); + BufferedStackTrace stack; + GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context, + common_flags()->fast_unwind_on_fatal); + stack.Print(); + MaybeDumpInstructionBytes(pc); + Printf("AddressSanitizer can not provide additional info.\n"); + ReportErrorSummary(description, &stack); +} + void ErrorDoubleFree::Print() { Decorator d; Printf("%s", d.Warning()); @@ -51,4 +96,29 @@ ReportErrorSummary("double-free", &stack); } +void ErrorNewDeleteSizeMismatch::Print() { + Decorator d; + Printf("%s", d.Warning()); + char tname[128]; + Report( + "ERROR: AddressSanitizer: new-delete-type-mismatch on %p in thread " + "T%d%s:\n", + addr_description.addr, tid, + ThreadNameWithParenthesis(tid, tname, sizeof(tname))); + Printf("%s object passed to delete has wrong type:\n", d.EndWarning()); + Printf( + " size of the allocated type: %zd bytes;\n" + " size of the deallocated type: %zd bytes.\n", + addr_description.chunk_access.chunk_size, delete_size); + CHECK_GT(free_stack->size, 0); + scariness.Print(); + GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); + stack.Print(); + addr_description.Print(); + 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"); +} + } // namespace __asan Index: lib/asan/asan_internal.h =================================================================== --- lib/asan/asan_internal.h +++ lib/asan/asan_internal.h @@ -65,6 +65,9 @@ // asan_win.cc void InitializePlatformExceptionHandlers(); +// asan_win.cc / asan_posix.cc +const char *DescribeSignalOrException(int signo); + // asan_rtl.cc void NORETURN ShowStatsAndAbort(); Index: lib/asan/asan_posix.cc =================================================================== --- lib/asan/asan_posix.cc +++ lib/asan/asan_posix.cc @@ -33,6 +33,17 @@ namespace __asan { +const char *DescribeSignalOrException(int signo) { + switch (signo) { + case SIGFPE: + return "FPE"; + case SIGILL: + return "ILL"; + default: + return "SEGV"; + } +} + void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { ScopedDeadlySignal signal_scope(GetCurrentThread()); int code = (int)((siginfo_t*)siginfo)->si_code; @@ -84,12 +95,8 @@ // unaligned memory access. if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR)) ReportStackOverflow(sig); - else if (signo == SIGFPE) - ReportDeadlySignal("FPE", sig); - else if (signo == SIGILL) - ReportDeadlySignal("ILL", sig); else - ReportDeadlySignal("SEGV", sig); + ReportDeadlySignal(signo, sig); } // ---------------------- TSD ---------------- {{{1 Index: lib/asan/asan_report.h =================================================================== --- lib/asan/asan_report.h +++ lib/asan/asan_report.h @@ -51,8 +51,8 @@ void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, uptr access_size, u32 exp, bool fatal); void ReportStackOverflow(const SignalContext &sig); -void ReportDeadlySignal(const char *description, const SignalContext &sig); -void ReportNewDeleteSizeMismatch(uptr addr, uptr alloc_size, uptr delete_size, +void ReportDeadlySignal(int signo, const SignalContext &sig); +void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, BufferedStackTrace *free_stack); void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack); void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack); Index: lib/asan/asan_report.cc =================================================================== --- lib/asan/asan_report.cc +++ lib/asan/asan_report.cc @@ -69,15 +69,6 @@ // ---------------------- Helper functions ----------------------- {{{1 -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, - 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); @@ -135,22 +126,6 @@ PrintShadowByte(str, " Right alloca redzone: ", kAsanAllocaRightMagic); } -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); @@ -344,46 +319,10 @@ in_report.ReportError(error); } -void ReportDeadlySignal(const char *description, const SignalContext &sig) { +void ReportDeadlySignal(int signo, const SignalContext &sig) { ScopedInErrorReport in_report(/*report*/ nullptr, /*fatal*/ true); - Decorator d; - Printf("%s", d.Warning()); - Report( - "ERROR: AddressSanitizer: %s on unknown address %p" - " (pc %p bp %p sp %p T%d)\n", - description, (void *)sig.addr, (void *)sig.pc, (void *)sig.bp, - (void *)sig.sp, GetCurrentTidOrInvalid()); - Printf("%s", d.EndWarning()); - ScarinessScore SS; - if (sig.pc < GetPageSizeCached()) - Report("Hint: pc points to the zero page.\n"); - if (sig.is_memory_access) { - const char *access_type = - sig.write_flag == SignalContext::WRITE - ? "WRITE" - : (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN"); - Report("The signal is caused by a %s memory access.\n", access_type); - if (sig.addr < GetPageSizeCached()) { - Report("Hint: address points to the zero page.\n"); - SS.Scare(10, "null-deref"); - } else if (sig.addr == sig.pc) { - SS.Scare(60, "wild-jump"); - } else if (sig.write_flag == SignalContext::WRITE) { - SS.Scare(30, "wild-addr-write"); - } else if (sig.write_flag == SignalContext::READ) { - SS.Scare(20, "wild-addr-read"); - } else { - SS.Scare(25, "wild-addr"); - } - } else { - SS.Scare(10, "signal"); - } - SS.Print(); - GET_STACK_TRACE_SIGNAL(sig); - stack.Print(); - MaybeDumpInstructionBytes(sig.pc); - Printf("AddressSanitizer can not provide additional info.\n"); - ReportErrorSummary(description, &stack); + ErrorDeadlySignal error{signo, sig, GetCurrentTidOrInvalid()}; // NOLINT + in_report.ReportError(error); } void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) { @@ -392,29 +331,11 @@ in_report.ReportError(error); } -void ReportNewDeleteSizeMismatch(uptr addr, uptr alloc_size, uptr delete_size, +void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, BufferedStackTrace *free_stack) { ScopedInErrorReport in_report; - Decorator d; - Printf("%s", d.Warning()); - char tname[128]; - u32 curr_tid = GetCurrentTidOrInvalid(); - Report("ERROR: AddressSanitizer: new-delete-type-mismatch on %p in " - "thread T%d%s:\n", - addr, curr_tid, - ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname))); - Printf("%s object passed to delete has wrong type:\n", d.EndWarning()); - Printf(" size of the allocated type: %zd bytes;\n" - " size of the deallocated type: %zd bytes.\n", - alloc_size, delete_size); - CHECK_GT(free_stack->size, 0); - ScarinessScore::PrintSimple(10, "new-delete-type-mismatch"); - GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); - stack.Print(); - 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"); + ErrorNewDeleteSizeMismatch error{addr, GetCurrentTidOrInvalid(), delete_size, free_stack}; + in_report.ReportError(error); } void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) { Index: lib/asan/asan_win.cc =================================================================== --- lib/asan/asan_win.cc +++ lib/asan/asan_win.cc @@ -270,7 +270,10 @@ } // Return the textual name for this exception. -static const char *DescribeDeadlyException(unsigned code) { +const char *DescribeSignalOrException(int signo) { + unsigned code = signo; + // Get the string description of the exception if this is a known deadly + // exception. switch (code) { case EXCEPTION_ACCESS_VIOLATION: return "access-violation"; @@ -289,12 +292,8 @@ CONTEXT *context = info->ContextRecord; if (ShouldReportDeadlyException(exception_record->ExceptionCode)) { - // Get the string description of the exception if this is a known deadly - // exception. - const char *description = - DescribeDeadlyException(exception_record->ExceptionCode); SignalContext sig = SignalContext::Create(exception_record, context); - ReportDeadlySignal(description, sig); + ReportDeadlySignal(exception_record->ExceptionCode, sig); } // FIXME: Handle EXCEPTION_STACK_OVERFLOW here.