diff --git a/compiler-rt/lib/ubsan/ubsan_diag.cc b/compiler-rt/lib/ubsan/ubsan_diag.cc index 2fca8d1c2ae0..26f34376f50c 100644 --- a/compiler-rt/lib/ubsan/ubsan_diag.cc +++ b/compiler-rt/lib/ubsan/ubsan_diag.cc @@ -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(); } diff --git a/compiler-rt/lib/ubsan/ubsan_diag.h b/compiler-rt/lib/ubsan/ubsan_diag.h index 77aaa6764b30..b2fe735a2525 100644 --- a/compiler-rt/lib/ubsan/ubsan_diag.h +++ b/compiler-rt/lib/ubsan/ubsan_diag.h @@ -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(); }; diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.cc b/compiler-rt/lib/ubsan/ubsan_handlers.cc index 14b12b6a97f0..154cbc8939dd 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.cc +++ b/compiler-rt/lib/ubsan/ubsan_handlers.cc @@ -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 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); } diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.h b/compiler-rt/lib/ubsan/ubsan_handlers.h index 910198c51a4b..4a4da43ee6bc 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.h +++ b/compiler-rt/lib/ubsan/ubsan_handlers.h @@ -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; diff --git a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc index 4002e61ef92f..fa244c85d954 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc +++ b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc @@ -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); } diff --git a/compiler-rt/test/ubsan/TestCases/Misc/missing_return.cpp b/compiler-rt/test/ubsan/TestCases/Misc/missing_return.cpp index 20ede152bcde..6e35c5bcfe7b 100644 --- a/compiler-rt/test/ubsan/TestCases/Misc/missing_return.cpp +++ b/compiler-rt/test/ubsan/TestCases/Misc/missing_return.cpp @@ -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]] } diff --git a/compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp b/compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp index 71d82e0c33aa..7c117621d4f0 100644 --- a/compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp +++ b/compiler-rt/test/ubsan/TestCases/TypeCheck/misaligned.cpp @@ -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 @@ -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: {{^ \^}}