Skip to content

Commit

Permalink
[ASan] Enable optional ASan recovery.
Browse files Browse the repository at this point in the history
Differential Revision: http://reviews.llvm.org/D12318

llvm-svn: 252723
  • Loading branch information
Yury Gribov committed Nov 11, 2015
1 parent 12982a8 commit 468d955
Show file tree
Hide file tree
Showing 10 changed files with 320 additions and 88 deletions.
3 changes: 3 additions & 0 deletions compiler-rt/lib/asan/asan_flags.inc
Expand Up @@ -134,3 +134,6 @@ ASAN_FLAG(int, detect_odr_violation, 2,
ASAN_FLAG(bool, dump_instruction_bytes, false,
"If true, dump 16 bytes starting at the instruction that caused SEGV")
ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
ASAN_FLAG(bool, halt_on_error, true,
"Crash the program after printing the first error report "
"(WARNING: USE AT YOUR OWN RISK!)")
2 changes: 1 addition & 1 deletion compiler-rt/lib/asan/asan_interceptors.cc
Expand Up @@ -75,7 +75,7 @@ struct AsanInterceptorContext {
} \
if (!suppressed) { \
GET_CURRENT_PC_BP_SP; \
__asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0); \
ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\
} \
} \
} while (0)
Expand Down
13 changes: 13 additions & 0 deletions compiler-rt/lib/asan/asan_interface_internal.h
Expand Up @@ -167,6 +167,19 @@ extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN(uptr p, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN(uptr p, uptr size);

SANITIZER_INTERFACE_ATTRIBUTE void __asan_load1_noabort(uptr p);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_load2_noabort(uptr p);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_load4_noabort(uptr p);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_load8_noabort(uptr p);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_load16_noabort(uptr p);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_store1_noabort(uptr p);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_store2_noabort(uptr p);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_store4_noabort(uptr p);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_store8_noabort(uptr p);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_store16_noabort(uptr p);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_loadN_noabort(uptr p, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_storeN_noabort(uptr p, uptr size);

SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load1(uptr p, u32 exp);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load2(uptr p, u32 exp);
SANITIZER_INTERFACE_ATTRIBUTE void __asan_exp_load4(uptr p, u32 exp);
Expand Down
117 changes: 86 additions & 31 deletions compiler-rt/lib/asan/asan_report.cc
Expand Up @@ -622,41 +622,56 @@ void DescribeThread(AsanThreadContext *context) {
// immediately after printing error report.
class ScopedInErrorReport {
public:
explicit ScopedInErrorReport(ReportData *report = nullptr) {
static atomic_uint32_t num_calls;
static u32 reporting_thread_tid;
if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
explicit ScopedInErrorReport(ReportData *report = nullptr,
bool fatal = false) {
halt_on_error_ = fatal || flags()->halt_on_error;

if (lock_.TryLock()) {
StartReporting(report);
return;
}

// ASan found two bugs in different threads simultaneously.

u32 current_tid = GetCurrentTidOrInvalid();
if (current_tid == reporting_thread_tid_ || current_tid == kInvalidTid) {
// This is either asynch signal or nested error during error reporting.
// Fail fast to avoid deadlocks.

// Can't use Report() here because of potential deadlocks
// in nested signal handlers.
const char msg[] = "AddressSanitizer: nested bug in the same thread, "
"aborting.\n";
WriteToFile(kStderrFd, msg, sizeof(msg));

internal__exit(common_flags()->exitcode);
}

if (halt_on_error_) {
// Do not print more than one report, otherwise they will mix up.
// Error reporting functions shouldn't return at this situation, as
// they are defined as no-return.
// they are effectively no-returns.

Report("AddressSanitizer: while reporting a bug found another one. "
"Ignoring.\n");
u32 current_tid = GetCurrentTidOrInvalid();
if (current_tid != reporting_thread_tid) {
// ASan found two bugs in different threads simultaneously. Sleep
// long enough to make sure that the thread which started to print
// an error report will finish doing it.
SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
}
"Ignoring.\n");

// Sleep long enough to make sure that the thread which started
// to print an error report will finish doing it.
SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));

// If we're still not dead for some reason, use raw _exit() instead of
// Die() to bypass any additional checks.
internal__exit(common_flags()->exitcode);
} else {
// The other thread will eventually finish reporting
// so it's safe to wait
lock_.Lock();
}
if (report) report_data = *report;
report_happened = true;
ASAN_ON_ERROR();
// Make sure the registry and sanitizer report mutexes are locked while
// we're printing an error report.
// We can lock them only here to avoid self-deadlock in case of
// recursive reports.
asanThreadRegistry().Lock();
CommonSanitizerReportMutex.Lock();
reporting_thread_tid = GetCurrentTidOrInvalid();
Printf("===================================================="
"=============\n");

StartReporting(report);
}
// Destructor is NORETURN, as functions that report errors are.
NORETURN ~ScopedInErrorReport() {

~ScopedInErrorReport() {
// Make sure the current thread is announced.
DescribeThread(GetCurrentThread());
// We may want to grab this lock again when printing stats.
Expand All @@ -667,11 +682,39 @@ class ScopedInErrorReport {
if (error_report_callback) {
error_report_callback(error_message_buffer);
}
Report("ABORTING\n");
Die();
CommonSanitizerReportMutex.Unlock();
reporting_thread_tid_ = kInvalidTid;
lock_.Unlock();
if (halt_on_error_) {
Report("ABORTING\n");
Die();
}
}

private:
void StartReporting(ReportData *report) {
if (report) report_data = *report;
report_happened = true;
ASAN_ON_ERROR();
// Make sure the registry and sanitizer report mutexes are locked while
// we're printing an error report.
// We can lock them only here to avoid self-deadlock in case of
// recursive reports.
asanThreadRegistry().Lock();
CommonSanitizerReportMutex.Lock();
reporting_thread_tid_ = GetCurrentTidOrInvalid();
Printf("===================================================="
"=============\n");
}

static StaticSpinMutex lock_;
static u32 reporting_thread_tid_;
bool halt_on_error_;
};

StaticSpinMutex ScopedInErrorReport::lock_;
u32 ScopedInErrorReport::reporting_thread_tid_;

void ReportStackOverflow(const SignalContext &sig) {
ScopedInErrorReport in_report;
Decorator d;
Expand All @@ -688,7 +731,7 @@ void ReportStackOverflow(const SignalContext &sig) {
}

void ReportDeadlySignal(const char *description, const SignalContext &sig) {
ScopedInErrorReport in_report;
ScopedInErrorReport in_report(/*report*/nullptr, /*fatal*/true);
Decorator d;
Printf("%s", d.Warning());
Report(
Expand Down Expand Up @@ -1034,7 +1077,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,

ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size,
bug_descr };
ScopedInErrorReport in_report(&report);
ScopedInErrorReport in_report(&report, fatal);

Decorator d;
Printf("%s", d.Warning());
Expand All @@ -1060,6 +1103,18 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
PrintShadowMemoryForAddress(addr);
}

} // namespace __asan

// --------------------------- Interface --------------------- {{{1
using namespace __asan; // NOLINT

void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
uptr access_size, u32 exp) {
ENABLE_FRAME_POINTER;
bool fatal = flags()->halt_on_error;
ReportGenericError(pc, bp, sp, addr, is_write, access_size, exp, fatal);
}

void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
error_report_callback = callback;
if (callback) {
Expand Down
66 changes: 31 additions & 35 deletions compiler-rt/lib/asan/asan_report.h
Expand Up @@ -49,45 +49,41 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size);
void DescribeThread(AsanThreadContext *context);

// Different kinds of error reports.
void NORETURN ReportStackOverflow(const SignalContext &sig);
void NORETURN ReportDeadlySignal(const char* description,
const SignalContext &sig);
void NORETURN ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
BufferedStackTrace *free_stack);
void NORETURN ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
void NORETURN ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack);
void NORETURN ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
AllocType alloc_type,
AllocType dealloc_type);
void NORETURN
ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack);
void NORETURN
ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
BufferedStackTrace *stack);
void NORETURN
ReportStringFunctionMemoryRangesOverlap(const char *function,
const char *offset1, uptr length1,
const char *offset2, uptr length2,
BufferedStackTrace *stack);
void NORETURN ReportStringFunctionSizeOverflow(uptr offset, uptr size,
BufferedStackTrace *stack);
void NORETURN
ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
uptr old_mid, uptr new_mid,
BufferedStackTrace *stack);
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 delete_size,
BufferedStackTrace *free_stack);
void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack);
void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
AllocType alloc_type,
AllocType dealloc_type);
void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack);
void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
BufferedStackTrace *stack);
void ReportStringFunctionMemoryRangesOverlap(const char *function,
const char *offset1, uptr length1,
const char *offset2, uptr length2,
BufferedStackTrace *stack);
void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
BufferedStackTrace *stack);
void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
uptr old_mid, uptr new_mid,
BufferedStackTrace *stack);

void NORETURN
ReportODRViolation(const __asan_global *g1, u32 stack_id1,
const __asan_global *g2, u32 stack_id2);
void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
const __asan_global *g2, u32 stack_id2);

// Mac-specific errors and warnings.
void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name,
BufferedStackTrace *stack);
void NORETURN ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr,
const char *zone_name,
BufferedStackTrace *stack);
void NORETURN ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr,
const char *zone_name,
BufferedStackTrace *stack);
void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr,
const char *zone_name,
BufferedStackTrace *stack);
void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr,
const char *zone_name,
BufferedStackTrace *stack);

} // namespace __asan

0 comments on commit 468d955

Please sign in to comment.