13cab2bb3Spatrick //===-- ubsan_handlers.cpp ------------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // Error logging entry points for the UBSan runtime.
103cab2bb3Spatrick //
113cab2bb3Spatrick //===----------------------------------------------------------------------===//
123cab2bb3Spatrick
133cab2bb3Spatrick #include "ubsan_platform.h"
143cab2bb3Spatrick #if CAN_SANITIZE_UB
153cab2bb3Spatrick #include "ubsan_handlers.h"
163cab2bb3Spatrick #include "ubsan_diag.h"
173cab2bb3Spatrick #include "ubsan_flags.h"
183cab2bb3Spatrick #include "ubsan_monitor.h"
191f9cb04fSpatrick #include "ubsan_value.h"
203cab2bb3Spatrick
213cab2bb3Spatrick #include "sanitizer_common/sanitizer_common.h"
223cab2bb3Spatrick
233cab2bb3Spatrick using namespace __sanitizer;
243cab2bb3Spatrick using namespace __ubsan;
253cab2bb3Spatrick
263cab2bb3Spatrick namespace __ubsan {
ignoreReport(SourceLocation SLoc,ReportOptions Opts,ErrorType ET)273cab2bb3Spatrick bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) {
283cab2bb3Spatrick // We are not allowed to skip error report: if we are in unrecoverable
293cab2bb3Spatrick // handler, we have to terminate the program right now, and therefore
303cab2bb3Spatrick // have to print some diagnostic.
313cab2bb3Spatrick //
323cab2bb3Spatrick // Even if source location is disabled, it doesn't mean that we have
333cab2bb3Spatrick // already report an error to the user: some concurrently running
343cab2bb3Spatrick // thread could have acquired it, but not yet printed the report.
353cab2bb3Spatrick if (Opts.FromUnrecoverableHandler)
363cab2bb3Spatrick return false;
373cab2bb3Spatrick return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc, SLoc.getFilename());
383cab2bb3Spatrick }
393cab2bb3Spatrick
401f9cb04fSpatrick /// Situations in which we might emit a check for the suitability of a
411f9cb04fSpatrick /// pointer or glvalue. Needs to be kept in sync with CodeGenFunction.h in
421f9cb04fSpatrick /// clang.
431f9cb04fSpatrick enum TypeCheckKind {
441f9cb04fSpatrick /// Checking the operand of a load. Must be suitably sized and aligned.
451f9cb04fSpatrick TCK_Load,
461f9cb04fSpatrick /// Checking the destination of a store. Must be suitably sized and aligned.
471f9cb04fSpatrick TCK_Store,
481f9cb04fSpatrick /// Checking the bound value in a reference binding. Must be suitably sized
491f9cb04fSpatrick /// and aligned, but is not required to refer to an object (until the
501f9cb04fSpatrick /// reference is used), per core issue 453.
511f9cb04fSpatrick TCK_ReferenceBinding,
521f9cb04fSpatrick /// Checking the object expression in a non-static data member access. Must
531f9cb04fSpatrick /// be an object within its lifetime.
541f9cb04fSpatrick TCK_MemberAccess,
551f9cb04fSpatrick /// Checking the 'this' pointer for a call to a non-static member function.
561f9cb04fSpatrick /// Must be an object within its lifetime.
571f9cb04fSpatrick TCK_MemberCall,
581f9cb04fSpatrick /// Checking the 'this' pointer for a constructor call.
591f9cb04fSpatrick TCK_ConstructorCall,
601f9cb04fSpatrick /// Checking the operand of a static_cast to a derived pointer type. Must be
611f9cb04fSpatrick /// null or an object within its lifetime.
621f9cb04fSpatrick TCK_DowncastPointer,
631f9cb04fSpatrick /// Checking the operand of a static_cast to a derived reference type. Must
641f9cb04fSpatrick /// be an object within its lifetime.
651f9cb04fSpatrick TCK_DowncastReference,
661f9cb04fSpatrick /// Checking the operand of a cast to a base object. Must be suitably sized
671f9cb04fSpatrick /// and aligned.
681f9cb04fSpatrick TCK_Upcast,
691f9cb04fSpatrick /// Checking the operand of a cast to a virtual base object. Must be an
701f9cb04fSpatrick /// object within its lifetime.
711f9cb04fSpatrick TCK_UpcastToVirtualBase,
721f9cb04fSpatrick /// Checking the value assigned to a _Nonnull pointer. Must not be null.
731f9cb04fSpatrick TCK_NonnullAssign,
741f9cb04fSpatrick /// Checking the operand of a dynamic_cast or a typeid expression. Must be
751f9cb04fSpatrick /// null or an object within its lifetime.
761f9cb04fSpatrick TCK_DynamicOperation
771f9cb04fSpatrick };
781f9cb04fSpatrick
79*810390e3Srobert extern const char *const TypeCheckKinds[] = {
803cab2bb3Spatrick "load of", "store to", "reference binding to", "member access within",
813cab2bb3Spatrick "member call on", "constructor call on", "downcast of", "downcast of",
823cab2bb3Spatrick "upcast of", "cast to virtual base of", "_Nonnull binding to",
833cab2bb3Spatrick "dynamic operation on"};
843cab2bb3Spatrick }
853cab2bb3Spatrick
handleTypeMismatchImpl(TypeMismatchData * Data,ValueHandle Pointer,ReportOptions Opts)863cab2bb3Spatrick static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
873cab2bb3Spatrick ReportOptions Opts) {
883cab2bb3Spatrick Location Loc = Data->Loc.acquire();
893cab2bb3Spatrick
903cab2bb3Spatrick uptr Alignment = (uptr)1 << Data->LogAlignment;
913cab2bb3Spatrick ErrorType ET;
923cab2bb3Spatrick if (!Pointer)
931f9cb04fSpatrick ET = (Data->TypeCheckKind == TCK_NonnullAssign)
941f9cb04fSpatrick ? ErrorType::NullPointerUseWithNullability
951f9cb04fSpatrick : ErrorType::NullPointerUse;
963cab2bb3Spatrick else if (Pointer & (Alignment - 1))
973cab2bb3Spatrick ET = ErrorType::MisalignedPointerUse;
983cab2bb3Spatrick else
993cab2bb3Spatrick ET = ErrorType::InsufficientObjectSize;
1003cab2bb3Spatrick
1013cab2bb3Spatrick // Use the SourceLocation from Data to track deduplication, even if it's
1023cab2bb3Spatrick // invalid.
1033cab2bb3Spatrick if (ignoreReport(Loc.getSourceLocation(), Opts, ET))
1043cab2bb3Spatrick return;
1053cab2bb3Spatrick
1063cab2bb3Spatrick SymbolizedStackHolder FallbackLoc;
1073cab2bb3Spatrick if (Data->Loc.isInvalid()) {
1083cab2bb3Spatrick FallbackLoc.reset(getCallerLocation(Opts.pc));
1093cab2bb3Spatrick Loc = FallbackLoc;
1103cab2bb3Spatrick }
1113cab2bb3Spatrick
1123cab2bb3Spatrick ScopedReport R(Opts, Loc, ET);
1133cab2bb3Spatrick
1143cab2bb3Spatrick switch (ET) {
1153cab2bb3Spatrick case ErrorType::NullPointerUse:
1161f9cb04fSpatrick case ErrorType::NullPointerUseWithNullability:
1173cab2bb3Spatrick Diag(Loc, DL_Error, ET, "%0 null pointer of type %1")
1183cab2bb3Spatrick << TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
1193cab2bb3Spatrick break;
1203cab2bb3Spatrick case ErrorType::MisalignedPointerUse:
1213cab2bb3Spatrick Diag(Loc, DL_Error, ET, "%0 misaligned address %1 for type %3, "
1223cab2bb3Spatrick "which requires %2 byte alignment")
1233cab2bb3Spatrick << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Alignment
1243cab2bb3Spatrick << Data->Type;
1253cab2bb3Spatrick break;
1263cab2bb3Spatrick case ErrorType::InsufficientObjectSize:
1273cab2bb3Spatrick Diag(Loc, DL_Error, ET, "%0 address %1 with insufficient space "
1283cab2bb3Spatrick "for an object of type %2")
1293cab2bb3Spatrick << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Data->Type;
1303cab2bb3Spatrick break;
1313cab2bb3Spatrick default:
1323cab2bb3Spatrick UNREACHABLE("unexpected error type!");
1333cab2bb3Spatrick }
1343cab2bb3Spatrick
1353cab2bb3Spatrick if (Pointer)
1363cab2bb3Spatrick Diag(Pointer, DL_Note, ET, "pointer points here");
1373cab2bb3Spatrick }
1383cab2bb3Spatrick
__ubsan_handle_type_mismatch_v1(TypeMismatchData * Data,ValueHandle Pointer)1393cab2bb3Spatrick void __ubsan::__ubsan_handle_type_mismatch_v1(TypeMismatchData *Data,
1403cab2bb3Spatrick ValueHandle Pointer) {
1413cab2bb3Spatrick GET_REPORT_OPTIONS(false);
1423cab2bb3Spatrick handleTypeMismatchImpl(Data, Pointer, Opts);
1433cab2bb3Spatrick }
__ubsan_handle_type_mismatch_v1_abort(TypeMismatchData * Data,ValueHandle Pointer)1443cab2bb3Spatrick void __ubsan::__ubsan_handle_type_mismatch_v1_abort(TypeMismatchData *Data,
1453cab2bb3Spatrick ValueHandle Pointer) {
1463cab2bb3Spatrick GET_REPORT_OPTIONS(true);
1473cab2bb3Spatrick handleTypeMismatchImpl(Data, Pointer, Opts);
1483cab2bb3Spatrick Die();
1493cab2bb3Spatrick }
1503cab2bb3Spatrick
handleAlignmentAssumptionImpl(AlignmentAssumptionData * Data,ValueHandle Pointer,ValueHandle Alignment,ValueHandle Offset,ReportOptions Opts)1513cab2bb3Spatrick static void handleAlignmentAssumptionImpl(AlignmentAssumptionData *Data,
1523cab2bb3Spatrick ValueHandle Pointer,
1533cab2bb3Spatrick ValueHandle Alignment,
1543cab2bb3Spatrick ValueHandle Offset,
1553cab2bb3Spatrick ReportOptions Opts) {
1563cab2bb3Spatrick Location Loc = Data->Loc.acquire();
1573cab2bb3Spatrick SourceLocation AssumptionLoc = Data->AssumptionLoc.acquire();
1583cab2bb3Spatrick
1593cab2bb3Spatrick ErrorType ET = ErrorType::AlignmentAssumption;
1603cab2bb3Spatrick
1613cab2bb3Spatrick if (ignoreReport(Loc.getSourceLocation(), Opts, ET))
1623cab2bb3Spatrick return;
1633cab2bb3Spatrick
1643cab2bb3Spatrick ScopedReport R(Opts, Loc, ET);
1653cab2bb3Spatrick
1663cab2bb3Spatrick uptr RealPointer = Pointer - Offset;
1673cab2bb3Spatrick uptr LSB = LeastSignificantSetBitIndex(RealPointer);
1683cab2bb3Spatrick uptr ActualAlignment = uptr(1) << LSB;
1693cab2bb3Spatrick
1703cab2bb3Spatrick uptr Mask = Alignment - 1;
1713cab2bb3Spatrick uptr MisAlignmentOffset = RealPointer & Mask;
1723cab2bb3Spatrick
1733cab2bb3Spatrick if (!Offset) {
1743cab2bb3Spatrick Diag(Loc, DL_Error, ET,
1753cab2bb3Spatrick "assumption of %0 byte alignment for pointer of type %1 failed")
1763cab2bb3Spatrick << Alignment << Data->Type;
1773cab2bb3Spatrick } else {
1783cab2bb3Spatrick Diag(Loc, DL_Error, ET,
1793cab2bb3Spatrick "assumption of %0 byte alignment (with offset of %1 byte) for pointer "
1803cab2bb3Spatrick "of type %2 failed")
1813cab2bb3Spatrick << Alignment << Offset << Data->Type;
1823cab2bb3Spatrick }
1833cab2bb3Spatrick
1843cab2bb3Spatrick if (!AssumptionLoc.isInvalid())
1853cab2bb3Spatrick Diag(AssumptionLoc, DL_Note, ET, "alignment assumption was specified here");
1863cab2bb3Spatrick
1873cab2bb3Spatrick Diag(RealPointer, DL_Note, ET,
1883cab2bb3Spatrick "%0address is %1 aligned, misalignment offset is %2 bytes")
1893cab2bb3Spatrick << (Offset ? "offset " : "") << ActualAlignment << MisAlignmentOffset;
1903cab2bb3Spatrick }
1913cab2bb3Spatrick
__ubsan_handle_alignment_assumption(AlignmentAssumptionData * Data,ValueHandle Pointer,ValueHandle Alignment,ValueHandle Offset)1923cab2bb3Spatrick void __ubsan::__ubsan_handle_alignment_assumption(AlignmentAssumptionData *Data,
1933cab2bb3Spatrick ValueHandle Pointer,
1943cab2bb3Spatrick ValueHandle Alignment,
1953cab2bb3Spatrick ValueHandle Offset) {
1963cab2bb3Spatrick GET_REPORT_OPTIONS(false);
1973cab2bb3Spatrick handleAlignmentAssumptionImpl(Data, Pointer, Alignment, Offset, Opts);
1983cab2bb3Spatrick }
__ubsan_handle_alignment_assumption_abort(AlignmentAssumptionData * Data,ValueHandle Pointer,ValueHandle Alignment,ValueHandle Offset)1993cab2bb3Spatrick void __ubsan::__ubsan_handle_alignment_assumption_abort(
2003cab2bb3Spatrick AlignmentAssumptionData *Data, ValueHandle Pointer, ValueHandle Alignment,
2013cab2bb3Spatrick ValueHandle Offset) {
2023cab2bb3Spatrick GET_REPORT_OPTIONS(true);
2033cab2bb3Spatrick handleAlignmentAssumptionImpl(Data, Pointer, Alignment, Offset, Opts);
2043cab2bb3Spatrick Die();
2053cab2bb3Spatrick }
2063cab2bb3Spatrick
2073cab2bb3Spatrick /// \brief Common diagnostic emission for various forms of integer overflow.
2083cab2bb3Spatrick template <typename T>
handleIntegerOverflowImpl(OverflowData * Data,ValueHandle LHS,const char * Operator,T RHS,ReportOptions Opts)2093cab2bb3Spatrick static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS,
2103cab2bb3Spatrick const char *Operator, T RHS,
2113cab2bb3Spatrick ReportOptions Opts) {
2123cab2bb3Spatrick SourceLocation Loc = Data->Loc.acquire();
2133cab2bb3Spatrick bool IsSigned = Data->Type.isSignedIntegerTy();
2143cab2bb3Spatrick ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow
2153cab2bb3Spatrick : ErrorType::UnsignedIntegerOverflow;
2163cab2bb3Spatrick
2173cab2bb3Spatrick if (ignoreReport(Loc, Opts, ET))
2183cab2bb3Spatrick return;
2193cab2bb3Spatrick
2203cab2bb3Spatrick // If this is an unsigned overflow in non-fatal mode, potentially ignore it.
2213cab2bb3Spatrick if (!IsSigned && !Opts.FromUnrecoverableHandler &&
2223cab2bb3Spatrick flags()->silence_unsigned_overflow)
2233cab2bb3Spatrick return;
2243cab2bb3Spatrick
2253cab2bb3Spatrick ScopedReport R(Opts, Loc, ET);
2263cab2bb3Spatrick
2273cab2bb3Spatrick Diag(Loc, DL_Error, ET, "%0 integer overflow: "
2283cab2bb3Spatrick "%1 %2 %3 cannot be represented in type %4")
2293cab2bb3Spatrick << (IsSigned ? "signed" : "unsigned") << Value(Data->Type, LHS)
2303cab2bb3Spatrick << Operator << RHS << Data->Type;
2313cab2bb3Spatrick }
2323cab2bb3Spatrick
2333cab2bb3Spatrick #define UBSAN_OVERFLOW_HANDLER(handler_name, op, unrecoverable) \
2343cab2bb3Spatrick void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \
2353cab2bb3Spatrick ValueHandle RHS) { \
2363cab2bb3Spatrick GET_REPORT_OPTIONS(unrecoverable); \
2373cab2bb3Spatrick handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \
2383cab2bb3Spatrick if (unrecoverable) \
2393cab2bb3Spatrick Die(); \
2403cab2bb3Spatrick }
2413cab2bb3Spatrick
2423cab2bb3Spatrick UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false)
2433cab2bb3Spatrick UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow_abort, "+", true)
2443cab2bb3Spatrick UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "-", false)
2453cab2bb3Spatrick UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow_abort, "-", true)
2463cab2bb3Spatrick UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "*", false)
2473cab2bb3Spatrick UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true)
2483cab2bb3Spatrick
handleNegateOverflowImpl(OverflowData * Data,ValueHandle OldVal,ReportOptions Opts)2493cab2bb3Spatrick static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal,
2503cab2bb3Spatrick ReportOptions Opts) {
2513cab2bb3Spatrick SourceLocation Loc = Data->Loc.acquire();
2523cab2bb3Spatrick bool IsSigned = Data->Type.isSignedIntegerTy();
2533cab2bb3Spatrick ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow
2543cab2bb3Spatrick : ErrorType::UnsignedIntegerOverflow;
2553cab2bb3Spatrick
2563cab2bb3Spatrick if (ignoreReport(Loc, Opts, ET))
2573cab2bb3Spatrick return;
2583cab2bb3Spatrick
2593cab2bb3Spatrick if (!IsSigned && flags()->silence_unsigned_overflow)
2603cab2bb3Spatrick return;
2613cab2bb3Spatrick
2623cab2bb3Spatrick ScopedReport R(Opts, Loc, ET);
2633cab2bb3Spatrick
2643cab2bb3Spatrick if (IsSigned)
2653cab2bb3Spatrick Diag(Loc, DL_Error, ET,
2663cab2bb3Spatrick "negation of %0 cannot be represented in type %1; "
2673cab2bb3Spatrick "cast to an unsigned type to negate this value to itself")
2683cab2bb3Spatrick << Value(Data->Type, OldVal) << Data->Type;
2693cab2bb3Spatrick else
2703cab2bb3Spatrick Diag(Loc, DL_Error, ET, "negation of %0 cannot be represented in type %1")
2713cab2bb3Spatrick << Value(Data->Type, OldVal) << Data->Type;
2723cab2bb3Spatrick }
2733cab2bb3Spatrick
__ubsan_handle_negate_overflow(OverflowData * Data,ValueHandle OldVal)2743cab2bb3Spatrick void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,
2753cab2bb3Spatrick ValueHandle OldVal) {
2763cab2bb3Spatrick GET_REPORT_OPTIONS(false);
2773cab2bb3Spatrick handleNegateOverflowImpl(Data, OldVal, Opts);
2783cab2bb3Spatrick }
__ubsan_handle_negate_overflow_abort(OverflowData * Data,ValueHandle OldVal)2793cab2bb3Spatrick void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data,
2803cab2bb3Spatrick ValueHandle OldVal) {
2813cab2bb3Spatrick GET_REPORT_OPTIONS(true);
2823cab2bb3Spatrick handleNegateOverflowImpl(Data, OldVal, Opts);
2833cab2bb3Spatrick Die();
2843cab2bb3Spatrick }
2853cab2bb3Spatrick
handleDivremOverflowImpl(OverflowData * Data,ValueHandle LHS,ValueHandle RHS,ReportOptions Opts)2863cab2bb3Spatrick static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS,
2873cab2bb3Spatrick ValueHandle RHS, ReportOptions Opts) {
2883cab2bb3Spatrick SourceLocation Loc = Data->Loc.acquire();
2893cab2bb3Spatrick Value LHSVal(Data->Type, LHS);
2903cab2bb3Spatrick Value RHSVal(Data->Type, RHS);
2913cab2bb3Spatrick
2923cab2bb3Spatrick ErrorType ET;
2933cab2bb3Spatrick if (RHSVal.isMinusOne())
2943cab2bb3Spatrick ET = ErrorType::SignedIntegerOverflow;
2953cab2bb3Spatrick else if (Data->Type.isIntegerTy())
2963cab2bb3Spatrick ET = ErrorType::IntegerDivideByZero;
2973cab2bb3Spatrick else
2983cab2bb3Spatrick ET = ErrorType::FloatDivideByZero;
2993cab2bb3Spatrick
3003cab2bb3Spatrick if (ignoreReport(Loc, Opts, ET))
3013cab2bb3Spatrick return;
3023cab2bb3Spatrick
3033cab2bb3Spatrick ScopedReport R(Opts, Loc, ET);
3043cab2bb3Spatrick
3053cab2bb3Spatrick switch (ET) {
3063cab2bb3Spatrick case ErrorType::SignedIntegerOverflow:
3073cab2bb3Spatrick Diag(Loc, DL_Error, ET,
3083cab2bb3Spatrick "division of %0 by -1 cannot be represented in type %1")
3093cab2bb3Spatrick << LHSVal << Data->Type;
3103cab2bb3Spatrick break;
3113cab2bb3Spatrick default:
3123cab2bb3Spatrick Diag(Loc, DL_Error, ET, "division by zero");
3133cab2bb3Spatrick break;
3143cab2bb3Spatrick }
3153cab2bb3Spatrick }
3163cab2bb3Spatrick
__ubsan_handle_divrem_overflow(OverflowData * Data,ValueHandle LHS,ValueHandle RHS)3173cab2bb3Spatrick void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data,
3183cab2bb3Spatrick ValueHandle LHS, ValueHandle RHS) {
3193cab2bb3Spatrick GET_REPORT_OPTIONS(false);
3203cab2bb3Spatrick handleDivremOverflowImpl(Data, LHS, RHS, Opts);
3213cab2bb3Spatrick }
__ubsan_handle_divrem_overflow_abort(OverflowData * Data,ValueHandle LHS,ValueHandle RHS)3223cab2bb3Spatrick void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data,
3233cab2bb3Spatrick ValueHandle LHS,
3243cab2bb3Spatrick ValueHandle RHS) {
3253cab2bb3Spatrick GET_REPORT_OPTIONS(true);
3263cab2bb3Spatrick handleDivremOverflowImpl(Data, LHS, RHS, Opts);
3273cab2bb3Spatrick Die();
3283cab2bb3Spatrick }
3293cab2bb3Spatrick
handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData * Data,ValueHandle LHS,ValueHandle RHS,ReportOptions Opts)3303cab2bb3Spatrick static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data,
3313cab2bb3Spatrick ValueHandle LHS, ValueHandle RHS,
3323cab2bb3Spatrick ReportOptions Opts) {
3333cab2bb3Spatrick SourceLocation Loc = Data->Loc.acquire();
3343cab2bb3Spatrick Value LHSVal(Data->LHSType, LHS);
3353cab2bb3Spatrick Value RHSVal(Data->RHSType, RHS);
3363cab2bb3Spatrick
3373cab2bb3Spatrick ErrorType ET;
3383cab2bb3Spatrick if (RHSVal.isNegative() ||
3393cab2bb3Spatrick RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth())
3403cab2bb3Spatrick ET = ErrorType::InvalidShiftExponent;
3413cab2bb3Spatrick else
3423cab2bb3Spatrick ET = ErrorType::InvalidShiftBase;
3433cab2bb3Spatrick
3443cab2bb3Spatrick if (ignoreReport(Loc, Opts, ET))
3453cab2bb3Spatrick return;
3463cab2bb3Spatrick
3473cab2bb3Spatrick ScopedReport R(Opts, Loc, ET);
3483cab2bb3Spatrick
3493cab2bb3Spatrick if (ET == ErrorType::InvalidShiftExponent) {
3503cab2bb3Spatrick if (RHSVal.isNegative())
3513cab2bb3Spatrick Diag(Loc, DL_Error, ET, "shift exponent %0 is negative") << RHSVal;
3523cab2bb3Spatrick else
3533cab2bb3Spatrick Diag(Loc, DL_Error, ET,
3543cab2bb3Spatrick "shift exponent %0 is too large for %1-bit type %2")
3553cab2bb3Spatrick << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType;
3563cab2bb3Spatrick } else {
3573cab2bb3Spatrick if (LHSVal.isNegative())
3583cab2bb3Spatrick Diag(Loc, DL_Error, ET, "left shift of negative value %0") << LHSVal;
3593cab2bb3Spatrick else
3603cab2bb3Spatrick Diag(Loc, DL_Error, ET,
3613cab2bb3Spatrick "left shift of %0 by %1 places cannot be represented in type %2")
3623cab2bb3Spatrick << LHSVal << RHSVal << Data->LHSType;
3633cab2bb3Spatrick }
3643cab2bb3Spatrick }
3653cab2bb3Spatrick
__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData * Data,ValueHandle LHS,ValueHandle RHS)3663cab2bb3Spatrick void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,
3673cab2bb3Spatrick ValueHandle LHS,
3683cab2bb3Spatrick ValueHandle RHS) {
3693cab2bb3Spatrick GET_REPORT_OPTIONS(false);
3703cab2bb3Spatrick handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);
3713cab2bb3Spatrick }
__ubsan_handle_shift_out_of_bounds_abort(ShiftOutOfBoundsData * Data,ValueHandle LHS,ValueHandle RHS)3723cab2bb3Spatrick void __ubsan::__ubsan_handle_shift_out_of_bounds_abort(
3733cab2bb3Spatrick ShiftOutOfBoundsData *Data,
3743cab2bb3Spatrick ValueHandle LHS,
3753cab2bb3Spatrick ValueHandle RHS) {
3763cab2bb3Spatrick GET_REPORT_OPTIONS(true);
3773cab2bb3Spatrick handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);
3783cab2bb3Spatrick Die();
3793cab2bb3Spatrick }
3803cab2bb3Spatrick
handleOutOfBoundsImpl(OutOfBoundsData * Data,ValueHandle Index,ReportOptions Opts)3813cab2bb3Spatrick static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,
3823cab2bb3Spatrick ReportOptions Opts) {
3833cab2bb3Spatrick SourceLocation Loc = Data->Loc.acquire();
3843cab2bb3Spatrick ErrorType ET = ErrorType::OutOfBoundsIndex;
3853cab2bb3Spatrick
3863cab2bb3Spatrick if (ignoreReport(Loc, Opts, ET))
3873cab2bb3Spatrick return;
3883cab2bb3Spatrick
3893cab2bb3Spatrick ScopedReport R(Opts, Loc, ET);
3903cab2bb3Spatrick
3913cab2bb3Spatrick Value IndexVal(Data->IndexType, Index);
3923cab2bb3Spatrick Diag(Loc, DL_Error, ET, "index %0 out of bounds for type %1")
3933cab2bb3Spatrick << IndexVal << Data->ArrayType;
3943cab2bb3Spatrick }
3953cab2bb3Spatrick
__ubsan_handle_out_of_bounds(OutOfBoundsData * Data,ValueHandle Index)3963cab2bb3Spatrick void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data,
3973cab2bb3Spatrick ValueHandle Index) {
3983cab2bb3Spatrick GET_REPORT_OPTIONS(false);
3993cab2bb3Spatrick handleOutOfBoundsImpl(Data, Index, Opts);
4003cab2bb3Spatrick }
__ubsan_handle_out_of_bounds_abort(OutOfBoundsData * Data,ValueHandle Index)4013cab2bb3Spatrick void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data,
4023cab2bb3Spatrick ValueHandle Index) {
4033cab2bb3Spatrick GET_REPORT_OPTIONS(true);
4043cab2bb3Spatrick handleOutOfBoundsImpl(Data, Index, Opts);
4053cab2bb3Spatrick Die();
4063cab2bb3Spatrick }
4073cab2bb3Spatrick
handleBuiltinUnreachableImpl(UnreachableData * Data,ReportOptions Opts)4083cab2bb3Spatrick static void handleBuiltinUnreachableImpl(UnreachableData *Data,
4093cab2bb3Spatrick ReportOptions Opts) {
4103cab2bb3Spatrick ErrorType ET = ErrorType::UnreachableCall;
4113cab2bb3Spatrick ScopedReport R(Opts, Data->Loc, ET);
4123cab2bb3Spatrick Diag(Data->Loc, DL_Error, ET,
4133cab2bb3Spatrick "execution reached an unreachable program point");
4143cab2bb3Spatrick }
4153cab2bb3Spatrick
__ubsan_handle_builtin_unreachable(UnreachableData * Data)4163cab2bb3Spatrick void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {
4173cab2bb3Spatrick GET_REPORT_OPTIONS(true);
4183cab2bb3Spatrick handleBuiltinUnreachableImpl(Data, Opts);
4193cab2bb3Spatrick Die();
4203cab2bb3Spatrick }
4213cab2bb3Spatrick
handleMissingReturnImpl(UnreachableData * Data,ReportOptions Opts)4223cab2bb3Spatrick static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) {
4233cab2bb3Spatrick ErrorType ET = ErrorType::MissingReturn;
4243cab2bb3Spatrick ScopedReport R(Opts, Data->Loc, ET);
4253cab2bb3Spatrick Diag(Data->Loc, DL_Error, ET,
4263cab2bb3Spatrick "execution reached the end of a value-returning function "
4273cab2bb3Spatrick "without returning a value");
4283cab2bb3Spatrick }
4293cab2bb3Spatrick
__ubsan_handle_missing_return(UnreachableData * Data)4303cab2bb3Spatrick void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {
4313cab2bb3Spatrick GET_REPORT_OPTIONS(true);
4323cab2bb3Spatrick handleMissingReturnImpl(Data, Opts);
4333cab2bb3Spatrick Die();
4343cab2bb3Spatrick }
4353cab2bb3Spatrick
handleVLABoundNotPositive(VLABoundData * Data,ValueHandle Bound,ReportOptions Opts)4363cab2bb3Spatrick static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,
4373cab2bb3Spatrick ReportOptions Opts) {
4383cab2bb3Spatrick SourceLocation Loc = Data->Loc.acquire();
4393cab2bb3Spatrick ErrorType ET = ErrorType::NonPositiveVLAIndex;
4403cab2bb3Spatrick
4413cab2bb3Spatrick if (ignoreReport(Loc, Opts, ET))
4423cab2bb3Spatrick return;
4433cab2bb3Spatrick
4443cab2bb3Spatrick ScopedReport R(Opts, Loc, ET);
4453cab2bb3Spatrick
4463cab2bb3Spatrick Diag(Loc, DL_Error, ET, "variable length array bound evaluates to "
4473cab2bb3Spatrick "non-positive value %0")
4483cab2bb3Spatrick << Value(Data->Type, Bound);
4493cab2bb3Spatrick }
4503cab2bb3Spatrick
__ubsan_handle_vla_bound_not_positive(VLABoundData * Data,ValueHandle Bound)4513cab2bb3Spatrick void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data,
4523cab2bb3Spatrick ValueHandle Bound) {
4533cab2bb3Spatrick GET_REPORT_OPTIONS(false);
4543cab2bb3Spatrick handleVLABoundNotPositive(Data, Bound, Opts);
4553cab2bb3Spatrick }
__ubsan_handle_vla_bound_not_positive_abort(VLABoundData * Data,ValueHandle Bound)4563cab2bb3Spatrick void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data,
4573cab2bb3Spatrick ValueHandle Bound) {
4583cab2bb3Spatrick GET_REPORT_OPTIONS(true);
4593cab2bb3Spatrick handleVLABoundNotPositive(Data, Bound, Opts);
4603cab2bb3Spatrick Die();
4613cab2bb3Spatrick }
4623cab2bb3Spatrick
looksLikeFloatCastOverflowDataV1(void * Data)4633cab2bb3Spatrick static bool looksLikeFloatCastOverflowDataV1(void *Data) {
4643cab2bb3Spatrick // First field is either a pointer to filename or a pointer to a
4653cab2bb3Spatrick // TypeDescriptor.
4663cab2bb3Spatrick u8 *FilenameOrTypeDescriptor;
4673cab2bb3Spatrick internal_memcpy(&FilenameOrTypeDescriptor, Data,
4683cab2bb3Spatrick sizeof(FilenameOrTypeDescriptor));
4693cab2bb3Spatrick
4703cab2bb3Spatrick // Heuristic: For float_cast_overflow, the TypeKind will be either TK_Integer
4713cab2bb3Spatrick // (0x0), TK_Float (0x1) or TK_Unknown (0xff). If both types are known,
4723cab2bb3Spatrick // adding both bytes will be 0 or 1 (for BE or LE). If it were a filename,
4733cab2bb3Spatrick // adding two printable characters will not yield such a value. Otherwise,
4743cab2bb3Spatrick // if one of them is 0xff, this is most likely TK_Unknown type descriptor.
4753cab2bb3Spatrick u16 MaybeFromTypeKind =
4763cab2bb3Spatrick FilenameOrTypeDescriptor[0] + FilenameOrTypeDescriptor[1];
4773cab2bb3Spatrick return MaybeFromTypeKind < 2 || FilenameOrTypeDescriptor[0] == 0xff ||
4783cab2bb3Spatrick FilenameOrTypeDescriptor[1] == 0xff;
4793cab2bb3Spatrick }
4803cab2bb3Spatrick
handleFloatCastOverflow(void * DataPtr,ValueHandle From,ReportOptions Opts)4813cab2bb3Spatrick static void handleFloatCastOverflow(void *DataPtr, ValueHandle From,
4823cab2bb3Spatrick ReportOptions Opts) {
4833cab2bb3Spatrick SymbolizedStackHolder CallerLoc;
4843cab2bb3Spatrick Location Loc;
4853cab2bb3Spatrick const TypeDescriptor *FromType, *ToType;
4863cab2bb3Spatrick ErrorType ET = ErrorType::FloatCastOverflow;
4873cab2bb3Spatrick
4883cab2bb3Spatrick if (looksLikeFloatCastOverflowDataV1(DataPtr)) {
4893cab2bb3Spatrick auto Data = reinterpret_cast<FloatCastOverflowData *>(DataPtr);
4903cab2bb3Spatrick CallerLoc.reset(getCallerLocation(Opts.pc));
4913cab2bb3Spatrick Loc = CallerLoc;
4923cab2bb3Spatrick FromType = &Data->FromType;
4933cab2bb3Spatrick ToType = &Data->ToType;
4943cab2bb3Spatrick } else {
4953cab2bb3Spatrick auto Data = reinterpret_cast<FloatCastOverflowDataV2 *>(DataPtr);
4963cab2bb3Spatrick SourceLocation SLoc = Data->Loc.acquire();
4973cab2bb3Spatrick if (ignoreReport(SLoc, Opts, ET))
4983cab2bb3Spatrick return;
4993cab2bb3Spatrick Loc = SLoc;
5003cab2bb3Spatrick FromType = &Data->FromType;
5013cab2bb3Spatrick ToType = &Data->ToType;
5023cab2bb3Spatrick }
5033cab2bb3Spatrick
5043cab2bb3Spatrick ScopedReport R(Opts, Loc, ET);
5053cab2bb3Spatrick
5063cab2bb3Spatrick Diag(Loc, DL_Error, ET,
5073cab2bb3Spatrick "%0 is outside the range of representable values of type %2")
5083cab2bb3Spatrick << Value(*FromType, From) << *FromType << *ToType;
5093cab2bb3Spatrick }
5103cab2bb3Spatrick
__ubsan_handle_float_cast_overflow(void * Data,ValueHandle From)5113cab2bb3Spatrick void __ubsan::__ubsan_handle_float_cast_overflow(void *Data, ValueHandle From) {
5123cab2bb3Spatrick GET_REPORT_OPTIONS(false);
5133cab2bb3Spatrick handleFloatCastOverflow(Data, From, Opts);
5143cab2bb3Spatrick }
__ubsan_handle_float_cast_overflow_abort(void * Data,ValueHandle From)5153cab2bb3Spatrick void __ubsan::__ubsan_handle_float_cast_overflow_abort(void *Data,
5163cab2bb3Spatrick ValueHandle From) {
5173cab2bb3Spatrick GET_REPORT_OPTIONS(true);
5183cab2bb3Spatrick handleFloatCastOverflow(Data, From, Opts);
5193cab2bb3Spatrick Die();
5203cab2bb3Spatrick }
5213cab2bb3Spatrick
handleLoadInvalidValue(InvalidValueData * Data,ValueHandle Val,ReportOptions Opts)5223cab2bb3Spatrick static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,
5233cab2bb3Spatrick ReportOptions Opts) {
5243cab2bb3Spatrick SourceLocation Loc = Data->Loc.acquire();
5253cab2bb3Spatrick // This check could be more precise if we used different handlers for
5263cab2bb3Spatrick // -fsanitize=bool and -fsanitize=enum.
5273cab2bb3Spatrick bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'")) ||
5283cab2bb3Spatrick (0 == internal_strncmp(Data->Type.getTypeName(), "'BOOL'", 6));
5293cab2bb3Spatrick ErrorType ET =
5303cab2bb3Spatrick IsBool ? ErrorType::InvalidBoolLoad : ErrorType::InvalidEnumLoad;
5313cab2bb3Spatrick
5323cab2bb3Spatrick if (ignoreReport(Loc, Opts, ET))
5333cab2bb3Spatrick return;
5343cab2bb3Spatrick
5353cab2bb3Spatrick ScopedReport R(Opts, Loc, ET);
5363cab2bb3Spatrick
5373cab2bb3Spatrick Diag(Loc, DL_Error, ET,
5383cab2bb3Spatrick "load of value %0, which is not a valid value for type %1")
5393cab2bb3Spatrick << Value(Data->Type, Val) << Data->Type;
5403cab2bb3Spatrick }
5413cab2bb3Spatrick
__ubsan_handle_load_invalid_value(InvalidValueData * Data,ValueHandle Val)5423cab2bb3Spatrick void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,
5433cab2bb3Spatrick ValueHandle Val) {
5443cab2bb3Spatrick GET_REPORT_OPTIONS(false);
5453cab2bb3Spatrick handleLoadInvalidValue(Data, Val, Opts);
5463cab2bb3Spatrick }
__ubsan_handle_load_invalid_value_abort(InvalidValueData * Data,ValueHandle Val)5473cab2bb3Spatrick void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data,
5483cab2bb3Spatrick ValueHandle Val) {
5493cab2bb3Spatrick GET_REPORT_OPTIONS(true);
5503cab2bb3Spatrick handleLoadInvalidValue(Data, Val, Opts);
5513cab2bb3Spatrick Die();
5523cab2bb3Spatrick }
5533cab2bb3Spatrick
handleImplicitConversion(ImplicitConversionData * Data,ReportOptions Opts,ValueHandle Src,ValueHandle Dst)5543cab2bb3Spatrick static void handleImplicitConversion(ImplicitConversionData *Data,
5553cab2bb3Spatrick ReportOptions Opts, ValueHandle Src,
5563cab2bb3Spatrick ValueHandle Dst) {
5573cab2bb3Spatrick SourceLocation Loc = Data->Loc.acquire();
5583cab2bb3Spatrick ErrorType ET = ErrorType::GenericUB;
5593cab2bb3Spatrick
5603cab2bb3Spatrick const TypeDescriptor &SrcTy = Data->FromType;
5613cab2bb3Spatrick const TypeDescriptor &DstTy = Data->ToType;
5623cab2bb3Spatrick
5633cab2bb3Spatrick bool SrcSigned = SrcTy.isSignedIntegerTy();
5643cab2bb3Spatrick bool DstSigned = DstTy.isSignedIntegerTy();
5653cab2bb3Spatrick
5663cab2bb3Spatrick switch (Data->Kind) {
5673cab2bb3Spatrick case ICCK_IntegerTruncation: { // Legacy, no longer used.
5683cab2bb3Spatrick // Let's figure out what it should be as per the new types, and upgrade.
5693cab2bb3Spatrick // If both types are unsigned, then it's an unsigned truncation.
5703cab2bb3Spatrick // Else, it is a signed truncation.
5713cab2bb3Spatrick if (!SrcSigned && !DstSigned) {
5723cab2bb3Spatrick ET = ErrorType::ImplicitUnsignedIntegerTruncation;
5733cab2bb3Spatrick } else {
5743cab2bb3Spatrick ET = ErrorType::ImplicitSignedIntegerTruncation;
5753cab2bb3Spatrick }
5763cab2bb3Spatrick break;
5773cab2bb3Spatrick }
5783cab2bb3Spatrick case ICCK_UnsignedIntegerTruncation:
5793cab2bb3Spatrick ET = ErrorType::ImplicitUnsignedIntegerTruncation;
5803cab2bb3Spatrick break;
5813cab2bb3Spatrick case ICCK_SignedIntegerTruncation:
5823cab2bb3Spatrick ET = ErrorType::ImplicitSignedIntegerTruncation;
5833cab2bb3Spatrick break;
5843cab2bb3Spatrick case ICCK_IntegerSignChange:
5853cab2bb3Spatrick ET = ErrorType::ImplicitIntegerSignChange;
5863cab2bb3Spatrick break;
5873cab2bb3Spatrick case ICCK_SignedIntegerTruncationOrSignChange:
5883cab2bb3Spatrick ET = ErrorType::ImplicitSignedIntegerTruncationOrSignChange;
5893cab2bb3Spatrick break;
5903cab2bb3Spatrick }
5913cab2bb3Spatrick
5923cab2bb3Spatrick if (ignoreReport(Loc, Opts, ET))
5933cab2bb3Spatrick return;
5943cab2bb3Spatrick
5953cab2bb3Spatrick ScopedReport R(Opts, Loc, ET);
5963cab2bb3Spatrick
5973cab2bb3Spatrick // FIXME: is it possible to dump the values as hex with fixed width?
5983cab2bb3Spatrick
5993cab2bb3Spatrick Diag(Loc, DL_Error, ET,
6003cab2bb3Spatrick "implicit conversion from type %0 of value %1 (%2-bit, %3signed) to "
6013cab2bb3Spatrick "type %4 changed the value to %5 (%6-bit, %7signed)")
6023cab2bb3Spatrick << SrcTy << Value(SrcTy, Src) << SrcTy.getIntegerBitWidth()
6033cab2bb3Spatrick << (SrcSigned ? "" : "un") << DstTy << Value(DstTy, Dst)
6043cab2bb3Spatrick << DstTy.getIntegerBitWidth() << (DstSigned ? "" : "un");
6053cab2bb3Spatrick }
6063cab2bb3Spatrick
__ubsan_handle_implicit_conversion(ImplicitConversionData * Data,ValueHandle Src,ValueHandle Dst)6073cab2bb3Spatrick void __ubsan::__ubsan_handle_implicit_conversion(ImplicitConversionData *Data,
6083cab2bb3Spatrick ValueHandle Src,
6093cab2bb3Spatrick ValueHandle Dst) {
6103cab2bb3Spatrick GET_REPORT_OPTIONS(false);
6113cab2bb3Spatrick handleImplicitConversion(Data, Opts, Src, Dst);
6123cab2bb3Spatrick }
__ubsan_handle_implicit_conversion_abort(ImplicitConversionData * Data,ValueHandle Src,ValueHandle Dst)6133cab2bb3Spatrick void __ubsan::__ubsan_handle_implicit_conversion_abort(
6143cab2bb3Spatrick ImplicitConversionData *Data, ValueHandle Src, ValueHandle Dst) {
6153cab2bb3Spatrick GET_REPORT_OPTIONS(true);
6163cab2bb3Spatrick handleImplicitConversion(Data, Opts, Src, Dst);
6173cab2bb3Spatrick Die();
6183cab2bb3Spatrick }
6193cab2bb3Spatrick
handleInvalidBuiltin(InvalidBuiltinData * Data,ReportOptions Opts)6203cab2bb3Spatrick static void handleInvalidBuiltin(InvalidBuiltinData *Data, ReportOptions Opts) {
6213cab2bb3Spatrick SourceLocation Loc = Data->Loc.acquire();
6223cab2bb3Spatrick ErrorType ET = ErrorType::InvalidBuiltin;
6233cab2bb3Spatrick
6243cab2bb3Spatrick if (ignoreReport(Loc, Opts, ET))
6253cab2bb3Spatrick return;
6263cab2bb3Spatrick
6273cab2bb3Spatrick ScopedReport R(Opts, Loc, ET);
6283cab2bb3Spatrick
6293cab2bb3Spatrick Diag(Loc, DL_Error, ET,
6303cab2bb3Spatrick "passing zero to %0, which is not a valid argument")
6313cab2bb3Spatrick << ((Data->Kind == BCK_CTZPassedZero) ? "ctz()" : "clz()");
6323cab2bb3Spatrick }
6333cab2bb3Spatrick
__ubsan_handle_invalid_builtin(InvalidBuiltinData * Data)6343cab2bb3Spatrick void __ubsan::__ubsan_handle_invalid_builtin(InvalidBuiltinData *Data) {
6353cab2bb3Spatrick GET_REPORT_OPTIONS(true);
6363cab2bb3Spatrick handleInvalidBuiltin(Data, Opts);
6373cab2bb3Spatrick }
__ubsan_handle_invalid_builtin_abort(InvalidBuiltinData * Data)6383cab2bb3Spatrick void __ubsan::__ubsan_handle_invalid_builtin_abort(InvalidBuiltinData *Data) {
6393cab2bb3Spatrick GET_REPORT_OPTIONS(true);
6403cab2bb3Spatrick handleInvalidBuiltin(Data, Opts);
6413cab2bb3Spatrick Die();
6423cab2bb3Spatrick }
6433cab2bb3Spatrick
handleInvalidObjCCast(InvalidObjCCast * Data,ValueHandle Pointer,ReportOptions Opts)6441f9cb04fSpatrick static void handleInvalidObjCCast(InvalidObjCCast *Data, ValueHandle Pointer,
6451f9cb04fSpatrick ReportOptions Opts) {
6461f9cb04fSpatrick SourceLocation Loc = Data->Loc.acquire();
6471f9cb04fSpatrick ErrorType ET = ErrorType::InvalidObjCCast;
6481f9cb04fSpatrick
6491f9cb04fSpatrick if (ignoreReport(Loc, Opts, ET))
6501f9cb04fSpatrick return;
6511f9cb04fSpatrick
6521f9cb04fSpatrick ScopedReport R(Opts, Loc, ET);
6531f9cb04fSpatrick
6541f9cb04fSpatrick const char *GivenClass = getObjCClassName(Pointer);
6551f9cb04fSpatrick const char *GivenClassStr = GivenClass ? GivenClass : "<unknown type>";
6561f9cb04fSpatrick
6571f9cb04fSpatrick Diag(Loc, DL_Error, ET,
6581f9cb04fSpatrick "invalid ObjC cast, object is a '%0', but expected a %1")
6591f9cb04fSpatrick << GivenClassStr << Data->ExpectedType;
6601f9cb04fSpatrick }
6611f9cb04fSpatrick
__ubsan_handle_invalid_objc_cast(InvalidObjCCast * Data,ValueHandle Pointer)6621f9cb04fSpatrick void __ubsan::__ubsan_handle_invalid_objc_cast(InvalidObjCCast *Data,
6631f9cb04fSpatrick ValueHandle Pointer) {
6641f9cb04fSpatrick GET_REPORT_OPTIONS(false);
6651f9cb04fSpatrick handleInvalidObjCCast(Data, Pointer, Opts);
6661f9cb04fSpatrick }
__ubsan_handle_invalid_objc_cast_abort(InvalidObjCCast * Data,ValueHandle Pointer)6671f9cb04fSpatrick void __ubsan::__ubsan_handle_invalid_objc_cast_abort(InvalidObjCCast *Data,
6681f9cb04fSpatrick ValueHandle Pointer) {
6691f9cb04fSpatrick GET_REPORT_OPTIONS(true);
6701f9cb04fSpatrick handleInvalidObjCCast(Data, Pointer, Opts);
6711f9cb04fSpatrick Die();
6721f9cb04fSpatrick }
6731f9cb04fSpatrick
handleNonNullReturn(NonNullReturnData * Data,SourceLocation * LocPtr,ReportOptions Opts,bool IsAttr)6743cab2bb3Spatrick static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr,
6753cab2bb3Spatrick ReportOptions Opts, bool IsAttr) {
6763cab2bb3Spatrick if (!LocPtr)
6773cab2bb3Spatrick UNREACHABLE("source location pointer is null!");
6783cab2bb3Spatrick
6793cab2bb3Spatrick SourceLocation Loc = LocPtr->acquire();
6801f9cb04fSpatrick ErrorType ET = IsAttr ? ErrorType::InvalidNullReturn
6811f9cb04fSpatrick : ErrorType::InvalidNullReturnWithNullability;
6823cab2bb3Spatrick
6833cab2bb3Spatrick if (ignoreReport(Loc, Opts, ET))
6843cab2bb3Spatrick return;
6853cab2bb3Spatrick
6863cab2bb3Spatrick ScopedReport R(Opts, Loc, ET);
6873cab2bb3Spatrick
6883cab2bb3Spatrick Diag(Loc, DL_Error, ET,
6893cab2bb3Spatrick "null pointer returned from function declared to never return null");
6903cab2bb3Spatrick if (!Data->AttrLoc.isInvalid())
6913cab2bb3Spatrick Diag(Data->AttrLoc, DL_Note, ET, "%0 specified here")
6923cab2bb3Spatrick << (IsAttr ? "returns_nonnull attribute"
6933cab2bb3Spatrick : "_Nonnull return type annotation");
6943cab2bb3Spatrick }
6953cab2bb3Spatrick
__ubsan_handle_nonnull_return_v1(NonNullReturnData * Data,SourceLocation * LocPtr)6963cab2bb3Spatrick void __ubsan::__ubsan_handle_nonnull_return_v1(NonNullReturnData *Data,
6973cab2bb3Spatrick SourceLocation *LocPtr) {
6983cab2bb3Spatrick GET_REPORT_OPTIONS(false);
6993cab2bb3Spatrick handleNonNullReturn(Data, LocPtr, Opts, true);
7003cab2bb3Spatrick }
7013cab2bb3Spatrick
__ubsan_handle_nonnull_return_v1_abort(NonNullReturnData * Data,SourceLocation * LocPtr)7023cab2bb3Spatrick void __ubsan::__ubsan_handle_nonnull_return_v1_abort(NonNullReturnData *Data,
7033cab2bb3Spatrick SourceLocation *LocPtr) {
7043cab2bb3Spatrick GET_REPORT_OPTIONS(true);
7053cab2bb3Spatrick handleNonNullReturn(Data, LocPtr, Opts, true);
7063cab2bb3Spatrick Die();
7073cab2bb3Spatrick }
7083cab2bb3Spatrick
__ubsan_handle_nullability_return_v1(NonNullReturnData * Data,SourceLocation * LocPtr)7093cab2bb3Spatrick void __ubsan::__ubsan_handle_nullability_return_v1(NonNullReturnData *Data,
7103cab2bb3Spatrick SourceLocation *LocPtr) {
7113cab2bb3Spatrick GET_REPORT_OPTIONS(false);
7123cab2bb3Spatrick handleNonNullReturn(Data, LocPtr, Opts, false);
7133cab2bb3Spatrick }
7143cab2bb3Spatrick
__ubsan_handle_nullability_return_v1_abort(NonNullReturnData * Data,SourceLocation * LocPtr)7153cab2bb3Spatrick void __ubsan::__ubsan_handle_nullability_return_v1_abort(
7163cab2bb3Spatrick NonNullReturnData *Data, SourceLocation *LocPtr) {
7173cab2bb3Spatrick GET_REPORT_OPTIONS(true);
7183cab2bb3Spatrick handleNonNullReturn(Data, LocPtr, Opts, false);
7193cab2bb3Spatrick Die();
7203cab2bb3Spatrick }
7213cab2bb3Spatrick
handleNonNullArg(NonNullArgData * Data,ReportOptions Opts,bool IsAttr)7223cab2bb3Spatrick static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts,
7233cab2bb3Spatrick bool IsAttr) {
7243cab2bb3Spatrick SourceLocation Loc = Data->Loc.acquire();
7251f9cb04fSpatrick ErrorType ET = IsAttr ? ErrorType::InvalidNullArgument
7261f9cb04fSpatrick : ErrorType::InvalidNullArgumentWithNullability;
7273cab2bb3Spatrick
7283cab2bb3Spatrick if (ignoreReport(Loc, Opts, ET))
7293cab2bb3Spatrick return;
7303cab2bb3Spatrick
7313cab2bb3Spatrick ScopedReport R(Opts, Loc, ET);
7323cab2bb3Spatrick
7333cab2bb3Spatrick Diag(Loc, DL_Error, ET,
7343cab2bb3Spatrick "null pointer passed as argument %0, which is declared to "
7353cab2bb3Spatrick "never be null")
7363cab2bb3Spatrick << Data->ArgIndex;
7373cab2bb3Spatrick if (!Data->AttrLoc.isInvalid())
7383cab2bb3Spatrick Diag(Data->AttrLoc, DL_Note, ET, "%0 specified here")
7393cab2bb3Spatrick << (IsAttr ? "nonnull attribute" : "_Nonnull type annotation");
7403cab2bb3Spatrick }
7413cab2bb3Spatrick
__ubsan_handle_nonnull_arg(NonNullArgData * Data)7423cab2bb3Spatrick void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) {
7433cab2bb3Spatrick GET_REPORT_OPTIONS(false);
7443cab2bb3Spatrick handleNonNullArg(Data, Opts, true);
7453cab2bb3Spatrick }
7463cab2bb3Spatrick
__ubsan_handle_nonnull_arg_abort(NonNullArgData * Data)7473cab2bb3Spatrick void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) {
7483cab2bb3Spatrick GET_REPORT_OPTIONS(true);
7493cab2bb3Spatrick handleNonNullArg(Data, Opts, true);
7503cab2bb3Spatrick Die();
7513cab2bb3Spatrick }
7523cab2bb3Spatrick
__ubsan_handle_nullability_arg(NonNullArgData * Data)7533cab2bb3Spatrick void __ubsan::__ubsan_handle_nullability_arg(NonNullArgData *Data) {
7543cab2bb3Spatrick GET_REPORT_OPTIONS(false);
7553cab2bb3Spatrick handleNonNullArg(Data, Opts, false);
7563cab2bb3Spatrick }
7573cab2bb3Spatrick
__ubsan_handle_nullability_arg_abort(NonNullArgData * Data)7583cab2bb3Spatrick void __ubsan::__ubsan_handle_nullability_arg_abort(NonNullArgData *Data) {
7593cab2bb3Spatrick GET_REPORT_OPTIONS(true);
7603cab2bb3Spatrick handleNonNullArg(Data, Opts, false);
7613cab2bb3Spatrick Die();
7623cab2bb3Spatrick }
7633cab2bb3Spatrick
handlePointerOverflowImpl(PointerOverflowData * Data,ValueHandle Base,ValueHandle Result,ReportOptions Opts)7643cab2bb3Spatrick static void handlePointerOverflowImpl(PointerOverflowData *Data,
7653cab2bb3Spatrick ValueHandle Base,
7663cab2bb3Spatrick ValueHandle Result,
7673cab2bb3Spatrick ReportOptions Opts) {
7683cab2bb3Spatrick SourceLocation Loc = Data->Loc.acquire();
7693cab2bb3Spatrick ErrorType ET;
7703cab2bb3Spatrick
7713cab2bb3Spatrick if (Base == 0 && Result == 0)
7723cab2bb3Spatrick ET = ErrorType::NullptrWithOffset;
7733cab2bb3Spatrick else if (Base == 0 && Result != 0)
7743cab2bb3Spatrick ET = ErrorType::NullptrWithNonZeroOffset;
7753cab2bb3Spatrick else if (Base != 0 && Result == 0)
7763cab2bb3Spatrick ET = ErrorType::NullptrAfterNonZeroOffset;
7773cab2bb3Spatrick else
7783cab2bb3Spatrick ET = ErrorType::PointerOverflow;
7793cab2bb3Spatrick
7803cab2bb3Spatrick if (ignoreReport(Loc, Opts, ET))
7813cab2bb3Spatrick return;
7823cab2bb3Spatrick
7833cab2bb3Spatrick ScopedReport R(Opts, Loc, ET);
7843cab2bb3Spatrick
7853cab2bb3Spatrick if (ET == ErrorType::NullptrWithOffset) {
7863cab2bb3Spatrick Diag(Loc, DL_Error, ET, "applying zero offset to null pointer");
7873cab2bb3Spatrick } else if (ET == ErrorType::NullptrWithNonZeroOffset) {
7883cab2bb3Spatrick Diag(Loc, DL_Error, ET, "applying non-zero offset %0 to null pointer")
7893cab2bb3Spatrick << Result;
7903cab2bb3Spatrick } else if (ET == ErrorType::NullptrAfterNonZeroOffset) {
7913cab2bb3Spatrick Diag(
7923cab2bb3Spatrick Loc, DL_Error, ET,
7933cab2bb3Spatrick "applying non-zero offset to non-null pointer %0 produced null pointer")
7943cab2bb3Spatrick << (void *)Base;
7953cab2bb3Spatrick } else if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) {
7963cab2bb3Spatrick if (Base > Result)
7973cab2bb3Spatrick Diag(Loc, DL_Error, ET,
7983cab2bb3Spatrick "addition of unsigned offset to %0 overflowed to %1")
7993cab2bb3Spatrick << (void *)Base << (void *)Result;
8003cab2bb3Spatrick else
8013cab2bb3Spatrick Diag(Loc, DL_Error, ET,
8023cab2bb3Spatrick "subtraction of unsigned offset from %0 overflowed to %1")
8033cab2bb3Spatrick << (void *)Base << (void *)Result;
8043cab2bb3Spatrick } else {
8053cab2bb3Spatrick Diag(Loc, DL_Error, ET,
8063cab2bb3Spatrick "pointer index expression with base %0 overflowed to %1")
8073cab2bb3Spatrick << (void *)Base << (void *)Result;
8083cab2bb3Spatrick }
8093cab2bb3Spatrick }
8103cab2bb3Spatrick
__ubsan_handle_pointer_overflow(PointerOverflowData * Data,ValueHandle Base,ValueHandle Result)8113cab2bb3Spatrick void __ubsan::__ubsan_handle_pointer_overflow(PointerOverflowData *Data,
8123cab2bb3Spatrick ValueHandle Base,
8133cab2bb3Spatrick ValueHandle Result) {
8143cab2bb3Spatrick GET_REPORT_OPTIONS(false);
8153cab2bb3Spatrick handlePointerOverflowImpl(Data, Base, Result, Opts);
8163cab2bb3Spatrick }
8173cab2bb3Spatrick
__ubsan_handle_pointer_overflow_abort(PointerOverflowData * Data,ValueHandle Base,ValueHandle Result)8183cab2bb3Spatrick void __ubsan::__ubsan_handle_pointer_overflow_abort(PointerOverflowData *Data,
8193cab2bb3Spatrick ValueHandle Base,
8203cab2bb3Spatrick ValueHandle Result) {
8213cab2bb3Spatrick GET_REPORT_OPTIONS(true);
8223cab2bb3Spatrick handlePointerOverflowImpl(Data, Base, Result, Opts);
8233cab2bb3Spatrick Die();
8243cab2bb3Spatrick }
8253cab2bb3Spatrick
handleCFIBadIcall(CFICheckFailData * Data,ValueHandle Function,ReportOptions Opts)8263cab2bb3Spatrick static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function,
8273cab2bb3Spatrick ReportOptions Opts) {
8283cab2bb3Spatrick if (Data->CheckKind != CFITCK_ICall && Data->CheckKind != CFITCK_NVMFCall)
8293cab2bb3Spatrick Die();
8303cab2bb3Spatrick
8313cab2bb3Spatrick SourceLocation Loc = Data->Loc.acquire();
8323cab2bb3Spatrick ErrorType ET = ErrorType::CFIBadType;
8333cab2bb3Spatrick
8343cab2bb3Spatrick if (ignoreReport(Loc, Opts, ET))
8353cab2bb3Spatrick return;
8363cab2bb3Spatrick
8373cab2bb3Spatrick ScopedReport R(Opts, Loc, ET);
8383cab2bb3Spatrick
8393cab2bb3Spatrick const char *CheckKindStr = Data->CheckKind == CFITCK_NVMFCall
8403cab2bb3Spatrick ? "non-virtual pointer to member function call"
8413cab2bb3Spatrick : "indirect function call";
8423cab2bb3Spatrick Diag(Loc, DL_Error, ET,
8433cab2bb3Spatrick "control flow integrity check for type %0 failed during %1")
8443cab2bb3Spatrick << Data->Type << CheckKindStr;
8453cab2bb3Spatrick
8463cab2bb3Spatrick SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));
8473cab2bb3Spatrick const char *FName = FLoc.get()->info.function;
8483cab2bb3Spatrick if (!FName)
8493cab2bb3Spatrick FName = "(unknown)";
8503cab2bb3Spatrick Diag(FLoc, DL_Note, ET, "%0 defined here") << FName;
8513cab2bb3Spatrick
8523cab2bb3Spatrick // If the failure involved different DSOs for the check location and icall
8533cab2bb3Spatrick // target, report the DSO names.
8543cab2bb3Spatrick const char *DstModule = FLoc.get()->info.module;
8553cab2bb3Spatrick if (!DstModule)
8563cab2bb3Spatrick DstModule = "(unknown)";
8573cab2bb3Spatrick
8583cab2bb3Spatrick const char *SrcModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Opts.pc);
8593cab2bb3Spatrick if (!SrcModule)
8603cab2bb3Spatrick SrcModule = "(unknown)";
8613cab2bb3Spatrick
8623cab2bb3Spatrick if (internal_strcmp(SrcModule, DstModule))
8633cab2bb3Spatrick Diag(Loc, DL_Note, ET,
8643cab2bb3Spatrick "check failed in %0, destination function located in %1")
8653cab2bb3Spatrick << SrcModule << DstModule;
8663cab2bb3Spatrick }
8673cab2bb3Spatrick
8683cab2bb3Spatrick namespace __ubsan {
8693cab2bb3Spatrick
8703cab2bb3Spatrick #ifdef UBSAN_CAN_USE_CXXABI
8713cab2bb3Spatrick
8723cab2bb3Spatrick #ifdef _WIN32
8733cab2bb3Spatrick
__ubsan_handle_cfi_bad_type_default(CFICheckFailData * Data,ValueHandle Vtable,bool ValidVtable,ReportOptions Opts)8743cab2bb3Spatrick extern "C" void __ubsan_handle_cfi_bad_type_default(CFICheckFailData *Data,
8753cab2bb3Spatrick ValueHandle Vtable,
8763cab2bb3Spatrick bool ValidVtable,
8773cab2bb3Spatrick ReportOptions Opts) {
8783cab2bb3Spatrick Die();
8793cab2bb3Spatrick }
8803cab2bb3Spatrick
8813cab2bb3Spatrick WIN_WEAK_ALIAS(__ubsan_handle_cfi_bad_type, __ubsan_handle_cfi_bad_type_default)
8823cab2bb3Spatrick #else
8833cab2bb3Spatrick SANITIZER_WEAK_ATTRIBUTE
8843cab2bb3Spatrick #endif
8853cab2bb3Spatrick void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
8863cab2bb3Spatrick bool ValidVtable, ReportOptions Opts);
8873cab2bb3Spatrick
8883cab2bb3Spatrick #else
8893cab2bb3Spatrick void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
8903cab2bb3Spatrick bool ValidVtable, ReportOptions Opts) {
8913cab2bb3Spatrick Die();
8923cab2bb3Spatrick }
8933cab2bb3Spatrick #endif
8943cab2bb3Spatrick
8953cab2bb3Spatrick } // namespace __ubsan
8963cab2bb3Spatrick
__ubsan_handle_cfi_check_fail(CFICheckFailData * Data,ValueHandle Value,uptr ValidVtable)8973cab2bb3Spatrick void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,
8983cab2bb3Spatrick ValueHandle Value,
8993cab2bb3Spatrick uptr ValidVtable) {
9003cab2bb3Spatrick GET_REPORT_OPTIONS(false);
9013cab2bb3Spatrick if (Data->CheckKind == CFITCK_ICall || Data->CheckKind == CFITCK_NVMFCall)
9023cab2bb3Spatrick handleCFIBadIcall(Data, Value, Opts);
9033cab2bb3Spatrick else
9043cab2bb3Spatrick __ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts);
9053cab2bb3Spatrick }
9063cab2bb3Spatrick
__ubsan_handle_cfi_check_fail_abort(CFICheckFailData * Data,ValueHandle Value,uptr ValidVtable)9073cab2bb3Spatrick void __ubsan::__ubsan_handle_cfi_check_fail_abort(CFICheckFailData *Data,
9083cab2bb3Spatrick ValueHandle Value,
9093cab2bb3Spatrick uptr ValidVtable) {
9103cab2bb3Spatrick GET_REPORT_OPTIONS(true);
9113cab2bb3Spatrick if (Data->CheckKind == CFITCK_ICall || Data->CheckKind == CFITCK_NVMFCall)
9123cab2bb3Spatrick handleCFIBadIcall(Data, Value, Opts);
9133cab2bb3Spatrick else
9143cab2bb3Spatrick __ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts);
9153cab2bb3Spatrick Die();
9163cab2bb3Spatrick }
9173cab2bb3Spatrick
9183cab2bb3Spatrick #endif // CAN_SANITIZE_UB
919