forked from OSchip/llvm-project
[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:
parent
753c18f5c0
commit
1989be7cf0
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue