Index: lib/asan/asan_errors.h =================================================================== --- lib/asan/asan_errors.h +++ lib/asan/asan_errors.h @@ -22,9 +22,11 @@ struct ErrorBase { ErrorBase() = default; - explicit ErrorBase(u32 tid_) : tid(tid_) {} + explicit ErrorBase(u32 tid_, const char *bug_descr_) + : tid(tid_), bug_descr(bug_descr_) {} ScarinessScoreBase scariness; u32 tid; + const char *bug_descr; }; struct ErrorStackOverflow : ErrorBase { @@ -35,14 +37,14 @@ // constructor ErrorStackOverflow() = default; ErrorStackOverflow(u32 tid, const SignalContext &sig) - : ErrorBase(tid), + : ErrorBase(tid, "stack-overflow"), addr(sig.addr), pc(sig.pc), bp(sig.bp), sp(sig.sp), context(sig.context) { scariness.Clear(); - scariness.Scare(10, "stack-overflow"); + scariness.Scare(10, bug_descr); } void Print(); }; @@ -58,7 +60,7 @@ // constructor ErrorDeadlySignal() = default; ErrorDeadlySignal(u32 tid, const SignalContext &sig, int signo_) - : ErrorBase(tid), + : ErrorBase(tid, nullptr), addr(sig.addr), pc(sig.pc), bp(sig.bp), @@ -70,18 +72,24 @@ scariness.Clear(); if (is_memory_access) { if (addr < GetPageSizeCached()) { - scariness.Scare(10, "null-deref"); + bug_descr = "null-deref"; + scariness.Scare(10, bug_descr); } else if (addr == pc) { - scariness.Scare(60, "wild-jump"); + bug_descr = "wild-jump"; + scariness.Scare(60, bug_descr); } else if (write_flag == SignalContext::WRITE) { - scariness.Scare(30, "wild-addr-write"); + bug_descr = "wild-addr-write"; + scariness.Scare(30, bug_descr); } else if (write_flag == SignalContext::READ) { - scariness.Scare(20, "wild-addr-read"); + bug_descr = "wild-addr-read"; + scariness.Scare(20, bug_descr); } else { - scariness.Scare(25, "wild-addr"); + bug_descr = "wild-addr"; + scariness.Scare(25, bug_descr); } } else { - scariness.Scare(10, "signal"); + bug_descr = "signal"; + scariness.Scare(10, bug_descr); } } void Print(); @@ -95,11 +103,11 @@ // constructor ErrorDoubleFree() = default; ErrorDoubleFree(u32 tid, BufferedStackTrace *stack, uptr addr) - : ErrorBase(tid), second_free_stack(stack) { + : ErrorBase(tid, "double-free"), second_free_stack(stack) { CHECK_GT(second_free_stack->size, 0); GetHeapAddressInformation(addr, 1, &addr_description); scariness.Clear(); - scariness.Scare(42, "double-free"); + scariness.Scare(42, bug_descr); } void Print(); }; @@ -114,10 +122,12 @@ ErrorNewDeleteSizeMismatch() = default; ErrorNewDeleteSizeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr, uptr delete_size_) - : ErrorBase(tid), free_stack(stack), delete_size(delete_size_) { + : ErrorBase(tid, "new-delete-type-mismatch"), + free_stack(stack), + delete_size(delete_size_) { GetHeapAddressInformation(addr, 1, &addr_description); scariness.Clear(); - scariness.Scare(10, "new-delete-type-mismatch"); + scariness.Scare(10, bug_descr); } void Print(); }; @@ -130,11 +140,11 @@ // constructor ErrorFreeNotMalloced() = default; ErrorFreeNotMalloced(u32 tid, BufferedStackTrace *stack, uptr addr) - : ErrorBase(tid), + : ErrorBase(tid, "bad-free"), free_stack(stack), addr_description(addr, /*shouldLockThreadRegistry=*/false) { scariness.Clear(); - scariness.Scare(40, "bad-free"); + scariness.Scare(40, bug_descr); } void Print(); }; @@ -149,13 +159,13 @@ ErrorAllocTypeMismatch() = default; ErrorAllocTypeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr, AllocType alloc_type_, AllocType dealloc_type_) - : ErrorBase(tid), + : ErrorBase(tid, "alloc-dealloc-mismatch"), dealloc_stack(stack), alloc_type(alloc_type_), dealloc_type(dealloc_type_) { GetHeapAddressInformation(addr, 1, &addr_description); scariness.Clear(); - scariness.Scare(10, "alloc-dealloc-mismatch"); + scariness.Scare(10, bug_descr); }; void Print(); }; @@ -168,7 +178,7 @@ // constructor ErrorMallocUsableSizeNotOwned() = default; ErrorMallocUsableSizeNotOwned(u32 tid, BufferedStackTrace *stack_, uptr addr) - : ErrorBase(tid), + : ErrorBase(tid, "bad-malloc_usable_size"), stack(stack_), addr_description(addr, /*shouldLockThreadRegistry=*/false) { scariness.Clear(); @@ -185,7 +195,7 @@ ErrorSanitizerGetAllocatedSizeNotOwned() = default; ErrorSanitizerGetAllocatedSizeNotOwned(u32 tid, BufferedStackTrace *stack_, uptr addr) - : ErrorBase(tid), + : ErrorBase(tid, "bad-__sanitizer_get_allocated_size"), stack(stack_), addr_description(addr, /*shouldLockThreadRegistry=*/false) { scariness.Clear(); @@ -206,7 +216,7 @@ ErrorStringFunctionMemoryRangesOverlap(u32 tid, BufferedStackTrace *stack_, uptr addr1, uptr length1_, uptr addr2, uptr length2_, const char *function_) - : ErrorBase(tid), + : ErrorBase(tid, "param-overlap"), stack(stack_), length1(length1_), length2(length2_), @@ -231,12 +241,12 @@ ErrorStringFunctionSizeOverflow() = default; ErrorStringFunctionSizeOverflow(u32 tid, BufferedStackTrace *stack_, uptr addr, uptr size_) - : ErrorBase(tid), + : ErrorBase(tid, "negative-size-param"), stack(stack_), addr_description(addr, /*shouldLockThreadRegistry=*/false), size(size_) { scariness.Clear(); - scariness.Scare(10, "negative-size-param"); + scariness.Scare(10, bug_descr); } void Print(); }; @@ -253,7 +263,7 @@ BufferedStackTrace *stack_, uptr beg_, uptr end_, uptr old_mid_, uptr new_mid_) - : ErrorBase(tid), + : ErrorBase(tid, "bad-__sanitizer_annotate_contiguous_container"), stack(stack_), beg(beg_), end(end_), @@ -270,7 +280,7 @@ ErrorODRViolation() = default; ErrorODRViolation(u32 tid, const __asan_global *g1, u32 stack_id1_, const __asan_global *g2, u32 stack_id2_) - : ErrorBase(tid), + : ErrorBase(tid, "odr-violation"), global1(*g1), global2(*g2), stack_id1(stack_id1_), @@ -287,7 +297,7 @@ ErrorInvalidPointerPair() = default; ErrorInvalidPointerPair(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr p1, uptr p2) - : ErrorBase(tid), + : ErrorBase(tid, "invalid-pointer-pair"), pc(pc_), bp(bp_), sp(sp_), @@ -300,7 +310,6 @@ AddressDescription addr_description; uptr pc, bp, sp; uptr access_size; - const char *bug_descr; bool is_write; u8 shadow_val; // VS2013 doesn't implement unrestricted unions, so we need a trivial default Index: lib/asan/asan_errors.cc =================================================================== --- lib/asan/asan_errors.cc +++ lib/asan/asan_errors.cc @@ -26,8 +26,8 @@ Decorator d; Printf("%s", d.Warning()); Report( - "ERROR: AddressSanitizer: stack-overflow on address %p" - " (pc %p bp %p sp %p T%d)\n", + "ERROR: AddressSanitizer: %s on address %p" + " (pc %p bp %p sp %p T%d)\n", bug_descr, (void *)addr, (void *)pc, (void *)bp, (void *)sp, tid); Printf("%s", d.EndWarning()); scariness.Print(); @@ -35,7 +35,7 @@ GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context, common_flags()->fast_unwind_on_fatal); stack.Print(); - ReportErrorSummary("stack-overflow", &stack); + ReportErrorSummary(bug_descr, &stack); } static void MaybeDumpInstructionBytes(uptr pc) { @@ -87,9 +87,9 @@ Printf("%s", d.Warning()); char tname[128]; Report( - "ERROR: AddressSanitizer: attempting double-free on %p in " + "ERROR: AddressSanitizer: attempting %s on %p in " "thread T%d%s:\n", - addr_description.addr, tid, + bug_descr, addr_description.addr, tid, ThreadNameWithParenthesis(tid, tname, sizeof(tname))); Printf("%s", d.EndWarning()); scariness.Print(); @@ -97,7 +97,7 @@ second_free_stack->top_frame_bp); stack.Print(); addr_description.Print(); - ReportErrorSummary("double-free", &stack); + ReportErrorSummary(bug_descr, &stack); } void ErrorNewDeleteSizeMismatch::Print() { @@ -105,9 +105,9 @@ Printf("%s", d.Warning()); char tname[128]; Report( - "ERROR: AddressSanitizer: new-delete-type-mismatch on %p in thread " + "ERROR: AddressSanitizer: %s on %p in thread " "T%d%s:\n", - addr_description.addr, tid, + bug_descr, addr_description.addr, tid, ThreadNameWithParenthesis(tid, tname, sizeof(tname))); Printf("%s object passed to delete has wrong type:\n", d.EndWarning()); Printf( @@ -119,7 +119,7 @@ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); stack.Print(); addr_description.Print(); - ReportErrorSummary("new-delete-type-mismatch", &stack); + ReportErrorSummary(bug_descr, &stack); Report( "HINT: if you don't care about these errors you may set " "ASAN_OPTIONS=new_delete_type_mismatch=0\n"); @@ -140,7 +140,7 @@ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); stack.Print(); addr_description.Print(); - ReportErrorSummary("bad-free", &stack); + ReportErrorSummary(bug_descr, &stack); } void ErrorAllocTypeMismatch::Print() { @@ -151,7 +151,8 @@ CHECK_NE(alloc_type, dealloc_type); Decorator d; Printf("%s", d.Warning()); - Report("ERROR: AddressSanitizer: alloc-dealloc-mismatch (%s vs %s) on %p\n", + Report("ERROR: AddressSanitizer: %s (%s vs %s) on %p\n", + bug_descr, alloc_names[alloc_type], dealloc_names[dealloc_type], addr_description.addr); Printf("%s", d.EndWarning()); @@ -160,7 +161,7 @@ GET_STACK_TRACE_FATAL(dealloc_stack->trace[0], dealloc_stack->top_frame_bp); stack.Print(); addr_description.Print(); - ReportErrorSummary("alloc-dealloc-mismatch", &stack); + ReportErrorSummary(bug_descr, &stack); Report( "HINT: if you don't care about these errors you may set " "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n"); @@ -176,7 +177,7 @@ Printf("%s", d.EndWarning()); stack->Print(); addr_description.Print(); - ReportErrorSummary("bad-malloc_usable_size", stack); + ReportErrorSummary(bug_descr, stack); } void ErrorSanitizerGetAllocatedSizeNotOwned::Print() { @@ -189,7 +190,7 @@ Printf("%s", d.EndWarning()); stack->Print(); addr_description.Print(); - ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack); + ReportErrorSummary(bug_descr, stack); } void ErrorStringFunctionMemoryRangesOverlap::Print() { @@ -214,13 +215,12 @@ void ErrorStringFunctionSizeOverflow::Print() { Decorator d; Printf("%s", d.Warning()); - const char *bug_type = "negative-size-param"; - Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", bug_type, size); + Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", bug_descr, size); Printf("%s", d.EndWarning()); scariness.Print(); stack->Print(); addr_description.Print(); - ReportErrorSummary(bug_type, stack); + ReportErrorSummary(bug_descr, stack); } void ErrorBadParamsToAnnotateContiguousContainer::Print() { @@ -236,13 +236,13 @@ if (!IsAligned(beg, granularity)) Report("ERROR: beg is not aligned by %d\n", granularity); stack->Print(); - ReportErrorSummary("bad-__sanitizer_annotate_contiguous_container", stack); + ReportErrorSummary(bug_descr, stack); } void ErrorODRViolation::Print() { Decorator d; Printf("%s", d.Warning()); - Report("ERROR: AddressSanitizer: odr-violation (%p):\n", global1.beg); + Report("ERROR: AddressSanitizer: %s (%p):\n", bug_descr, global1.beg); Printf("%s", d.EndWarning()); InternalScopedString g1_loc(256), g2_loc(256); PrintGlobalLocation(&g1_loc, global1); @@ -262,23 +262,22 @@ "HINT: if you don't care about these errors you may set " "ASAN_OPTIONS=detect_odr_violation=0\n"); InternalScopedString error_msg(256); - error_msg.append("odr-violation: global '%s' at %s", + error_msg.append("%s: global '%s' at %s", bug_descr, MaybeDemangleGlobalName(global1.name), g1_loc.data()); ReportErrorSummary(error_msg.data()); } void ErrorInvalidPointerPair::Print() { - const char *bug_type = "invalid-pointer-pair"; Decorator d; Printf("%s", d.Warning()); - Report("ERROR: AddressSanitizer: invalid-pointer-pair: %p %p\n", + Report("ERROR: AddressSanitizer: %s: %p %p\n", bug_descr, addr1_description.Address(), addr2_description.Address()); Printf("%s", d.EndWarning()); GET_STACK_TRACE_FATAL(pc, bp); stack.Print(); addr1_description.Print(); addr2_description.Print(); - ReportErrorSummary(bug_type, &stack); + ReportErrorSummary(bug_descr, &stack); } static bool AdjacentShadowValuesAreFullyPoisoned(u8 *s) { @@ -287,7 +286,7 @@ ErrorGeneric::ErrorGeneric(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr addr, bool is_write_, uptr access_size_) - : ErrorBase(tid), + : ErrorBase(tid, nullptr), addr_description(addr, access_size_, /*shouldLockThreadRegistry=*/false), pc(pc_), bp(bp_), Index: lib/asan/asan_report.cc =================================================================== --- lib/asan/asan_report.cc +++ lib/asan/asan_report.cc @@ -427,7 +427,7 @@ } int __asan_report_present() { - return ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric; + return ScopedInErrorReport::CurrentError().kind != kErrorKindInvalid; } uptr __asan_get_report_pc() { @@ -449,9 +449,11 @@ } uptr __asan_get_report_address() { - if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) - return ScopedInErrorReport::CurrentError() - .Generic.addr_description.Address(); + ErrorDescription &err = ScopedInErrorReport::CurrentError(); + if (err.kind == kErrorKindGeneric) + return err.Generic.addr_description.Address(); + else if (err.kind == kErrorKindDoubleFree) + return err.DoubleFree.addr_description.addr; return 0; } @@ -468,7 +470,7 @@ } const char *__asan_get_report_description() { - if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) + if (ScopedInErrorReport::CurrentError().kind != kErrorKindInvalid) return ScopedInErrorReport::CurrentError().Generic.bug_descr; return nullptr; } Index: test/asan/TestCases/debug_double_free.cc =================================================================== --- test/asan/TestCases/debug_double_free.cc +++ test/asan/TestCases/debug_double_free.cc @@ -0,0 +1,32 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s + +#include +#include +#include + +char *heap_ptr; + +int main() { + heap_ptr = (char *)malloc(10); + fprintf(stderr, "heap_ptr: %p\n", heap_ptr); + // CHECK: heap_ptr: 0x[[ADDR:[0-9a-f]+]] + + free(heap_ptr); + free(heap_ptr); // BOOM + return 0; +} + +void __asan_on_error() { + int present = __asan_report_present(); + void *addr = __asan_get_report_address(); + const char *description = __asan_get_report_description(); + + fprintf(stderr, "%s\n", (present == 1) ? "report present" : ""); + // CHECK: report present + fprintf(stderr, "addr: %p\n", addr); + // CHECK: addr: {{0x0*}}[[ADDR]] + fprintf(stderr, "description: %s\n", description); + // CHECK: description: double-free +} + +// CHECK: AddressSanitizer: attempting double-free on {{0x0*}}[[ADDR]] in thread T0