[ASan] Enable optional ASan recovery.
Differential Revision: http://reviews.llvm.org/D12318 llvm-svn: 252723
This commit is contained in:
parent
12982a816c
commit
468d955b98
|
|
@ -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!)")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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;
|
||||
|
|
@ -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(
|
||||
|
|
@ -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());
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -113,13 +113,18 @@ static void OnLowLevelAllocate(uptr ptr, uptr size) {
|
|||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_report_ ## type ## size(uptr addr) { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
__asan_report_error(pc, bp, sp, addr, is_write, size, 0); \
|
||||
ReportGenericError(pc, bp, sp, addr, is_write, size, 0, true); \
|
||||
} \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_report_exp_ ## type ## size(uptr addr, u32 exp) { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
__asan_report_error(pc, bp, sp, addr, is_write, size, exp); \
|
||||
}
|
||||
ReportGenericError(pc, bp, sp, addr, is_write, size, exp, true); \
|
||||
} \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_report_ ## type ## size ## _noabort(uptr addr) { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
ReportGenericError(pc, bp, sp, addr, is_write, size, 0, false); \
|
||||
} \
|
||||
|
||||
ASAN_REPORT_ERROR(load, false, 1)
|
||||
ASAN_REPORT_ERROR(load, false, 2)
|
||||
|
|
@ -132,22 +137,27 @@ ASAN_REPORT_ERROR(store, true, 4)
|
|||
ASAN_REPORT_ERROR(store, true, 8)
|
||||
ASAN_REPORT_ERROR(store, true, 16)
|
||||
|
||||
#define ASAN_REPORT_ERROR_N(type, is_write) \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_report_ ## type ## _n(uptr addr, uptr size) { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
__asan_report_error(pc, bp, sp, addr, is_write, size, 0); \
|
||||
} \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
#define ASAN_REPORT_ERROR_N(type, is_write) \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_report_ ## type ## _n(uptr addr, uptr size) { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
ReportGenericError(pc, bp, sp, addr, is_write, size, 0, true); \
|
||||
} \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_report_exp_ ## type ## _n(uptr addr, uptr size, u32 exp) { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
__asan_report_error(pc, bp, sp, addr, is_write, size, exp); \
|
||||
}
|
||||
ReportGenericError(pc, bp, sp, addr, is_write, size, exp, true); \
|
||||
} \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_report_ ## type ## _n_noabort(uptr addr, uptr size) { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
ReportGenericError(pc, bp, sp, addr, is_write, size, 0, false); \
|
||||
} \
|
||||
|
||||
ASAN_REPORT_ERROR_N(load, false)
|
||||
ASAN_REPORT_ERROR_N(store, true)
|
||||
|
||||
#define ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp_arg) \
|
||||
#define ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp_arg, fatal) \
|
||||
uptr sp = MEM_TO_SHADOW(addr); \
|
||||
uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast<u8 *>(sp) \
|
||||
: *reinterpret_cast<u16 *>(sp); \
|
||||
|
|
@ -159,7 +169,8 @@ ASAN_REPORT_ERROR_N(store, true)
|
|||
*__asan_test_only_reported_buggy_pointer = addr; \
|
||||
} else { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
__asan_report_error(pc, bp, sp, addr, is_write, size, exp_arg); \
|
||||
ReportGenericError(pc, bp, sp, addr, is_write, size, exp_arg, \
|
||||
fatal); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
|
@ -167,12 +178,16 @@ ASAN_REPORT_ERROR_N(store, true)
|
|||
#define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size) \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_##type##size(uptr addr) { \
|
||||
ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0) \
|
||||
ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0, true) \
|
||||
} \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_exp_##type##size(uptr addr, u32 exp) { \
|
||||
ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp) \
|
||||
}
|
||||
ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp, true) \
|
||||
} \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_##type##size ## _noabort(uptr addr) { \
|
||||
ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, 0, false) \
|
||||
} \
|
||||
|
||||
ASAN_MEMORY_ACCESS_CALLBACK(load, false, 1)
|
||||
ASAN_MEMORY_ACCESS_CALLBACK(load, false, 2)
|
||||
|
|
@ -190,7 +205,7 @@ NOINLINE INTERFACE_ATTRIBUTE
|
|||
void __asan_loadN(uptr addr, uptr size) {
|
||||
if (__asan_region_is_poisoned(addr, size)) {
|
||||
GET_CALLER_PC_BP_SP;
|
||||
__asan_report_error(pc, bp, sp, addr, false, size, 0);
|
||||
ReportGenericError(pc, bp, sp, addr, false, size, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -199,7 +214,16 @@ NOINLINE INTERFACE_ATTRIBUTE
|
|||
void __asan_exp_loadN(uptr addr, uptr size, u32 exp) {
|
||||
if (__asan_region_is_poisoned(addr, size)) {
|
||||
GET_CALLER_PC_BP_SP;
|
||||
__asan_report_error(pc, bp, sp, addr, false, size, exp);
|
||||
ReportGenericError(pc, bp, sp, addr, false, size, exp, true);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
NOINLINE INTERFACE_ATTRIBUTE
|
||||
void __asan_loadN_noabort(uptr addr, uptr size) {
|
||||
if (__asan_region_is_poisoned(addr, size)) {
|
||||
GET_CALLER_PC_BP_SP;
|
||||
ReportGenericError(pc, bp, sp, addr, false, size, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -208,7 +232,7 @@ NOINLINE INTERFACE_ATTRIBUTE
|
|||
void __asan_storeN(uptr addr, uptr size) {
|
||||
if (__asan_region_is_poisoned(addr, size)) {
|
||||
GET_CALLER_PC_BP_SP;
|
||||
__asan_report_error(pc, bp, sp, addr, true, size, 0);
|
||||
ReportGenericError(pc, bp, sp, addr, true, size, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +241,16 @@ NOINLINE INTERFACE_ATTRIBUTE
|
|||
void __asan_exp_storeN(uptr addr, uptr size, u32 exp) {
|
||||
if (__asan_region_is_poisoned(addr, size)) {
|
||||
GET_CALLER_PC_BP_SP;
|
||||
__asan_report_error(pc, bp, sp, addr, true, size, exp);
|
||||
ReportGenericError(pc, bp, sp, addr, true, size, exp, true);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
NOINLINE INTERFACE_ATTRIBUTE
|
||||
void __asan_storeN_noabort(uptr addr, uptr size) {
|
||||
if (__asan_region_is_poisoned(addr, size)) {
|
||||
GET_CALLER_PC_BP_SP;
|
||||
ReportGenericError(pc, bp, sp, addr, true, size, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,18 @@
|
|||
// RUN: echo __asan_report_store16 >> %t.interface
|
||||
// RUN: echo __asan_report_load_n >> %t.interface
|
||||
// RUN: echo __asan_report_store_n >> %t.interface
|
||||
// RUN: echo __asan_report_load1_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_load2_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_load4_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_load8_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_load16_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_store1_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_store2_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_store4_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_store8_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_store16_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_load_n_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_store_n_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_exp_load1 >> %t.interface
|
||||
// RUN: echo __asan_report_exp_load2 >> %t.interface
|
||||
// RUN: echo __asan_report_exp_load4 >> %t.interface
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
// Stress test recovery mode with many threads.
|
||||
//
|
||||
// RUN: %clangxx_asan -fsanitize-recover=address %s -o %t
|
||||
//
|
||||
// RUN: env ASAN_OPTIONS=halt_on_error=false:max_errors=1000 %run %t 1 10 >1.txt 2>&1
|
||||
// RUN: FileCheck %s < 1.txt
|
||||
// RUN: [ $(wc -l < 1.txt) -gt 1 ]
|
||||
//
|
||||
// RUN: env ASAN_OPTIONS=halt_on_error=false:max_errors=1000 %run %t 10 20 >10.txt 2>&1
|
||||
// RUN: FileCheck %s < 10.txt
|
||||
// This one is racy although very unlikely to fail:
|
||||
// RUN: [ $(wc -l < 10.txt) -gt 1 ]
|
||||
// Collisions are highly unlikely but still possible so we need the alternative:
|
||||
// RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 1.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 1.txt
|
||||
//
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <sanitizer/asan_interface.h>
|
||||
|
||||
size_t nthreads = 10;
|
||||
size_t niter = 10;
|
||||
|
||||
void *run(void *arg) {
|
||||
unsigned seed = (unsigned)(size_t)arg;
|
||||
|
||||
volatile char tmp[2];
|
||||
__asan_poison_memory_region(&tmp, sizeof(tmp));
|
||||
|
||||
for (size_t i = 0; i < niter; ++i) {
|
||||
struct timespec delay = { 0, rand_r(&seed) * 1000000 };
|
||||
nanosleep(&delay, 0);
|
||||
|
||||
// Expect error collisions here
|
||||
// CHECK: AddressSanitizer: use-after-poison
|
||||
volatile int idx = 0;
|
||||
tmp[idx] = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Syntax: %s nthreads niter\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
nthreads = (size_t)strtoul(argv[1], 0, 0);
|
||||
niter = (size_t)strtoul(argv[2], 0, 0);
|
||||
|
||||
pthread_t *tids = new pthread_t[nthreads];
|
||||
|
||||
for (size_t i = 0; i < nthreads; ++i) {
|
||||
if (0 != pthread_create(&tids[i], 0, run, (void *)i)) {
|
||||
fprintf(stderr, "Failed to create thread\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nthreads; ++i) {
|
||||
if (0 != pthread_join(tids[i], 0)) {
|
||||
fprintf(stderr, "Failed to join thread\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK-COLLISION: AddressSanitizer: nested bug in the same thread, aborting
|
||||
// CHECK-NO-COLLISION: All threads terminated
|
||||
printf("All threads terminated\n");
|
||||
|
||||
delete [] tids;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -24,6 +24,18 @@
|
|||
// RUN: echo __asan_report_store16 >> %t.interface
|
||||
// RUN: echo __asan_report_load_n >> %t.interface
|
||||
// RUN: echo __asan_report_store_n >> %t.interface
|
||||
// RUN: echo __asan_report_load1_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_load2_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_load4_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_load8_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_load16_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_store1_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_store2_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_store4_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_store8_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_store16_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_load_n_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_store_n_noabort >> %t.interface
|
||||
// RUN: echo __asan_report_exp_load1 >> %t.interface
|
||||
// RUN: echo __asan_report_exp_load2 >> %t.interface
|
||||
// RUN: echo __asan_report_exp_load4 >> %t.interface
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
// Test recovery mode.
|
||||
//
|
||||
// RUN: %clang_asan -fsanitize-recover=address %s -o %t
|
||||
//
|
||||
// RUN: env not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: env ASAN_OPTIONS=$ASAN_OPTIONS:halt_on_error=true not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: env ASAN_OPTIONS=$ASAN_OPTIONS:halt_on_error=false %run %t 2>&1 | FileCheck %s --check-prefix CHECK-RECOVER
|
||||
|
||||
#include <string.h>
|
||||
|
||||
volatile int ten = 10;
|
||||
|
||||
int main() {
|
||||
char x[10];
|
||||
// CHECK: WRITE of size 11
|
||||
// CHECK-RECOVER: WRITE of size 11
|
||||
memset(x, 0, 11);
|
||||
// CHECK-NOT: READ of size 1
|
||||
// CHECK-RECOVER: READ of size 1
|
||||
volatile int res = x[ten];
|
||||
// CHECK-NOT: WRITE of size 1
|
||||
// CHECK-RECOVER: WRITE of size 1
|
||||
x[ten] = res + 3;
|
||||
// CHECK-NOT: READ of size 1
|
||||
// CHECK-RECOVER: READ of size 1
|
||||
res = x[ten];
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue