[asan] Reify ErrorDeadlySignal

Summary: Keep reifying other errors.

Reviewers: kcc, samsonov

Subscribers: llvm-commits, kubabrecka

Differential Revision: https://reviews.llvm.org/D23873

llvm-svn: 280930
This commit is contained in:
Filipe Cabecinhas 2016-09-08 12:58:15 +00:00
parent 753c18f5c0
commit 1989be7cf0
7 changed files with 125 additions and 71 deletions

View File

@ -13,7 +13,9 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "asan_errors.h" #include "asan_errors.h"
#include <signal.h>
#include "asan_descriptions.h" #include "asan_descriptions.h"
#include "asan_report.h"
#include "asan_stack.h" #include "asan_stack.h"
namespace __asan { namespace __asan {
@ -34,6 +36,50 @@ void ErrorStackOverflow::Print() {
ReportErrorSummary("stack-overflow", &stack); 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() { void ErrorDoubleFree::Print() {
Decorator d; Decorator d;
Printf("%s", d.Warning()); Printf("%s", d.Warning());

View File

@ -16,6 +16,7 @@
#include "asan_descriptions.h" #include "asan_descriptions.h"
#include "asan_scariness_score.h" #include "asan_scariness_score.h"
#include "sanitizer_common/sanitizer_common.h"
namespace __asan { namespace __asan {
@ -44,6 +45,47 @@ struct ErrorStackOverflow : ErrorBase {
void Print(); 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) {
scariness.Clear();
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 { struct ErrorDoubleFree : ErrorBase {
u32 tid; u32 tid;
HeapAddressDescription addr_description; HeapAddressDescription addr_description;
@ -84,6 +126,7 @@ struct ErrorNewDeleteSizeMismatch : ErrorBase {
enum ErrorKind { enum ErrorKind {
kErrorKindInvalid = 0, kErrorKindInvalid = 0,
kErrorKindStackOverflow, kErrorKindStackOverflow,
kErrorKindDeadlySignal,
kErrorKindDoubleFree, kErrorKindDoubleFree,
kErrorKindNewDeleteSizeMismatch, kErrorKindNewDeleteSizeMismatch,
}; };
@ -97,6 +140,7 @@ struct ErrorDescription {
// add a lot of code and the benefit wouldn't be that big. // add a lot of code and the benefit wouldn't be that big.
union { union {
ErrorStackOverflow stack_overflow; ErrorStackOverflow stack_overflow;
ErrorDeadlySignal deadly_signal;
ErrorDoubleFree double_free; ErrorDoubleFree double_free;
ErrorNewDeleteSizeMismatch new_delete_size_mismatch; ErrorNewDeleteSizeMismatch new_delete_size_mismatch;
}; };
@ -104,6 +148,9 @@ struct ErrorDescription {
ErrorDescription(const ErrorStackOverflow &e) // NOLINT ErrorDescription(const ErrorStackOverflow &e) // NOLINT
: kind(kErrorKindStackOverflow), : kind(kErrorKindStackOverflow),
stack_overflow(e) {} stack_overflow(e) {}
ErrorDescription(const ErrorDeadlySignal &e) // NOLINT
: kind(kErrorKindDeadlySignal),
deadly_signal(e) {}
ErrorDescription(const ErrorDoubleFree &e) // NOLINT ErrorDescription(const ErrorDoubleFree &e) // NOLINT
: kind(kErrorKindDoubleFree), : kind(kErrorKindDoubleFree),
double_free(e) {} double_free(e) {}
@ -117,6 +164,9 @@ struct ErrorDescription {
case kErrorKindStackOverflow: case kErrorKindStackOverflow:
stack_overflow.Print(); stack_overflow.Print();
return; return;
case kErrorKindDeadlySignal:
deadly_signal.Print();
return;
case kErrorKindDoubleFree: case kErrorKindDoubleFree:
double_free.Print(); double_free.Print();
return; return;

View File

@ -65,6 +65,9 @@ void AsanInitFromRtl();
// asan_win.cc // asan_win.cc
void InitializePlatformExceptionHandlers(); void InitializePlatformExceptionHandlers();
// asan_win.cc / asan_posix.cc
const char *DescribeSignalOrException(int signo);
// asan_rtl.cc // asan_rtl.cc
void NORETURN ShowStatsAndAbort(); void NORETURN ShowStatsAndAbort();

View File

@ -33,6 +33,17 @@
namespace __asan { 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) { void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
ScopedDeadlySignal signal_scope(GetCurrentThread()); ScopedDeadlySignal signal_scope(GetCurrentThread());
int code = (int)((siginfo_t*)siginfo)->si_code; int code = (int)((siginfo_t*)siginfo)->si_code;
@ -84,14 +95,8 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
// unaligned memory access. // unaligned memory access.
if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR)) if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
ReportStackOverflow(sig); ReportStackOverflow(sig);
else if (signo == SIGFPE)
ReportDeadlySignal("FPE", sig);
else if (signo == SIGILL)
ReportDeadlySignal("ILL", sig);
else if (signo == SIGABRT)
ReportDeadlySignal("ABRT", sig);
else else
ReportDeadlySignal("SEGV", sig); ReportDeadlySignal(signo, sig);
} }
// ---------------------- TSD ---------------- {{{1 // ---------------------- TSD ---------------- {{{1

View File

@ -69,8 +69,8 @@ void AppendToErrorMessageBuffer(const char *buffer) {
// ---------------------- Helper functions ----------------------- {{{1 // ---------------------- Helper functions ----------------------- {{{1
static void PrintMemoryByte(InternalScopedString *str, const char *before, void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte,
u8 byte, bool in_shadow, const char *after = "\n") { bool in_shadow, const char *after) {
Decorator d; Decorator d;
str->append("%s%s%x%x%s%s", before, str->append("%s%s%x%x%s%s", before,
in_shadow ? d.ShadowByte(byte) : d.MemoryByte(), in_shadow ? d.ShadowByte(byte) : d.MemoryByte(),
@ -135,22 +135,6 @@ static void PrintLegend(InternalScopedString *str) {
PrintShadowByte(str, " Right alloca redzone: ", kAsanAllocaRightMagic); 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) { static void PrintShadowMemoryForAddress(uptr addr) {
if (!AddrIsInMem(addr)) return; if (!AddrIsInMem(addr)) return;
uptr shadow_addr = MemToShadow(addr); uptr shadow_addr = MemToShadow(addr);
@ -344,46 +328,10 @@ void ReportStackOverflow(const SignalContext &sig) {
in_report.ReportError(error); 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); ScopedInErrorReport in_report(/*report*/ nullptr, /*fatal*/ true);
Decorator d; ErrorDeadlySignal error(signo, sig, GetCurrentTidOrInvalid());
Printf("%s", d.Warning()); in_report.ReportError(error);
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);
} }
void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) { void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {

View File

@ -42,6 +42,9 @@ const char *MaybeDemangleGlobalName(const char *name);
void PrintGlobalNameIfASCII(InternalScopedString *str, const __asan_global &g); void PrintGlobalNameIfASCII(InternalScopedString *str, const __asan_global &g);
void PrintGlobalLocation(InternalScopedString *str, const __asan_global &g); void PrintGlobalLocation(InternalScopedString *str, const __asan_global &g);
void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte,
bool in_shadow, const char *after = "\n");
// The following functions prints address description depending // The following functions prints address description depending
// on the memory type (shadow/heap/stack/global). // on the memory type (shadow/heap/stack/global).
bool ParseFrameDescription(const char *frame_descr, bool ParseFrameDescription(const char *frame_descr,
@ -51,7 +54,7 @@ bool ParseFrameDescription(const char *frame_descr,
void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
uptr access_size, u32 exp, bool fatal); uptr access_size, u32 exp, bool fatal);
void ReportStackOverflow(const SignalContext &sig); void ReportStackOverflow(const SignalContext &sig);
void ReportDeadlySignal(const char *description, const SignalContext &sig); void ReportDeadlySignal(int signo, const SignalContext &sig);
void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size, void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
BufferedStackTrace *free_stack); BufferedStackTrace *free_stack);
void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack); void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);

View File

@ -270,7 +270,10 @@ static bool ShouldReportDeadlyException(unsigned code) {
} }
// Return the textual name for this exception. // 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) { switch (code) {
case EXCEPTION_ACCESS_VIOLATION: case EXCEPTION_ACCESS_VIOLATION:
return "access-violation"; return "access-violation";
@ -289,12 +292,8 @@ static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
CONTEXT *context = info->ContextRecord; CONTEXT *context = info->ContextRecord;
if (ShouldReportDeadlyException(exception_record->ExceptionCode)) { 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); SignalContext sig = SignalContext::Create(exception_record, context);
ReportDeadlySignal(description, sig); ReportDeadlySignal(exception_record->ExceptionCode, sig);
} }
// FIXME: Handle EXCEPTION_STACK_OVERFLOW here. // FIXME: Handle EXCEPTION_STACK_OVERFLOW here.