Index: lib/asan/CMakeLists.txt =================================================================== --- lib/asan/CMakeLists.txt +++ lib/asan/CMakeLists.txt @@ -5,6 +5,7 @@ asan_activation.cc asan_debugging.cc asan_descriptions.cc + asan_errors.cc asan_fake_stack.cc asan_flags.cc asan_globals.cc Index: lib/asan/asan_errors.h =================================================================== --- /dev/null +++ lib/asan/asan_errors.h @@ -0,0 +1,82 @@ +//===-- asan_errors.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// ASan-private header for error structures. +//===----------------------------------------------------------------------===// +#ifndef ASAN_ERRORS_H +#define ASAN_ERRORS_H + +#include "asan_descriptions.h" +#include "asan_scariness_score.h" + +namespace __asan { + +struct ErrorBase { + ScarinessScoreBase scariness; +}; + +struct ErrorStackOverflow : ErrorBase { + u32 tid; + uptr addr, pc, bp, sp; + // ErrorStackOverflow never owns the context. + void *context; + // VS2013 doesn't implement unrestricted unions, so we need a trivial default + // constructor + ErrorStackOverflow() = default; + ErrorStackOverflow(const SignalContext &sig, u32 tid_) + : tid(tid_), + addr(sig.addr), + pc(sig.pc), + bp(sig.bp), + sp(sig.sp), + context(sig.context) { + scariness.Clear(); + scariness.Scare(10, "stack-overflow"); + } + void Print(); +}; + +enum ErrorKind { + kErrorKindInvalid = 0, + kErrorKindStackOverflow, +}; + +struct ErrorDescription { + ErrorKind kind; + // We're using a tagged union because it allows us to have a trivially + // copiable type and use the same structures as the public interface. + // + // We can add a wrapper around it to make it "more c++-like", but that would + // add a lot of code and the benefit wouldn't be that big. + union { + ErrorStackOverflow stack_overflow; + }; + ErrorDescription() { internal_memset(this, 0, sizeof(*this)); } + ErrorDescription(const ErrorStackOverflow &e) // NOLINT + : kind(kErrorKindStackOverflow), + stack_overflow(e) {} + + bool IsValid() { return kind != kErrorKindInvalid; } + void Print() { + switch (kind) { + case kErrorKindStackOverflow: + stack_overflow.Print(); + return; + case kErrorKindInvalid: + CHECK(0); + } + CHECK(0); + } +}; + +} // namespace __asan + +#endif // ASAN_ERRORS_H Index: lib/asan/asan_errors.cc =================================================================== --- /dev/null +++ lib/asan/asan_errors.cc @@ -0,0 +1,36 @@ +//===-- asan_errors.cc ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// ASan implementation for error structures. +//===----------------------------------------------------------------------===// + +#include "asan_errors.h" +#include "asan_stack.h" + +namespace __asan { + +void ErrorStackOverflow::Print() { + Decorator d; + Printf("%s", d.Warning()); + Report( + "ERROR: AddressSanitizer: stack-overflow on address %p" + " (pc %p bp %p sp %p T%d)\n", + (void *)addr, (void *)pc, (void *)bp, (void *)sp, tid); + Printf("%s", d.EndWarning()); + scariness.Print(); + BufferedStackTrace stack; + GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context, + common_flags()->fast_unwind_on_fatal); + stack.Print(); + ReportErrorSummary("stack-overflow", &stack); +} + +} // namespace __asan Index: lib/asan/asan_report.cc =================================================================== --- lib/asan/asan_report.cc +++ lib/asan/asan_report.cc @@ -12,6 +12,7 @@ // This file contains error reporting code. //===----------------------------------------------------------------------===// +#include "asan_errors.h" #include "asan_flags.h" #include "asan_descriptions.h" #include "asan_internal.h" @@ -267,6 +268,8 @@ } ~ScopedInErrorReport() { + if (current_error_.IsValid()) current_error_.Print(); + // Make sure the current thread is announced. DescribeThread(GetCurrentThread()); // We may want to grab this lock again when printing stats. @@ -301,6 +304,12 @@ } } + void ReportError(const ErrorDescription &description) { + // Can only report one error per ScopedInErrorReport. + CHECK_EQ(current_error_.kind, kErrorKindInvalid); + current_error_ = description; + } + private: void StartReporting(ReportData *report) { if (report) report_data = *report; @@ -319,26 +328,20 @@ static StaticSpinMutex lock_; static u32 reporting_thread_tid_; + // Error currently being reported. This enables the destructor to interact + // with the debugger and point it to an error description. + static ErrorDescription current_error_; bool halt_on_error_; }; StaticSpinMutex ScopedInErrorReport::lock_; u32 ScopedInErrorReport::reporting_thread_tid_ = kInvalidTid; +ErrorDescription ScopedInErrorReport::current_error_; void ReportStackOverflow(const SignalContext &sig) { ScopedInErrorReport in_report(/*report*/ nullptr, /*fatal*/ true); - Decorator d; - Printf("%s", d.Warning()); - Report( - "ERROR: AddressSanitizer: stack-overflow on address %p" - " (pc %p bp %p sp %p T%d)\n", - (void *)sig.addr, (void *)sig.pc, (void *)sig.bp, (void *)sig.sp, - GetCurrentTidOrInvalid()); - Printf("%s", d.EndWarning()); - ScarinessScore::PrintSimple(10, "stack-overflow"); - GET_STACK_TRACE_SIGNAL(sig); - stack.Print(); - ReportErrorSummary("stack-overflow", &stack); + ErrorStackOverflow error{sig, GetCurrentTidOrInvalid()}; // NOLINT + in_report.ReportError(error); } void ReportDeadlySignal(const char *description, const SignalContext &sig) {