[UBSan] Add support for printing backtraces to all UBSan handlers
llvm-svn: 216289
This commit is contained in:
parent
93be0b24b8
commit
2ccbc621df
|
@ -21,7 +21,7 @@
|
|||
|
||||
using namespace __ubsan;
|
||||
|
||||
void __ubsan::MaybePrintStackTrace(uptr pc, uptr bp) {
|
||||
static void MaybePrintStackTrace(uptr pc, uptr bp) {
|
||||
// We assume that flags are already parsed: InitIfNecessary
|
||||
// will definitely be called when we print the first diagnostics message.
|
||||
if (!flags()->print_stacktrace)
|
||||
|
@ -301,15 +301,15 @@ Diag::~Diag() {
|
|||
NumRanges, Args);
|
||||
}
|
||||
|
||||
ScopedReport::ScopedReport(bool DieAfterReport)
|
||||
: DieAfterReport(DieAfterReport) {
|
||||
ScopedReport::ScopedReport(ReportOptions Opts) : Opts(Opts) {
|
||||
InitIfNecessary();
|
||||
CommonSanitizerReportMutex.Lock();
|
||||
}
|
||||
|
||||
ScopedReport::~ScopedReport() {
|
||||
MaybePrintStackTrace(Opts.pc, Opts.bp);
|
||||
CommonSanitizerReportMutex.Unlock();
|
||||
if (DieAfterReport)
|
||||
if (Opts.DieAfterReport)
|
||||
Die();
|
||||
}
|
||||
|
||||
|
|
|
@ -205,17 +205,27 @@ public:
|
|||
Diag &operator<<(const Range &R) { return AddRange(R); }
|
||||
};
|
||||
|
||||
void MaybePrintStackTrace(uptr pc, uptr bp);
|
||||
struct ReportOptions {
|
||||
/// If DieAfterReport is specified, UBSan will terminate the program after the
|
||||
/// report is printed.
|
||||
bool DieAfterReport;
|
||||
/// pc/bp are used to unwind the stack trace.
|
||||
uptr pc;
|
||||
uptr bp;
|
||||
};
|
||||
|
||||
#define GET_REPORT_OPTIONS(die_after_report) \
|
||||
GET_CALLER_PC_BP; \
|
||||
ReportOptions Opts = {die_after_report, pc, bp}
|
||||
|
||||
/// \brief Instantiate this class before printing diagnostics in the error
|
||||
/// report. This class ensures that reports from different threads and from
|
||||
/// different sanitizers won't be mixed. If DieAfterReport is specified, it
|
||||
/// will terminate the program in the destructor.
|
||||
/// different sanitizers won't be mixed.
|
||||
class ScopedReport {
|
||||
bool DieAfterReport;
|
||||
ReportOptions Opts;
|
||||
|
||||
public:
|
||||
ScopedReport(bool DieAfterReport);
|
||||
ScopedReport(ReportOptions Opts);
|
||||
~ScopedReport();
|
||||
};
|
||||
|
||||
|
|
|
@ -27,13 +27,13 @@ namespace __ubsan {
|
|||
}
|
||||
|
||||
static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
|
||||
Location FallbackLoc, bool Abort) {
|
||||
Location FallbackLoc, ReportOptions Opts) {
|
||||
Location Loc = Data->Loc.acquire();
|
||||
// Use the SourceLocation from Data to track deduplication, even if 'invalid'
|
||||
if (Loc.getSourceLocation().isDisabled())
|
||||
return;
|
||||
|
||||
ScopedReport R(Abort);
|
||||
ScopedReport R(Opts);
|
||||
|
||||
if (Data->Loc.isInvalid())
|
||||
Loc = FallbackLoc;
|
||||
|
@ -56,22 +56,25 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
|
|||
|
||||
void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data,
|
||||
ValueHandle Pointer) {
|
||||
handleTypeMismatchImpl(Data, Pointer, getCallerLocation(), false);
|
||||
GET_REPORT_OPTIONS(false);
|
||||
handleTypeMismatchImpl(Data, Pointer, getCallerLocation(), Opts);
|
||||
}
|
||||
void __ubsan::__ubsan_handle_type_mismatch_abort(TypeMismatchData *Data,
|
||||
ValueHandle Pointer) {
|
||||
handleTypeMismatchImpl(Data, Pointer, getCallerLocation(), true);
|
||||
GET_REPORT_OPTIONS(true);
|
||||
handleTypeMismatchImpl(Data, Pointer, getCallerLocation(), Opts);
|
||||
}
|
||||
|
||||
/// \brief Common diagnostic emission for various forms of integer overflow.
|
||||
template <typename T>
|
||||
static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS,
|
||||
const char *Operator, T RHS, bool Abort) {
|
||||
const char *Operator, T RHS,
|
||||
ReportOptions Opts) {
|
||||
SourceLocation Loc = Data->Loc.acquire();
|
||||
if (Loc.isDisabled())
|
||||
return;
|
||||
|
||||
ScopedReport R(Abort);
|
||||
ScopedReport R(Opts);
|
||||
|
||||
Diag(Loc, DL_Error, "%0 integer overflow: "
|
||||
"%1 %2 %3 cannot be represented in type %4")
|
||||
|
@ -82,7 +85,8 @@ static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS,
|
|||
#define UBSAN_OVERFLOW_HANDLER(handler_name, op, abort) \
|
||||
void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \
|
||||
ValueHandle RHS) { \
|
||||
handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), abort); \
|
||||
GET_REPORT_OPTIONS(abort); \
|
||||
handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \
|
||||
}
|
||||
|
||||
UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false)
|
||||
|
@ -93,12 +97,12 @@ UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "*", false)
|
|||
UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true)
|
||||
|
||||
static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal,
|
||||
bool Abort) {
|
||||
ReportOptions Opts) {
|
||||
SourceLocation Loc = Data->Loc.acquire();
|
||||
if (Loc.isDisabled())
|
||||
return;
|
||||
|
||||
ScopedReport R(Abort);
|
||||
ScopedReport R(Opts);
|
||||
|
||||
if (Data->Type.isSignedIntegerTy())
|
||||
Diag(Loc, DL_Error,
|
||||
|
@ -113,20 +117,22 @@ static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal,
|
|||
|
||||
void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,
|
||||
ValueHandle OldVal) {
|
||||
handleNegateOverflowImpl(Data, OldVal, false);
|
||||
GET_REPORT_OPTIONS(false);
|
||||
handleNegateOverflowImpl(Data, OldVal, Opts);
|
||||
}
|
||||
void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data,
|
||||
ValueHandle OldVal) {
|
||||
handleNegateOverflowImpl(Data, OldVal, true);
|
||||
GET_REPORT_OPTIONS(true);
|
||||
handleNegateOverflowImpl(Data, OldVal, Opts);
|
||||
}
|
||||
|
||||
static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS,
|
||||
ValueHandle RHS, bool Abort) {
|
||||
ValueHandle RHS, ReportOptions Opts) {
|
||||
SourceLocation Loc = Data->Loc.acquire();
|
||||
if (Loc.isDisabled())
|
||||
return;
|
||||
|
||||
ScopedReport R(Abort);
|
||||
ScopedReport R(Opts);
|
||||
|
||||
Value LHSVal(Data->Type, LHS);
|
||||
Value RHSVal(Data->Type, RHS);
|
||||
|
@ -140,22 +146,24 @@ static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS,
|
|||
|
||||
void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data,
|
||||
ValueHandle LHS, ValueHandle RHS) {
|
||||
handleDivremOverflowImpl(Data, LHS, RHS, false);
|
||||
GET_REPORT_OPTIONS(false);
|
||||
handleDivremOverflowImpl(Data, LHS, RHS, Opts);
|
||||
}
|
||||
void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data,
|
||||
ValueHandle LHS,
|
||||
ValueHandle RHS) {
|
||||
handleDivremOverflowImpl(Data, LHS, RHS, true);
|
||||
GET_REPORT_OPTIONS(true);
|
||||
handleDivremOverflowImpl(Data, LHS, RHS, Opts);
|
||||
}
|
||||
|
||||
static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data,
|
||||
ValueHandle LHS, ValueHandle RHS,
|
||||
bool Abort) {
|
||||
ReportOptions Opts) {
|
||||
SourceLocation Loc = Data->Loc.acquire();
|
||||
if (Loc.isDisabled())
|
||||
return;
|
||||
|
||||
ScopedReport R(Abort);
|
||||
ScopedReport R(Opts);
|
||||
|
||||
Value LHSVal(Data->LHSType, LHS);
|
||||
Value RHSVal(Data->RHSType, RHS);
|
||||
|
@ -176,22 +184,24 @@ static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data,
|
|||
void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,
|
||||
ValueHandle LHS,
|
||||
ValueHandle RHS) {
|
||||
handleShiftOutOfBoundsImpl(Data, LHS, RHS, false);
|
||||
GET_REPORT_OPTIONS(false);
|
||||
handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);
|
||||
}
|
||||
void __ubsan::__ubsan_handle_shift_out_of_bounds_abort(
|
||||
ShiftOutOfBoundsData *Data,
|
||||
ValueHandle LHS,
|
||||
ValueHandle RHS) {
|
||||
handleShiftOutOfBoundsImpl(Data, LHS, RHS, true);
|
||||
GET_REPORT_OPTIONS(true);
|
||||
handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);
|
||||
}
|
||||
|
||||
static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,
|
||||
bool Abort) {
|
||||
ReportOptions Opts) {
|
||||
SourceLocation Loc = Data->Loc.acquire();
|
||||
if (Loc.isDisabled())
|
||||
return;
|
||||
|
||||
ScopedReport R(Abort);
|
||||
ScopedReport R(Opts);
|
||||
|
||||
Value IndexVal(Data->IndexType, Index);
|
||||
Diag(Loc, DL_Error, "index %0 out of bounds for type %1")
|
||||
|
@ -200,32 +210,36 @@ static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,
|
|||
|
||||
void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data,
|
||||
ValueHandle Index) {
|
||||
handleOutOfBoundsImpl(Data, Index, false);
|
||||
GET_REPORT_OPTIONS(false);
|
||||
handleOutOfBoundsImpl(Data, Index, Opts);
|
||||
}
|
||||
void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data,
|
||||
ValueHandle Index) {
|
||||
handleOutOfBoundsImpl(Data, Index, true);
|
||||
GET_REPORT_OPTIONS(true);
|
||||
handleOutOfBoundsImpl(Data, Index, Opts);
|
||||
}
|
||||
|
||||
void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {
|
||||
ScopedReport R(true);
|
||||
GET_REPORT_OPTIONS(true);
|
||||
ScopedReport R(Opts);
|
||||
Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call");
|
||||
}
|
||||
|
||||
void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {
|
||||
ScopedReport R(true);
|
||||
GET_REPORT_OPTIONS(true);
|
||||
ScopedReport R(Opts);
|
||||
Diag(Data->Loc, DL_Error,
|
||||
"execution reached the end of a value-returning function "
|
||||
"without returning a value");
|
||||
}
|
||||
|
||||
static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,
|
||||
bool Abort) {
|
||||
ReportOptions Opts) {
|
||||
SourceLocation Loc = Data->Loc.acquire();
|
||||
if (Loc.isDisabled())
|
||||
return;
|
||||
|
||||
ScopedReport R(Abort);
|
||||
ScopedReport R(Opts);
|
||||
|
||||
Diag(Loc, DL_Error, "variable length array bound evaluates to "
|
||||
"non-positive value %0")
|
||||
|
@ -234,18 +248,19 @@ static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,
|
|||
|
||||
void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data,
|
||||
ValueHandle Bound) {
|
||||
handleVLABoundNotPositive(Data, Bound, false);
|
||||
GET_REPORT_OPTIONS(false);
|
||||
handleVLABoundNotPositive(Data, Bound, Opts);
|
||||
}
|
||||
void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data,
|
||||
ValueHandle Bound) {
|
||||
handleVLABoundNotPositive(Data, Bound, true);
|
||||
GET_REPORT_OPTIONS(true);
|
||||
handleVLABoundNotPositive(Data, Bound, Opts);
|
||||
}
|
||||
|
||||
|
||||
static void handleFloatCastOverflow(FloatCastOverflowData *Data, ValueHandle From,
|
||||
bool Abort) {
|
||||
static void handleFloatCastOverflow(FloatCastOverflowData *Data,
|
||||
ValueHandle From, ReportOptions Opts) {
|
||||
// TODO: Add deduplication once a SourceLocation is generated for this check.
|
||||
ScopedReport R(Abort);
|
||||
ScopedReport R(Opts);
|
||||
|
||||
Diag(getCallerLocation(), DL_Error,
|
||||
"value %0 is outside the range of representable values of type %2")
|
||||
|
@ -254,21 +269,23 @@ static void handleFloatCastOverflow(FloatCastOverflowData *Data, ValueHandle Fro
|
|||
|
||||
void __ubsan::__ubsan_handle_float_cast_overflow(FloatCastOverflowData *Data,
|
||||
ValueHandle From) {
|
||||
handleFloatCastOverflow(Data, From, false);
|
||||
GET_REPORT_OPTIONS(false);
|
||||
handleFloatCastOverflow(Data, From, Opts);
|
||||
}
|
||||
void
|
||||
__ubsan::__ubsan_handle_float_cast_overflow_abort(FloatCastOverflowData *Data,
|
||||
ValueHandle From) {
|
||||
handleFloatCastOverflow(Data, From, true);
|
||||
GET_REPORT_OPTIONS(true);
|
||||
handleFloatCastOverflow(Data, From, Opts);
|
||||
}
|
||||
|
||||
static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,
|
||||
bool Abort) {
|
||||
ReportOptions Opts) {
|
||||
SourceLocation Loc = Data->Loc.acquire();
|
||||
if (Loc.isDisabled())
|
||||
return;
|
||||
|
||||
ScopedReport R(Abort);
|
||||
ScopedReport R(Opts);
|
||||
|
||||
Diag(Loc, DL_Error,
|
||||
"load of value %0, which is not a valid value for type %1")
|
||||
|
@ -277,20 +294,23 @@ static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,
|
|||
|
||||
void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,
|
||||
ValueHandle Val) {
|
||||
handleLoadInvalidValue(Data, Val, false);
|
||||
GET_REPORT_OPTIONS(false);
|
||||
handleLoadInvalidValue(Data, Val, Opts);
|
||||
}
|
||||
void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data,
|
||||
ValueHandle Val) {
|
||||
handleLoadInvalidValue(Data, Val, true);
|
||||
GET_REPORT_OPTIONS(true);
|
||||
handleLoadInvalidValue(Data, Val, Opts);
|
||||
}
|
||||
|
||||
static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
|
||||
ValueHandle Function, bool Abort) {
|
||||
ValueHandle Function,
|
||||
ReportOptions Opts) {
|
||||
const char *FName = "(unknown)";
|
||||
|
||||
Location Loc = getFunctionLocation(Function, &FName);
|
||||
|
||||
ScopedReport R(Abort);
|
||||
ScopedReport R(Opts);
|
||||
|
||||
Diag(Data->Loc, DL_Error,
|
||||
"call to function %0 through pointer to incorrect function type %1")
|
||||
|
@ -301,29 +321,33 @@ static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
|
|||
void
|
||||
__ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data,
|
||||
ValueHandle Function) {
|
||||
handleFunctionTypeMismatch(Data, Function, false);
|
||||
GET_REPORT_OPTIONS(false);
|
||||
handleFunctionTypeMismatch(Data, Function, Opts);
|
||||
}
|
||||
|
||||
void __ubsan::__ubsan_handle_function_type_mismatch_abort(
|
||||
FunctionTypeMismatchData *Data, ValueHandle Function) {
|
||||
handleFunctionTypeMismatch(Data, Function, true);
|
||||
GET_REPORT_OPTIONS(true);
|
||||
handleFunctionTypeMismatch(Data, Function, Opts);
|
||||
}
|
||||
|
||||
static void handleNonnullReturn(NonNullReturnData *Data, bool Abort) {
|
||||
static void handleNonnullReturn(NonNullReturnData *Data, ReportOptions Opts) {
|
||||
SourceLocation Loc = Data->Loc.acquire();
|
||||
if (Loc.isDisabled())
|
||||
return;
|
||||
|
||||
ScopedReport R(Abort);
|
||||
ScopedReport R(Opts);
|
||||
|
||||
Diag(Loc, DL_Error, "null pointer returned from function declared to never "
|
||||
"return null");
|
||||
}
|
||||
|
||||
void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) {
|
||||
handleNonnullReturn(Data, false);
|
||||
GET_REPORT_OPTIONS(false);
|
||||
handleNonnullReturn(Data, Opts);
|
||||
}
|
||||
|
||||
void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) {
|
||||
handleNonnullReturn(Data, true);
|
||||
GET_REPORT_OPTIONS(true);
|
||||
handleNonnullReturn(Data, Opts);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,10 @@ struct TypeMismatchData {
|
|||
unsigned char TypeCheckKind;
|
||||
};
|
||||
|
||||
#define UNRECOVERABLE(checkname, ...) \
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE \
|
||||
void __ubsan_handle_ ## checkname( __VA_ARGS__ );
|
||||
|
||||
#define RECOVERABLE(checkname, ...) \
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE \
|
||||
void __ubsan_handle_ ## checkname( __VA_ARGS__ ); \
|
||||
|
@ -81,11 +85,9 @@ struct UnreachableData {
|
|||
};
|
||||
|
||||
/// \brief Handle a __builtin_unreachable which is reached.
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __ubsan_handle_builtin_unreachable(UnreachableData *Data);
|
||||
UNRECOVERABLE(builtin_unreachable, UnreachableData *Data)
|
||||
/// \brief Handle reaching the end of a value-returning function.
|
||||
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __ubsan_handle_missing_return(UnreachableData *Data);
|
||||
UNRECOVERABLE(missing_return, UnreachableData *Data)
|
||||
|
||||
struct VLABoundData {
|
||||
SourceLocation Loc;
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace __ubsan {
|
|||
|
||||
static void HandleDynamicTypeCacheMiss(
|
||||
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash,
|
||||
bool Abort, uptr pc, uptr bp) {
|
||||
ReportOptions Opts) {
|
||||
if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash))
|
||||
// Just a cache miss. The type matches after all.
|
||||
return;
|
||||
|
@ -44,7 +44,7 @@ static void HandleDynamicTypeCacheMiss(
|
|||
if (Loc.isDisabled())
|
||||
return;
|
||||
|
||||
ScopedReport R(Abort);
|
||||
ScopedReport R(Opts);
|
||||
|
||||
Diag(Loc, DL_Error,
|
||||
"%0 address %1 which does not point to an object of type %2")
|
||||
|
@ -68,17 +68,15 @@ static void HandleDynamicTypeCacheMiss(
|
|||
<< MangledName(DTI.getSubobjectTypeName())
|
||||
<< Range(Pointer, Pointer + sizeof(uptr),
|
||||
"vptr for %2 base class of %1");
|
||||
|
||||
MaybePrintStackTrace(pc, bp);
|
||||
}
|
||||
|
||||
void __ubsan::__ubsan_handle_dynamic_type_cache_miss(
|
||||
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
|
||||
GET_CALLER_PC_BP;
|
||||
HandleDynamicTypeCacheMiss(Data, Pointer, Hash, false, pc, bp);
|
||||
GET_REPORT_OPTIONS(false);
|
||||
HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts);
|
||||
}
|
||||
void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort(
|
||||
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
|
||||
GET_CALLER_PC_BP;
|
||||
HandleDynamicTypeCacheMiss(Data, Pointer, Hash, true, pc, bp);
|
||||
GET_REPORT_OPTIONS(true);
|
||||
HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
// RUN: %clangxx -fsanitize=return %s -O3 -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx -fsanitize=return -g %s -O3 -o %t
|
||||
// RUN: not %run %t 2>&1 | FileCheck %s
|
||||
// RUN: UBSAN_OPTIONS=print_stacktrace=1 not %run %t 2>&1 | FileCheck %s --check-prefix=STACKTRACE
|
||||
|
||||
// CHECK: missing_return.cpp:4:5: runtime error: execution reached the end of a value-returning function without returning a value
|
||||
// CHECK: missing_return.cpp:[[@LINE+1]]:5: runtime error: execution reached the end of a value-returning function without returning a value
|
||||
int f() {
|
||||
// STACKTRACE: #0 {{.*}} in f(){{.*}}missing_return.cpp:[[@LINE-1]]
|
||||
}
|
||||
|
||||
int main(int, char **argv) {
|
||||
return f();
|
||||
// STACKTRACE: #1 {{.*}} in main{{.*}}missing_return.cpp:[[@LINE-1]]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clangxx -fsanitize=alignment %s -O3 -o %t
|
||||
// RUN: %clangxx -fsanitize=alignment -g %s -O3 -o %t
|
||||
// RUN: %run %t l0 && %run %t s0 && %run %t r0 && %run %t m0 && %run %t f0 && %run %t n0
|
||||
// RUN: %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --strict-whitespace
|
||||
// RUN: %run %t s1 2>&1 | FileCheck %s --check-prefix=CHECK-STORE
|
||||
|
@ -6,6 +6,7 @@
|
|||
// RUN: %run %t m1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER
|
||||
// RUN: %run %t f1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN
|
||||
// RUN: %run %t n1 2>&1 | FileCheck %s --check-prefix=CHECK-NEW
|
||||
// RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --check-prefix=CHECK-STACK-LOAD
|
||||
|
||||
#include <new>
|
||||
|
||||
|
@ -31,6 +32,7 @@ int main(int, char **argv) {
|
|||
// CHECK-LOAD-NEXT: {{^ 00 00 00 01 02 03 04 05}}
|
||||
// CHECK-LOAD-NEXT: {{^ \^}}
|
||||
return *p && 0;
|
||||
// CHECK-STACK-LOAD: #0 {{.*}} in main{{.*}}misaligned.cpp
|
||||
|
||||
case 's':
|
||||
// CHECK-STORE: misaligned.cpp:[[@LINE+4]]:5: runtime error: store to misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment
|
||||
|
@ -63,8 +65,7 @@ int main(int, char **argv) {
|
|||
return s->f() && 0;
|
||||
|
||||
case 'n':
|
||||
// FIXME: Provide a better source location here.
|
||||
// CHECK-NEW: misaligned{{.*}}+0x{{[0-9a-f]*}}): runtime error: constructor call on misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment
|
||||
// CHECK-NEW: misaligned.cpp:[[@LINE+4]]:5: runtime error: constructor call on misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment
|
||||
// CHECK-NEW-NEXT: [[PTR]]: note: pointer points here
|
||||
// CHECK-NEW-NEXT: {{^ 00 00 00 01 02 03 04 05}}
|
||||
// CHECK-NEW-NEXT: {{^ \^}}
|
||||
|
|
Loading…
Reference in New Issue