xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/ubsan/ubsan_handlers.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
168d75effSDimitry Andric //===-- ubsan_handlers.cpp ------------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // Error logging entry points for the UBSan runtime.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric //===----------------------------------------------------------------------===//
1268d75effSDimitry Andric 
1368d75effSDimitry Andric #include "ubsan_platform.h"
1468d75effSDimitry Andric #if CAN_SANITIZE_UB
1568d75effSDimitry Andric #include "ubsan_handlers.h"
1668d75effSDimitry Andric #include "ubsan_diag.h"
1768d75effSDimitry Andric #include "ubsan_flags.h"
1868d75effSDimitry Andric #include "ubsan_monitor.h"
195ffd83dbSDimitry Andric #include "ubsan_value.h"
2068d75effSDimitry Andric 
2168d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
2268d75effSDimitry Andric 
2368d75effSDimitry Andric using namespace __sanitizer;
2468d75effSDimitry Andric using namespace __ubsan;
2568d75effSDimitry Andric 
2668d75effSDimitry Andric namespace __ubsan {
2768d75effSDimitry Andric bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) {
2868d75effSDimitry Andric   // We are not allowed to skip error report: if we are in unrecoverable
2968d75effSDimitry Andric   // handler, we have to terminate the program right now, and therefore
3068d75effSDimitry Andric   // have to print some diagnostic.
3168d75effSDimitry Andric   //
3268d75effSDimitry Andric   // Even if source location is disabled, it doesn't mean that we have
3368d75effSDimitry Andric   // already report an error to the user: some concurrently running
3468d75effSDimitry Andric   // thread could have acquired it, but not yet printed the report.
3568d75effSDimitry Andric   if (Opts.FromUnrecoverableHandler)
3668d75effSDimitry Andric     return false;
3768d75effSDimitry Andric   return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc, SLoc.getFilename());
3868d75effSDimitry Andric }
3968d75effSDimitry Andric 
405ffd83dbSDimitry Andric /// Situations in which we might emit a check for the suitability of a
415ffd83dbSDimitry Andric /// pointer or glvalue. Needs to be kept in sync with CodeGenFunction.h in
425ffd83dbSDimitry Andric /// clang.
435ffd83dbSDimitry Andric enum TypeCheckKind {
445ffd83dbSDimitry Andric   /// Checking the operand of a load. Must be suitably sized and aligned.
455ffd83dbSDimitry Andric   TCK_Load,
465ffd83dbSDimitry Andric   /// Checking the destination of a store. Must be suitably sized and aligned.
475ffd83dbSDimitry Andric   TCK_Store,
485ffd83dbSDimitry Andric   /// Checking the bound value in a reference binding. Must be suitably sized
495ffd83dbSDimitry Andric   /// and aligned, but is not required to refer to an object (until the
505ffd83dbSDimitry Andric   /// reference is used), per core issue 453.
515ffd83dbSDimitry Andric   TCK_ReferenceBinding,
525ffd83dbSDimitry Andric   /// Checking the object expression in a non-static data member access. Must
535ffd83dbSDimitry Andric   /// be an object within its lifetime.
545ffd83dbSDimitry Andric   TCK_MemberAccess,
555ffd83dbSDimitry Andric   /// Checking the 'this' pointer for a call to a non-static member function.
565ffd83dbSDimitry Andric   /// Must be an object within its lifetime.
575ffd83dbSDimitry Andric   TCK_MemberCall,
585ffd83dbSDimitry Andric   /// Checking the 'this' pointer for a constructor call.
595ffd83dbSDimitry Andric   TCK_ConstructorCall,
605ffd83dbSDimitry Andric   /// Checking the operand of a static_cast to a derived pointer type. Must be
615ffd83dbSDimitry Andric   /// null or an object within its lifetime.
625ffd83dbSDimitry Andric   TCK_DowncastPointer,
635ffd83dbSDimitry Andric   /// Checking the operand of a static_cast to a derived reference type. Must
645ffd83dbSDimitry Andric   /// be an object within its lifetime.
655ffd83dbSDimitry Andric   TCK_DowncastReference,
665ffd83dbSDimitry Andric   /// Checking the operand of a cast to a base object. Must be suitably sized
675ffd83dbSDimitry Andric   /// and aligned.
685ffd83dbSDimitry Andric   TCK_Upcast,
695ffd83dbSDimitry Andric   /// Checking the operand of a cast to a virtual base object. Must be an
705ffd83dbSDimitry Andric   /// object within its lifetime.
715ffd83dbSDimitry Andric   TCK_UpcastToVirtualBase,
725ffd83dbSDimitry Andric   /// Checking the value assigned to a _Nonnull pointer. Must not be null.
735ffd83dbSDimitry Andric   TCK_NonnullAssign,
745ffd83dbSDimitry Andric   /// Checking the operand of a dynamic_cast or a typeid expression.  Must be
755ffd83dbSDimitry Andric   /// null or an object within its lifetime.
765ffd83dbSDimitry Andric   TCK_DynamicOperation
775ffd83dbSDimitry Andric };
785ffd83dbSDimitry Andric 
79bdd1243dSDimitry Andric extern const char *const TypeCheckKinds[] = {
8068d75effSDimitry Andric     "load of", "store to", "reference binding to", "member access within",
8168d75effSDimitry Andric     "member call on", "constructor call on", "downcast of", "downcast of",
8268d75effSDimitry Andric     "upcast of", "cast to virtual base of", "_Nonnull binding to",
8368d75effSDimitry Andric     "dynamic operation on"};
8468d75effSDimitry Andric }
8568d75effSDimitry Andric 
8668d75effSDimitry Andric static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
8768d75effSDimitry Andric                                    ReportOptions Opts) {
8868d75effSDimitry Andric   Location Loc = Data->Loc.acquire();
8968d75effSDimitry Andric 
9068d75effSDimitry Andric   uptr Alignment = (uptr)1 << Data->LogAlignment;
9168d75effSDimitry Andric   ErrorType ET;
9268d75effSDimitry Andric   if (!Pointer)
935ffd83dbSDimitry Andric     ET = (Data->TypeCheckKind == TCK_NonnullAssign)
945ffd83dbSDimitry Andric              ? ErrorType::NullPointerUseWithNullability
955ffd83dbSDimitry Andric              : ErrorType::NullPointerUse;
9668d75effSDimitry Andric   else if (Pointer & (Alignment - 1))
9768d75effSDimitry Andric     ET = ErrorType::MisalignedPointerUse;
9868d75effSDimitry Andric   else
9968d75effSDimitry Andric     ET = ErrorType::InsufficientObjectSize;
10068d75effSDimitry Andric 
10168d75effSDimitry Andric   // Use the SourceLocation from Data to track deduplication, even if it's
10268d75effSDimitry Andric   // invalid.
10368d75effSDimitry Andric   if (ignoreReport(Loc.getSourceLocation(), Opts, ET))
10468d75effSDimitry Andric     return;
10568d75effSDimitry Andric 
10668d75effSDimitry Andric   SymbolizedStackHolder FallbackLoc;
10768d75effSDimitry Andric   if (Data->Loc.isInvalid()) {
10868d75effSDimitry Andric     FallbackLoc.reset(getCallerLocation(Opts.pc));
10968d75effSDimitry Andric     Loc = FallbackLoc;
11068d75effSDimitry Andric   }
11168d75effSDimitry Andric 
11268d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
11368d75effSDimitry Andric 
11468d75effSDimitry Andric   switch (ET) {
11568d75effSDimitry Andric   case ErrorType::NullPointerUse:
1165ffd83dbSDimitry Andric   case ErrorType::NullPointerUseWithNullability:
11768d75effSDimitry Andric     Diag(Loc, DL_Error, ET, "%0 null pointer of type %1")
11868d75effSDimitry Andric         << TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
11968d75effSDimitry Andric     break;
12068d75effSDimitry Andric   case ErrorType::MisalignedPointerUse:
12168d75effSDimitry Andric     Diag(Loc, DL_Error, ET, "%0 misaligned address %1 for type %3, "
12268d75effSDimitry Andric                         "which requires %2 byte alignment")
12368d75effSDimitry Andric         << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Alignment
12468d75effSDimitry Andric         << Data->Type;
12568d75effSDimitry Andric     break;
12668d75effSDimitry Andric   case ErrorType::InsufficientObjectSize:
12768d75effSDimitry Andric     Diag(Loc, DL_Error, ET, "%0 address %1 with insufficient space "
12868d75effSDimitry Andric                         "for an object of type %2")
12968d75effSDimitry Andric         << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Data->Type;
13068d75effSDimitry Andric     break;
13168d75effSDimitry Andric   default:
13268d75effSDimitry Andric     UNREACHABLE("unexpected error type!");
13368d75effSDimitry Andric   }
13468d75effSDimitry Andric 
13568d75effSDimitry Andric   if (Pointer)
13668d75effSDimitry Andric     Diag(Pointer, DL_Note, ET, "pointer points here");
13768d75effSDimitry Andric }
13868d75effSDimitry Andric 
13968d75effSDimitry Andric void __ubsan::__ubsan_handle_type_mismatch_v1(TypeMismatchData *Data,
14068d75effSDimitry Andric                                               ValueHandle Pointer) {
14168d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
14268d75effSDimitry Andric   handleTypeMismatchImpl(Data, Pointer, Opts);
14368d75effSDimitry Andric }
14468d75effSDimitry Andric void __ubsan::__ubsan_handle_type_mismatch_v1_abort(TypeMismatchData *Data,
14568d75effSDimitry Andric                                                     ValueHandle Pointer) {
14668d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
14768d75effSDimitry Andric   handleTypeMismatchImpl(Data, Pointer, Opts);
14868d75effSDimitry Andric   Die();
14968d75effSDimitry Andric }
15068d75effSDimitry Andric 
15168d75effSDimitry Andric static void handleAlignmentAssumptionImpl(AlignmentAssumptionData *Data,
15268d75effSDimitry Andric                                           ValueHandle Pointer,
15368d75effSDimitry Andric                                           ValueHandle Alignment,
15468d75effSDimitry Andric                                           ValueHandle Offset,
15568d75effSDimitry Andric                                           ReportOptions Opts) {
15668d75effSDimitry Andric   Location Loc = Data->Loc.acquire();
15768d75effSDimitry Andric   SourceLocation AssumptionLoc = Data->AssumptionLoc.acquire();
15868d75effSDimitry Andric 
15968d75effSDimitry Andric   ErrorType ET = ErrorType::AlignmentAssumption;
16068d75effSDimitry Andric 
16168d75effSDimitry Andric   if (ignoreReport(Loc.getSourceLocation(), Opts, ET))
16268d75effSDimitry Andric     return;
16368d75effSDimitry Andric 
16468d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
16568d75effSDimitry Andric 
16668d75effSDimitry Andric   uptr RealPointer = Pointer - Offset;
16768d75effSDimitry Andric   uptr LSB = LeastSignificantSetBitIndex(RealPointer);
16868d75effSDimitry Andric   uptr ActualAlignment = uptr(1) << LSB;
16968d75effSDimitry Andric 
17068d75effSDimitry Andric   uptr Mask = Alignment - 1;
17168d75effSDimitry Andric   uptr MisAlignmentOffset = RealPointer & Mask;
17268d75effSDimitry Andric 
17368d75effSDimitry Andric   if (!Offset) {
17468d75effSDimitry Andric     Diag(Loc, DL_Error, ET,
17568d75effSDimitry Andric          "assumption of %0 byte alignment for pointer of type %1 failed")
17668d75effSDimitry Andric         << Alignment << Data->Type;
17768d75effSDimitry Andric   } else {
17868d75effSDimitry Andric     Diag(Loc, DL_Error, ET,
17968d75effSDimitry Andric          "assumption of %0 byte alignment (with offset of %1 byte) for pointer "
18068d75effSDimitry Andric          "of type %2 failed")
18168d75effSDimitry Andric         << Alignment << Offset << Data->Type;
18268d75effSDimitry Andric   }
18368d75effSDimitry Andric 
18468d75effSDimitry Andric   if (!AssumptionLoc.isInvalid())
18568d75effSDimitry Andric     Diag(AssumptionLoc, DL_Note, ET, "alignment assumption was specified here");
18668d75effSDimitry Andric 
18768d75effSDimitry Andric   Diag(RealPointer, DL_Note, ET,
18868d75effSDimitry Andric        "%0address is %1 aligned, misalignment offset is %2 bytes")
18968d75effSDimitry Andric       << (Offset ? "offset " : "") << ActualAlignment << MisAlignmentOffset;
19068d75effSDimitry Andric }
19168d75effSDimitry Andric 
19268d75effSDimitry Andric void __ubsan::__ubsan_handle_alignment_assumption(AlignmentAssumptionData *Data,
19368d75effSDimitry Andric                                                   ValueHandle Pointer,
19468d75effSDimitry Andric                                                   ValueHandle Alignment,
19568d75effSDimitry Andric                                                   ValueHandle Offset) {
19668d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
19768d75effSDimitry Andric   handleAlignmentAssumptionImpl(Data, Pointer, Alignment, Offset, Opts);
19868d75effSDimitry Andric }
19968d75effSDimitry Andric void __ubsan::__ubsan_handle_alignment_assumption_abort(
20068d75effSDimitry Andric     AlignmentAssumptionData *Data, ValueHandle Pointer, ValueHandle Alignment,
20168d75effSDimitry Andric     ValueHandle Offset) {
20268d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
20368d75effSDimitry Andric   handleAlignmentAssumptionImpl(Data, Pointer, Alignment, Offset, Opts);
20468d75effSDimitry Andric   Die();
20568d75effSDimitry Andric }
20668d75effSDimitry Andric 
20768d75effSDimitry Andric /// \brief Common diagnostic emission for various forms of integer overflow.
20868d75effSDimitry Andric template <typename T>
20968d75effSDimitry Andric static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS,
21068d75effSDimitry Andric                                       const char *Operator, T RHS,
21168d75effSDimitry Andric                                       ReportOptions Opts) {
21268d75effSDimitry Andric   SourceLocation Loc = Data->Loc.acquire();
21368d75effSDimitry Andric   bool IsSigned = Data->Type.isSignedIntegerTy();
21468d75effSDimitry Andric   ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow
21568d75effSDimitry Andric                           : ErrorType::UnsignedIntegerOverflow;
21668d75effSDimitry Andric 
21768d75effSDimitry Andric   if (ignoreReport(Loc, Opts, ET))
21868d75effSDimitry Andric     return;
21968d75effSDimitry Andric 
22068d75effSDimitry Andric   // If this is an unsigned overflow in non-fatal mode, potentially ignore it.
22168d75effSDimitry Andric   if (!IsSigned && !Opts.FromUnrecoverableHandler &&
22268d75effSDimitry Andric       flags()->silence_unsigned_overflow)
22368d75effSDimitry Andric     return;
22468d75effSDimitry Andric 
22568d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
22668d75effSDimitry Andric 
22768d75effSDimitry Andric   Diag(Loc, DL_Error, ET, "%0 integer overflow: "
22868d75effSDimitry Andric                           "%1 %2 %3 cannot be represented in type %4")
22968d75effSDimitry Andric       << (IsSigned ? "signed" : "unsigned") << Value(Data->Type, LHS)
23068d75effSDimitry Andric       << Operator << RHS << Data->Type;
23168d75effSDimitry Andric }
23268d75effSDimitry Andric 
23368d75effSDimitry Andric #define UBSAN_OVERFLOW_HANDLER(handler_name, op, unrecoverable)                \
23468d75effSDimitry Andric   void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS,              \
23568d75effSDimitry Andric                              ValueHandle RHS) {                                \
23668d75effSDimitry Andric     GET_REPORT_OPTIONS(unrecoverable);                                         \
23768d75effSDimitry Andric     handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts);    \
23868d75effSDimitry Andric     if (unrecoverable)                                                         \
23968d75effSDimitry Andric       Die();                                                                   \
24068d75effSDimitry Andric   }
24168d75effSDimitry Andric 
24268d75effSDimitry Andric UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false)
24368d75effSDimitry Andric UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow_abort, "+", true)
24468d75effSDimitry Andric UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "-", false)
24568d75effSDimitry Andric UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow_abort, "-", true)
24668d75effSDimitry Andric UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "*", false)
24768d75effSDimitry Andric UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true)
24868d75effSDimitry Andric 
24968d75effSDimitry Andric static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal,
25068d75effSDimitry Andric                                      ReportOptions Opts) {
25168d75effSDimitry Andric   SourceLocation Loc = Data->Loc.acquire();
25268d75effSDimitry Andric   bool IsSigned = Data->Type.isSignedIntegerTy();
25368d75effSDimitry Andric   ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow
25468d75effSDimitry Andric                           : ErrorType::UnsignedIntegerOverflow;
25568d75effSDimitry Andric 
25668d75effSDimitry Andric   if (ignoreReport(Loc, Opts, ET))
25768d75effSDimitry Andric     return;
25868d75effSDimitry Andric 
25968d75effSDimitry Andric   if (!IsSigned && flags()->silence_unsigned_overflow)
26068d75effSDimitry Andric     return;
26168d75effSDimitry Andric 
26268d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
26368d75effSDimitry Andric 
26468d75effSDimitry Andric   if (IsSigned)
26568d75effSDimitry Andric     Diag(Loc, DL_Error, ET,
26668d75effSDimitry Andric          "negation of %0 cannot be represented in type %1; "
26768d75effSDimitry Andric          "cast to an unsigned type to negate this value to itself")
26868d75effSDimitry Andric         << Value(Data->Type, OldVal) << Data->Type;
26968d75effSDimitry Andric   else
27068d75effSDimitry Andric     Diag(Loc, DL_Error, ET, "negation of %0 cannot be represented in type %1")
27168d75effSDimitry Andric         << Value(Data->Type, OldVal) << Data->Type;
27268d75effSDimitry Andric }
27368d75effSDimitry Andric 
27468d75effSDimitry Andric void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,
27568d75effSDimitry Andric                                              ValueHandle OldVal) {
27668d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
27768d75effSDimitry Andric   handleNegateOverflowImpl(Data, OldVal, Opts);
27868d75effSDimitry Andric }
27968d75effSDimitry Andric void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data,
28068d75effSDimitry Andric                                                     ValueHandle OldVal) {
28168d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
28268d75effSDimitry Andric   handleNegateOverflowImpl(Data, OldVal, Opts);
28368d75effSDimitry Andric   Die();
28468d75effSDimitry Andric }
28568d75effSDimitry Andric 
28668d75effSDimitry Andric static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS,
28768d75effSDimitry Andric                                      ValueHandle RHS, ReportOptions Opts) {
28868d75effSDimitry Andric   SourceLocation Loc = Data->Loc.acquire();
28968d75effSDimitry Andric   Value LHSVal(Data->Type, LHS);
29068d75effSDimitry Andric   Value RHSVal(Data->Type, RHS);
29168d75effSDimitry Andric 
29268d75effSDimitry Andric   ErrorType ET;
29368d75effSDimitry Andric   if (RHSVal.isMinusOne())
29468d75effSDimitry Andric     ET = ErrorType::SignedIntegerOverflow;
29568d75effSDimitry Andric   else if (Data->Type.isIntegerTy())
29668d75effSDimitry Andric     ET = ErrorType::IntegerDivideByZero;
29768d75effSDimitry Andric   else
29868d75effSDimitry Andric     ET = ErrorType::FloatDivideByZero;
29968d75effSDimitry Andric 
30068d75effSDimitry Andric   if (ignoreReport(Loc, Opts, ET))
30168d75effSDimitry Andric     return;
30268d75effSDimitry Andric 
30368d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
30468d75effSDimitry Andric 
30568d75effSDimitry Andric   switch (ET) {
30668d75effSDimitry Andric   case ErrorType::SignedIntegerOverflow:
30768d75effSDimitry Andric     Diag(Loc, DL_Error, ET,
30868d75effSDimitry Andric          "division of %0 by -1 cannot be represented in type %1")
30968d75effSDimitry Andric         << LHSVal << Data->Type;
31068d75effSDimitry Andric     break;
31168d75effSDimitry Andric   default:
31268d75effSDimitry Andric     Diag(Loc, DL_Error, ET, "division by zero");
31368d75effSDimitry Andric     break;
31468d75effSDimitry Andric   }
31568d75effSDimitry Andric }
31668d75effSDimitry Andric 
31768d75effSDimitry Andric void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data,
31868d75effSDimitry Andric                                              ValueHandle LHS, ValueHandle RHS) {
31968d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
32068d75effSDimitry Andric   handleDivremOverflowImpl(Data, LHS, RHS, Opts);
32168d75effSDimitry Andric }
32268d75effSDimitry Andric void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data,
32368d75effSDimitry Andric                                                     ValueHandle LHS,
32468d75effSDimitry Andric                                                     ValueHandle RHS) {
32568d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
32668d75effSDimitry Andric   handleDivremOverflowImpl(Data, LHS, RHS, Opts);
32768d75effSDimitry Andric   Die();
32868d75effSDimitry Andric }
32968d75effSDimitry Andric 
33068d75effSDimitry Andric static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data,
33168d75effSDimitry Andric                                        ValueHandle LHS, ValueHandle RHS,
33268d75effSDimitry Andric                                        ReportOptions Opts) {
33368d75effSDimitry Andric   SourceLocation Loc = Data->Loc.acquire();
33468d75effSDimitry Andric   Value LHSVal(Data->LHSType, LHS);
33568d75effSDimitry Andric   Value RHSVal(Data->RHSType, RHS);
33668d75effSDimitry Andric 
33768d75effSDimitry Andric   ErrorType ET;
33868d75effSDimitry Andric   if (RHSVal.isNegative() ||
33968d75effSDimitry Andric       RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth())
34068d75effSDimitry Andric     ET = ErrorType::InvalidShiftExponent;
34168d75effSDimitry Andric   else
34268d75effSDimitry Andric     ET = ErrorType::InvalidShiftBase;
34368d75effSDimitry Andric 
34468d75effSDimitry Andric   if (ignoreReport(Loc, Opts, ET))
34568d75effSDimitry Andric     return;
34668d75effSDimitry Andric 
34768d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
34868d75effSDimitry Andric 
34968d75effSDimitry Andric   if (ET == ErrorType::InvalidShiftExponent) {
35068d75effSDimitry Andric     if (RHSVal.isNegative())
35168d75effSDimitry Andric       Diag(Loc, DL_Error, ET, "shift exponent %0 is negative") << RHSVal;
35268d75effSDimitry Andric     else
35368d75effSDimitry Andric       Diag(Loc, DL_Error, ET,
35468d75effSDimitry Andric            "shift exponent %0 is too large for %1-bit type %2")
35568d75effSDimitry Andric           << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType;
35668d75effSDimitry Andric   } else {
35768d75effSDimitry Andric     if (LHSVal.isNegative())
35868d75effSDimitry Andric       Diag(Loc, DL_Error, ET, "left shift of negative value %0") << LHSVal;
35968d75effSDimitry Andric     else
36068d75effSDimitry Andric       Diag(Loc, DL_Error, ET,
36168d75effSDimitry Andric            "left shift of %0 by %1 places cannot be represented in type %2")
36268d75effSDimitry Andric           << LHSVal << RHSVal << Data->LHSType;
36368d75effSDimitry Andric   }
36468d75effSDimitry Andric }
36568d75effSDimitry Andric 
36668d75effSDimitry Andric void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,
36768d75effSDimitry Andric                                                  ValueHandle LHS,
36868d75effSDimitry Andric                                                  ValueHandle RHS) {
36968d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
37068d75effSDimitry Andric   handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);
37168d75effSDimitry Andric }
37268d75effSDimitry Andric void __ubsan::__ubsan_handle_shift_out_of_bounds_abort(
37368d75effSDimitry Andric                                                      ShiftOutOfBoundsData *Data,
37468d75effSDimitry Andric                                                      ValueHandle LHS,
37568d75effSDimitry Andric                                                      ValueHandle RHS) {
37668d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
37768d75effSDimitry Andric   handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);
37868d75effSDimitry Andric   Die();
37968d75effSDimitry Andric }
38068d75effSDimitry Andric 
38168d75effSDimitry Andric static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,
38268d75effSDimitry Andric                                   ReportOptions Opts) {
38368d75effSDimitry Andric   SourceLocation Loc = Data->Loc.acquire();
38468d75effSDimitry Andric   ErrorType ET = ErrorType::OutOfBoundsIndex;
38568d75effSDimitry Andric 
38668d75effSDimitry Andric   if (ignoreReport(Loc, Opts, ET))
38768d75effSDimitry Andric     return;
38868d75effSDimitry Andric 
38968d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
39068d75effSDimitry Andric 
39168d75effSDimitry Andric   Value IndexVal(Data->IndexType, Index);
39268d75effSDimitry Andric   Diag(Loc, DL_Error, ET, "index %0 out of bounds for type %1")
39368d75effSDimitry Andric     << IndexVal << Data->ArrayType;
39468d75effSDimitry Andric }
39568d75effSDimitry Andric 
39668d75effSDimitry Andric void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data,
39768d75effSDimitry Andric                                            ValueHandle Index) {
39868d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
39968d75effSDimitry Andric   handleOutOfBoundsImpl(Data, Index, Opts);
40068d75effSDimitry Andric }
40168d75effSDimitry Andric void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data,
40268d75effSDimitry Andric                                                  ValueHandle Index) {
40368d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
40468d75effSDimitry Andric   handleOutOfBoundsImpl(Data, Index, Opts);
40568d75effSDimitry Andric   Die();
40668d75effSDimitry Andric }
40768d75effSDimitry Andric 
40868d75effSDimitry Andric static void handleBuiltinUnreachableImpl(UnreachableData *Data,
40968d75effSDimitry Andric                                          ReportOptions Opts) {
41068d75effSDimitry Andric   ErrorType ET = ErrorType::UnreachableCall;
41168d75effSDimitry Andric   ScopedReport R(Opts, Data->Loc, ET);
41268d75effSDimitry Andric   Diag(Data->Loc, DL_Error, ET,
41368d75effSDimitry Andric        "execution reached an unreachable program point");
41468d75effSDimitry Andric }
41568d75effSDimitry Andric 
41668d75effSDimitry Andric void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {
41768d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
41868d75effSDimitry Andric   handleBuiltinUnreachableImpl(Data, Opts);
41968d75effSDimitry Andric   Die();
42068d75effSDimitry Andric }
42168d75effSDimitry Andric 
42268d75effSDimitry Andric static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) {
42368d75effSDimitry Andric   ErrorType ET = ErrorType::MissingReturn;
42468d75effSDimitry Andric   ScopedReport R(Opts, Data->Loc, ET);
42568d75effSDimitry Andric   Diag(Data->Loc, DL_Error, ET,
42668d75effSDimitry Andric        "execution reached the end of a value-returning function "
42768d75effSDimitry Andric        "without returning a value");
42868d75effSDimitry Andric }
42968d75effSDimitry Andric 
43068d75effSDimitry Andric void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {
43168d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
43268d75effSDimitry Andric   handleMissingReturnImpl(Data, Opts);
43368d75effSDimitry Andric   Die();
43468d75effSDimitry Andric }
43568d75effSDimitry Andric 
43668d75effSDimitry Andric static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,
43768d75effSDimitry Andric                                       ReportOptions Opts) {
43868d75effSDimitry Andric   SourceLocation Loc = Data->Loc.acquire();
43968d75effSDimitry Andric   ErrorType ET = ErrorType::NonPositiveVLAIndex;
44068d75effSDimitry Andric 
44168d75effSDimitry Andric   if (ignoreReport(Loc, Opts, ET))
44268d75effSDimitry Andric     return;
44368d75effSDimitry Andric 
44468d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
44568d75effSDimitry Andric 
44668d75effSDimitry Andric   Diag(Loc, DL_Error, ET, "variable length array bound evaluates to "
44768d75effSDimitry Andric                           "non-positive value %0")
44868d75effSDimitry Andric       << Value(Data->Type, Bound);
44968d75effSDimitry Andric }
45068d75effSDimitry Andric 
45168d75effSDimitry Andric void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data,
45268d75effSDimitry Andric                                                     ValueHandle Bound) {
45368d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
45468d75effSDimitry Andric   handleVLABoundNotPositive(Data, Bound, Opts);
45568d75effSDimitry Andric }
45668d75effSDimitry Andric void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data,
45768d75effSDimitry Andric                                                           ValueHandle Bound) {
45868d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
45968d75effSDimitry Andric   handleVLABoundNotPositive(Data, Bound, Opts);
46068d75effSDimitry Andric   Die();
46168d75effSDimitry Andric }
46268d75effSDimitry Andric 
46368d75effSDimitry Andric static bool looksLikeFloatCastOverflowDataV1(void *Data) {
46468d75effSDimitry Andric   // First field is either a pointer to filename or a pointer to a
46568d75effSDimitry Andric   // TypeDescriptor.
46668d75effSDimitry Andric   u8 *FilenameOrTypeDescriptor;
46768d75effSDimitry Andric   internal_memcpy(&FilenameOrTypeDescriptor, Data,
46868d75effSDimitry Andric                   sizeof(FilenameOrTypeDescriptor));
46968d75effSDimitry Andric 
47068d75effSDimitry Andric   // Heuristic: For float_cast_overflow, the TypeKind will be either TK_Integer
47168d75effSDimitry Andric   // (0x0), TK_Float (0x1) or TK_Unknown (0xff). If both types are known,
47268d75effSDimitry Andric   // adding both bytes will be 0 or 1 (for BE or LE). If it were a filename,
47368d75effSDimitry Andric   // adding two printable characters will not yield such a value. Otherwise,
47468d75effSDimitry Andric   // if one of them is 0xff, this is most likely TK_Unknown type descriptor.
47568d75effSDimitry Andric   u16 MaybeFromTypeKind =
47668d75effSDimitry Andric       FilenameOrTypeDescriptor[0] + FilenameOrTypeDescriptor[1];
47768d75effSDimitry Andric   return MaybeFromTypeKind < 2 || FilenameOrTypeDescriptor[0] == 0xff ||
47868d75effSDimitry Andric          FilenameOrTypeDescriptor[1] == 0xff;
47968d75effSDimitry Andric }
48068d75effSDimitry Andric 
48168d75effSDimitry Andric static void handleFloatCastOverflow(void *DataPtr, ValueHandle From,
48268d75effSDimitry Andric                                     ReportOptions Opts) {
48368d75effSDimitry Andric   SymbolizedStackHolder CallerLoc;
48468d75effSDimitry Andric   Location Loc;
48568d75effSDimitry Andric   const TypeDescriptor *FromType, *ToType;
48668d75effSDimitry Andric   ErrorType ET = ErrorType::FloatCastOverflow;
48768d75effSDimitry Andric 
48868d75effSDimitry Andric   if (looksLikeFloatCastOverflowDataV1(DataPtr)) {
48968d75effSDimitry Andric     auto Data = reinterpret_cast<FloatCastOverflowData *>(DataPtr);
49068d75effSDimitry Andric     CallerLoc.reset(getCallerLocation(Opts.pc));
49168d75effSDimitry Andric     Loc = CallerLoc;
49268d75effSDimitry Andric     FromType = &Data->FromType;
49368d75effSDimitry Andric     ToType = &Data->ToType;
49468d75effSDimitry Andric   } else {
49568d75effSDimitry Andric     auto Data = reinterpret_cast<FloatCastOverflowDataV2 *>(DataPtr);
49668d75effSDimitry Andric     SourceLocation SLoc = Data->Loc.acquire();
49768d75effSDimitry Andric     if (ignoreReport(SLoc, Opts, ET))
49868d75effSDimitry Andric       return;
49968d75effSDimitry Andric     Loc = SLoc;
50068d75effSDimitry Andric     FromType = &Data->FromType;
50168d75effSDimitry Andric     ToType = &Data->ToType;
50268d75effSDimitry Andric   }
50368d75effSDimitry Andric 
50468d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
50568d75effSDimitry Andric 
50668d75effSDimitry Andric   Diag(Loc, DL_Error, ET,
50768d75effSDimitry Andric        "%0 is outside the range of representable values of type %2")
50868d75effSDimitry Andric       << Value(*FromType, From) << *FromType << *ToType;
50968d75effSDimitry Andric }
51068d75effSDimitry Andric 
51168d75effSDimitry Andric void __ubsan::__ubsan_handle_float_cast_overflow(void *Data, ValueHandle From) {
51268d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
51368d75effSDimitry Andric   handleFloatCastOverflow(Data, From, Opts);
51468d75effSDimitry Andric }
51568d75effSDimitry Andric void __ubsan::__ubsan_handle_float_cast_overflow_abort(void *Data,
51668d75effSDimitry Andric                                                        ValueHandle From) {
51768d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
51868d75effSDimitry Andric   handleFloatCastOverflow(Data, From, Opts);
51968d75effSDimitry Andric   Die();
52068d75effSDimitry Andric }
52168d75effSDimitry Andric 
52268d75effSDimitry Andric static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,
52368d75effSDimitry Andric                                    ReportOptions Opts) {
52468d75effSDimitry Andric   SourceLocation Loc = Data->Loc.acquire();
52568d75effSDimitry Andric   // This check could be more precise if we used different handlers for
52668d75effSDimitry Andric   // -fsanitize=bool and -fsanitize=enum.
52768d75effSDimitry Andric   bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'")) ||
52868d75effSDimitry Andric                 (0 == internal_strncmp(Data->Type.getTypeName(), "'BOOL'", 6));
52968d75effSDimitry Andric   ErrorType ET =
53068d75effSDimitry Andric       IsBool ? ErrorType::InvalidBoolLoad : ErrorType::InvalidEnumLoad;
53168d75effSDimitry Andric 
53268d75effSDimitry Andric   if (ignoreReport(Loc, Opts, ET))
53368d75effSDimitry Andric     return;
53468d75effSDimitry Andric 
53568d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
53668d75effSDimitry Andric 
53768d75effSDimitry Andric   Diag(Loc, DL_Error, ET,
53868d75effSDimitry Andric        "load of value %0, which is not a valid value for type %1")
53968d75effSDimitry Andric       << Value(Data->Type, Val) << Data->Type;
54068d75effSDimitry Andric }
54168d75effSDimitry Andric 
54268d75effSDimitry Andric void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,
54368d75effSDimitry Andric                                                 ValueHandle Val) {
54468d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
54568d75effSDimitry Andric   handleLoadInvalidValue(Data, Val, Opts);
54668d75effSDimitry Andric }
54768d75effSDimitry Andric void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data,
54868d75effSDimitry Andric                                                       ValueHandle Val) {
54968d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
55068d75effSDimitry Andric   handleLoadInvalidValue(Data, Val, Opts);
55168d75effSDimitry Andric   Die();
55268d75effSDimitry Andric }
55368d75effSDimitry Andric 
55468d75effSDimitry Andric static void handleImplicitConversion(ImplicitConversionData *Data,
55568d75effSDimitry Andric                                      ReportOptions Opts, ValueHandle Src,
55668d75effSDimitry Andric                                      ValueHandle Dst) {
55768d75effSDimitry Andric   SourceLocation Loc = Data->Loc.acquire();
55868d75effSDimitry Andric   const TypeDescriptor &SrcTy = Data->FromType;
55968d75effSDimitry Andric   const TypeDescriptor &DstTy = Data->ToType;
56068d75effSDimitry Andric   bool SrcSigned = SrcTy.isSignedIntegerTy();
56168d75effSDimitry Andric   bool DstSigned = DstTy.isSignedIntegerTy();
562*0fca6ea1SDimitry Andric   ErrorType ET = ErrorType::GenericUB;
56368d75effSDimitry Andric 
56468d75effSDimitry Andric   switch (Data->Kind) {
56568d75effSDimitry Andric   case ICCK_IntegerTruncation: { // Legacy, no longer used.
56668d75effSDimitry Andric     // Let's figure out what it should be as per the new types, and upgrade.
56768d75effSDimitry Andric     // If both types are unsigned, then it's an unsigned truncation.
56868d75effSDimitry Andric     // Else, it is a signed truncation.
56968d75effSDimitry Andric     if (!SrcSigned && !DstSigned) {
57068d75effSDimitry Andric       ET = ErrorType::ImplicitUnsignedIntegerTruncation;
57168d75effSDimitry Andric     } else {
57268d75effSDimitry Andric       ET = ErrorType::ImplicitSignedIntegerTruncation;
57368d75effSDimitry Andric     }
57468d75effSDimitry Andric     break;
57568d75effSDimitry Andric   }
57668d75effSDimitry Andric   case ICCK_UnsignedIntegerTruncation:
57768d75effSDimitry Andric     ET = ErrorType::ImplicitUnsignedIntegerTruncation;
57868d75effSDimitry Andric     break;
57968d75effSDimitry Andric   case ICCK_SignedIntegerTruncation:
58068d75effSDimitry Andric     ET = ErrorType::ImplicitSignedIntegerTruncation;
58168d75effSDimitry Andric     break;
58268d75effSDimitry Andric   case ICCK_IntegerSignChange:
58368d75effSDimitry Andric     ET = ErrorType::ImplicitIntegerSignChange;
58468d75effSDimitry Andric     break;
58568d75effSDimitry Andric   case ICCK_SignedIntegerTruncationOrSignChange:
58668d75effSDimitry Andric     ET = ErrorType::ImplicitSignedIntegerTruncationOrSignChange;
58768d75effSDimitry Andric     break;
58868d75effSDimitry Andric   }
58968d75effSDimitry Andric 
59068d75effSDimitry Andric   if (ignoreReport(Loc, Opts, ET))
59168d75effSDimitry Andric     return;
59268d75effSDimitry Andric 
59368d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
59468d75effSDimitry Andric 
595*0fca6ea1SDimitry Andric   // In the case we have a bitfield, we want to explicitly say so in the
596*0fca6ea1SDimitry Andric   // error message.
59768d75effSDimitry Andric   // FIXME: is it possible to dump the values as hex with fixed width?
598*0fca6ea1SDimitry Andric   if (Data->BitfieldBits)
599*0fca6ea1SDimitry Andric     Diag(Loc, DL_Error, ET,
600*0fca6ea1SDimitry Andric          "implicit conversion from type %0 of value %1 (%2-bit, %3signed) to "
601*0fca6ea1SDimitry Andric          "type %4 changed the value to %5 (%6-bit bitfield, %7signed)")
602*0fca6ea1SDimitry Andric         << SrcTy << Value(SrcTy, Src) << SrcTy.getIntegerBitWidth()
603*0fca6ea1SDimitry Andric         << (SrcSigned ? "" : "un") << DstTy << Value(DstTy, Dst)
604*0fca6ea1SDimitry Andric         << Data->BitfieldBits << (DstSigned ? "" : "un");
605*0fca6ea1SDimitry Andric   else
60668d75effSDimitry Andric     Diag(Loc, DL_Error, ET,
60768d75effSDimitry Andric          "implicit conversion from type %0 of value %1 (%2-bit, %3signed) to "
60868d75effSDimitry Andric          "type %4 changed the value to %5 (%6-bit, %7signed)")
60968d75effSDimitry Andric         << SrcTy << Value(SrcTy, Src) << SrcTy.getIntegerBitWidth()
61068d75effSDimitry Andric         << (SrcSigned ? "" : "un") << DstTy << Value(DstTy, Dst)
61168d75effSDimitry Andric         << DstTy.getIntegerBitWidth() << (DstSigned ? "" : "un");
61268d75effSDimitry Andric }
61368d75effSDimitry Andric 
61468d75effSDimitry Andric void __ubsan::__ubsan_handle_implicit_conversion(ImplicitConversionData *Data,
61568d75effSDimitry Andric                                                  ValueHandle Src,
61668d75effSDimitry Andric                                                  ValueHandle Dst) {
61768d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
61868d75effSDimitry Andric   handleImplicitConversion(Data, Opts, Src, Dst);
61968d75effSDimitry Andric }
62068d75effSDimitry Andric void __ubsan::__ubsan_handle_implicit_conversion_abort(
62168d75effSDimitry Andric     ImplicitConversionData *Data, ValueHandle Src, ValueHandle Dst) {
62268d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
62368d75effSDimitry Andric   handleImplicitConversion(Data, Opts, Src, Dst);
62468d75effSDimitry Andric   Die();
62568d75effSDimitry Andric }
62668d75effSDimitry Andric 
62768d75effSDimitry Andric static void handleInvalidBuiltin(InvalidBuiltinData *Data, ReportOptions Opts) {
62868d75effSDimitry Andric   SourceLocation Loc = Data->Loc.acquire();
62968d75effSDimitry Andric   ErrorType ET = ErrorType::InvalidBuiltin;
63068d75effSDimitry Andric 
63168d75effSDimitry Andric   if (ignoreReport(Loc, Opts, ET))
63268d75effSDimitry Andric     return;
63368d75effSDimitry Andric 
63468d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
63568d75effSDimitry Andric 
63668d75effSDimitry Andric   Diag(Loc, DL_Error, ET,
63768d75effSDimitry Andric        "passing zero to %0, which is not a valid argument")
63868d75effSDimitry Andric     << ((Data->Kind == BCK_CTZPassedZero) ? "ctz()" : "clz()");
63968d75effSDimitry Andric }
64068d75effSDimitry Andric 
64168d75effSDimitry Andric void __ubsan::__ubsan_handle_invalid_builtin(InvalidBuiltinData *Data) {
64268d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
64368d75effSDimitry Andric   handleInvalidBuiltin(Data, Opts);
64468d75effSDimitry Andric }
64568d75effSDimitry Andric void __ubsan::__ubsan_handle_invalid_builtin_abort(InvalidBuiltinData *Data) {
64668d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
64768d75effSDimitry Andric   handleInvalidBuiltin(Data, Opts);
64868d75effSDimitry Andric   Die();
64968d75effSDimitry Andric }
65068d75effSDimitry Andric 
6515ffd83dbSDimitry Andric static void handleInvalidObjCCast(InvalidObjCCast *Data, ValueHandle Pointer,
6525ffd83dbSDimitry Andric                                   ReportOptions Opts) {
6535ffd83dbSDimitry Andric   SourceLocation Loc = Data->Loc.acquire();
6545ffd83dbSDimitry Andric   ErrorType ET = ErrorType::InvalidObjCCast;
6555ffd83dbSDimitry Andric 
6565ffd83dbSDimitry Andric   if (ignoreReport(Loc, Opts, ET))
6575ffd83dbSDimitry Andric     return;
6585ffd83dbSDimitry Andric 
6595ffd83dbSDimitry Andric   ScopedReport R(Opts, Loc, ET);
6605ffd83dbSDimitry Andric 
6615ffd83dbSDimitry Andric   const char *GivenClass = getObjCClassName(Pointer);
6625ffd83dbSDimitry Andric   const char *GivenClassStr = GivenClass ? GivenClass : "<unknown type>";
6635ffd83dbSDimitry Andric 
6645ffd83dbSDimitry Andric   Diag(Loc, DL_Error, ET,
6655ffd83dbSDimitry Andric        "invalid ObjC cast, object is a '%0', but expected a %1")
6665ffd83dbSDimitry Andric       << GivenClassStr << Data->ExpectedType;
6675ffd83dbSDimitry Andric }
6685ffd83dbSDimitry Andric 
6695ffd83dbSDimitry Andric void __ubsan::__ubsan_handle_invalid_objc_cast(InvalidObjCCast *Data,
6705ffd83dbSDimitry Andric                                                ValueHandle Pointer) {
6715ffd83dbSDimitry Andric   GET_REPORT_OPTIONS(false);
6725ffd83dbSDimitry Andric   handleInvalidObjCCast(Data, Pointer, Opts);
6735ffd83dbSDimitry Andric }
6745ffd83dbSDimitry Andric void __ubsan::__ubsan_handle_invalid_objc_cast_abort(InvalidObjCCast *Data,
6755ffd83dbSDimitry Andric                                                      ValueHandle Pointer) {
6765ffd83dbSDimitry Andric   GET_REPORT_OPTIONS(true);
6775ffd83dbSDimitry Andric   handleInvalidObjCCast(Data, Pointer, Opts);
6785ffd83dbSDimitry Andric   Die();
6795ffd83dbSDimitry Andric }
6805ffd83dbSDimitry Andric 
68168d75effSDimitry Andric static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr,
68268d75effSDimitry Andric                                 ReportOptions Opts, bool IsAttr) {
68368d75effSDimitry Andric   if (!LocPtr)
68468d75effSDimitry Andric     UNREACHABLE("source location pointer is null!");
68568d75effSDimitry Andric 
68668d75effSDimitry Andric   SourceLocation Loc = LocPtr->acquire();
6875ffd83dbSDimitry Andric   ErrorType ET = IsAttr ? ErrorType::InvalidNullReturn
6885ffd83dbSDimitry Andric                         : ErrorType::InvalidNullReturnWithNullability;
68968d75effSDimitry Andric 
69068d75effSDimitry Andric   if (ignoreReport(Loc, Opts, ET))
69168d75effSDimitry Andric     return;
69268d75effSDimitry Andric 
69368d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
69468d75effSDimitry Andric 
69568d75effSDimitry Andric   Diag(Loc, DL_Error, ET,
69668d75effSDimitry Andric        "null pointer returned from function declared to never return null");
69768d75effSDimitry Andric   if (!Data->AttrLoc.isInvalid())
69868d75effSDimitry Andric     Diag(Data->AttrLoc, DL_Note, ET, "%0 specified here")
69968d75effSDimitry Andric         << (IsAttr ? "returns_nonnull attribute"
70068d75effSDimitry Andric                    : "_Nonnull return type annotation");
70168d75effSDimitry Andric }
70268d75effSDimitry Andric 
70368d75effSDimitry Andric void __ubsan::__ubsan_handle_nonnull_return_v1(NonNullReturnData *Data,
70468d75effSDimitry Andric                                                SourceLocation *LocPtr) {
70568d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
70668d75effSDimitry Andric   handleNonNullReturn(Data, LocPtr, Opts, true);
70768d75effSDimitry Andric }
70868d75effSDimitry Andric 
70968d75effSDimitry Andric void __ubsan::__ubsan_handle_nonnull_return_v1_abort(NonNullReturnData *Data,
71068d75effSDimitry Andric                                                      SourceLocation *LocPtr) {
71168d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
71268d75effSDimitry Andric   handleNonNullReturn(Data, LocPtr, Opts, true);
71368d75effSDimitry Andric   Die();
71468d75effSDimitry Andric }
71568d75effSDimitry Andric 
71668d75effSDimitry Andric void __ubsan::__ubsan_handle_nullability_return_v1(NonNullReturnData *Data,
71768d75effSDimitry Andric                                                    SourceLocation *LocPtr) {
71868d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
71968d75effSDimitry Andric   handleNonNullReturn(Data, LocPtr, Opts, false);
72068d75effSDimitry Andric }
72168d75effSDimitry Andric 
72268d75effSDimitry Andric void __ubsan::__ubsan_handle_nullability_return_v1_abort(
72368d75effSDimitry Andric     NonNullReturnData *Data, SourceLocation *LocPtr) {
72468d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
72568d75effSDimitry Andric   handleNonNullReturn(Data, LocPtr, Opts, false);
72668d75effSDimitry Andric   Die();
72768d75effSDimitry Andric }
72868d75effSDimitry Andric 
72968d75effSDimitry Andric static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts,
73068d75effSDimitry Andric                              bool IsAttr) {
73168d75effSDimitry Andric   SourceLocation Loc = Data->Loc.acquire();
7325ffd83dbSDimitry Andric   ErrorType ET = IsAttr ? ErrorType::InvalidNullArgument
7335ffd83dbSDimitry Andric                         : ErrorType::InvalidNullArgumentWithNullability;
73468d75effSDimitry Andric 
73568d75effSDimitry Andric   if (ignoreReport(Loc, Opts, ET))
73668d75effSDimitry Andric     return;
73768d75effSDimitry Andric 
73868d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
73968d75effSDimitry Andric 
74068d75effSDimitry Andric   Diag(Loc, DL_Error, ET,
74168d75effSDimitry Andric        "null pointer passed as argument %0, which is declared to "
74268d75effSDimitry Andric        "never be null")
74368d75effSDimitry Andric       << Data->ArgIndex;
74468d75effSDimitry Andric   if (!Data->AttrLoc.isInvalid())
74568d75effSDimitry Andric     Diag(Data->AttrLoc, DL_Note, ET, "%0 specified here")
74668d75effSDimitry Andric         << (IsAttr ? "nonnull attribute" : "_Nonnull type annotation");
74768d75effSDimitry Andric }
74868d75effSDimitry Andric 
74968d75effSDimitry Andric void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) {
75068d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
75168d75effSDimitry Andric   handleNonNullArg(Data, Opts, true);
75268d75effSDimitry Andric }
75368d75effSDimitry Andric 
75468d75effSDimitry Andric void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) {
75568d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
75668d75effSDimitry Andric   handleNonNullArg(Data, Opts, true);
75768d75effSDimitry Andric   Die();
75868d75effSDimitry Andric }
75968d75effSDimitry Andric 
76068d75effSDimitry Andric void __ubsan::__ubsan_handle_nullability_arg(NonNullArgData *Data) {
76168d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
76268d75effSDimitry Andric   handleNonNullArg(Data, Opts, false);
76368d75effSDimitry Andric }
76468d75effSDimitry Andric 
76568d75effSDimitry Andric void __ubsan::__ubsan_handle_nullability_arg_abort(NonNullArgData *Data) {
76668d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
76768d75effSDimitry Andric   handleNonNullArg(Data, Opts, false);
76868d75effSDimitry Andric   Die();
76968d75effSDimitry Andric }
77068d75effSDimitry Andric 
77168d75effSDimitry Andric static void handlePointerOverflowImpl(PointerOverflowData *Data,
77268d75effSDimitry Andric                                       ValueHandle Base,
77368d75effSDimitry Andric                                       ValueHandle Result,
77468d75effSDimitry Andric                                       ReportOptions Opts) {
77568d75effSDimitry Andric   SourceLocation Loc = Data->Loc.acquire();
77668d75effSDimitry Andric   ErrorType ET;
77768d75effSDimitry Andric 
77868d75effSDimitry Andric   if (Base == 0 && Result == 0)
77968d75effSDimitry Andric     ET = ErrorType::NullptrWithOffset;
78068d75effSDimitry Andric   else if (Base == 0 && Result != 0)
78168d75effSDimitry Andric     ET = ErrorType::NullptrWithNonZeroOffset;
78268d75effSDimitry Andric   else if (Base != 0 && Result == 0)
78368d75effSDimitry Andric     ET = ErrorType::NullptrAfterNonZeroOffset;
78468d75effSDimitry Andric   else
78568d75effSDimitry Andric     ET = ErrorType::PointerOverflow;
78668d75effSDimitry Andric 
78768d75effSDimitry Andric   if (ignoreReport(Loc, Opts, ET))
78868d75effSDimitry Andric     return;
78968d75effSDimitry Andric 
79068d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
79168d75effSDimitry Andric 
79268d75effSDimitry Andric   if (ET == ErrorType::NullptrWithOffset) {
79368d75effSDimitry Andric     Diag(Loc, DL_Error, ET, "applying zero offset to null pointer");
79468d75effSDimitry Andric   } else if (ET == ErrorType::NullptrWithNonZeroOffset) {
79568d75effSDimitry Andric     Diag(Loc, DL_Error, ET, "applying non-zero offset %0 to null pointer")
79668d75effSDimitry Andric         << Result;
79768d75effSDimitry Andric   } else if (ET == ErrorType::NullptrAfterNonZeroOffset) {
79868d75effSDimitry Andric     Diag(
79968d75effSDimitry Andric         Loc, DL_Error, ET,
80068d75effSDimitry Andric         "applying non-zero offset to non-null pointer %0 produced null pointer")
80168d75effSDimitry Andric         << (void *)Base;
80268d75effSDimitry Andric   } else if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) {
80368d75effSDimitry Andric     if (Base > Result)
80468d75effSDimitry Andric       Diag(Loc, DL_Error, ET,
80568d75effSDimitry Andric            "addition of unsigned offset to %0 overflowed to %1")
80668d75effSDimitry Andric           << (void *)Base << (void *)Result;
80768d75effSDimitry Andric     else
80868d75effSDimitry Andric       Diag(Loc, DL_Error, ET,
80968d75effSDimitry Andric            "subtraction of unsigned offset from %0 overflowed to %1")
81068d75effSDimitry Andric           << (void *)Base << (void *)Result;
81168d75effSDimitry Andric   } else {
81268d75effSDimitry Andric     Diag(Loc, DL_Error, ET,
81368d75effSDimitry Andric          "pointer index expression with base %0 overflowed to %1")
81468d75effSDimitry Andric         << (void *)Base << (void *)Result;
81568d75effSDimitry Andric   }
81668d75effSDimitry Andric }
81768d75effSDimitry Andric 
81868d75effSDimitry Andric void __ubsan::__ubsan_handle_pointer_overflow(PointerOverflowData *Data,
81968d75effSDimitry Andric                                               ValueHandle Base,
82068d75effSDimitry Andric                                               ValueHandle Result) {
82168d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
82268d75effSDimitry Andric   handlePointerOverflowImpl(Data, Base, Result, Opts);
82368d75effSDimitry Andric }
82468d75effSDimitry Andric 
82568d75effSDimitry Andric void __ubsan::__ubsan_handle_pointer_overflow_abort(PointerOverflowData *Data,
82668d75effSDimitry Andric                                                     ValueHandle Base,
82768d75effSDimitry Andric                                                     ValueHandle Result) {
82868d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
82968d75effSDimitry Andric   handlePointerOverflowImpl(Data, Base, Result, Opts);
83068d75effSDimitry Andric   Die();
83168d75effSDimitry Andric }
83268d75effSDimitry Andric 
83368d75effSDimitry Andric static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function,
83468d75effSDimitry Andric                               ReportOptions Opts) {
83568d75effSDimitry Andric   if (Data->CheckKind != CFITCK_ICall && Data->CheckKind != CFITCK_NVMFCall)
83668d75effSDimitry Andric     Die();
83768d75effSDimitry Andric 
83868d75effSDimitry Andric   SourceLocation Loc = Data->Loc.acquire();
83968d75effSDimitry Andric   ErrorType ET = ErrorType::CFIBadType;
84068d75effSDimitry Andric 
84168d75effSDimitry Andric   if (ignoreReport(Loc, Opts, ET))
84268d75effSDimitry Andric     return;
84368d75effSDimitry Andric 
84468d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
84568d75effSDimitry Andric 
84668d75effSDimitry Andric   const char *CheckKindStr = Data->CheckKind == CFITCK_NVMFCall
84768d75effSDimitry Andric                                  ? "non-virtual pointer to member function call"
84868d75effSDimitry Andric                                  : "indirect function call";
84968d75effSDimitry Andric   Diag(Loc, DL_Error, ET,
85068d75effSDimitry Andric        "control flow integrity check for type %0 failed during %1")
85168d75effSDimitry Andric       << Data->Type << CheckKindStr;
85268d75effSDimitry Andric 
85368d75effSDimitry Andric   SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));
85468d75effSDimitry Andric   const char *FName = FLoc.get()->info.function;
85568d75effSDimitry Andric   if (!FName)
85668d75effSDimitry Andric     FName = "(unknown)";
85768d75effSDimitry Andric   Diag(FLoc, DL_Note, ET, "%0 defined here") << FName;
85868d75effSDimitry Andric 
85968d75effSDimitry Andric   // If the failure involved different DSOs for the check location and icall
86068d75effSDimitry Andric   // target, report the DSO names.
86168d75effSDimitry Andric   const char *DstModule = FLoc.get()->info.module;
86268d75effSDimitry Andric   if (!DstModule)
86368d75effSDimitry Andric     DstModule = "(unknown)";
86468d75effSDimitry Andric 
86568d75effSDimitry Andric   const char *SrcModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Opts.pc);
86668d75effSDimitry Andric   if (!SrcModule)
86768d75effSDimitry Andric     SrcModule = "(unknown)";
86868d75effSDimitry Andric 
86968d75effSDimitry Andric   if (internal_strcmp(SrcModule, DstModule))
87068d75effSDimitry Andric     Diag(Loc, DL_Note, ET,
87168d75effSDimitry Andric          "check failed in %0, destination function located in %1")
87268d75effSDimitry Andric         << SrcModule << DstModule;
87368d75effSDimitry Andric }
87468d75effSDimitry Andric 
87568d75effSDimitry Andric namespace __ubsan {
87668d75effSDimitry Andric 
87768d75effSDimitry Andric #ifdef UBSAN_CAN_USE_CXXABI
87868d75effSDimitry Andric 
87968d75effSDimitry Andric #ifdef _WIN32
88068d75effSDimitry Andric 
88168d75effSDimitry Andric extern "C" void __ubsan_handle_cfi_bad_type_default(CFICheckFailData *Data,
88268d75effSDimitry Andric                                                     ValueHandle Vtable,
88368d75effSDimitry Andric                                                     bool ValidVtable,
88468d75effSDimitry Andric                                                     ReportOptions Opts) {
88568d75effSDimitry Andric   Die();
88668d75effSDimitry Andric }
88768d75effSDimitry Andric 
88868d75effSDimitry Andric WIN_WEAK_ALIAS(__ubsan_handle_cfi_bad_type, __ubsan_handle_cfi_bad_type_default)
88968d75effSDimitry Andric #else
89068d75effSDimitry Andric SANITIZER_WEAK_ATTRIBUTE
89168d75effSDimitry Andric #endif
89268d75effSDimitry Andric void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
89368d75effSDimitry Andric                                  bool ValidVtable, ReportOptions Opts);
89468d75effSDimitry Andric 
89568d75effSDimitry Andric #else
89668d75effSDimitry Andric void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
89768d75effSDimitry Andric                                  bool ValidVtable, ReportOptions Opts) {
89868d75effSDimitry Andric   Die();
89968d75effSDimitry Andric }
90068d75effSDimitry Andric #endif
90168d75effSDimitry Andric 
90268d75effSDimitry Andric }  // namespace __ubsan
90368d75effSDimitry Andric 
90468d75effSDimitry Andric void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,
90568d75effSDimitry Andric                                             ValueHandle Value,
90668d75effSDimitry Andric                                             uptr ValidVtable) {
90768d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
90868d75effSDimitry Andric   if (Data->CheckKind == CFITCK_ICall || Data->CheckKind == CFITCK_NVMFCall)
90968d75effSDimitry Andric     handleCFIBadIcall(Data, Value, Opts);
91068d75effSDimitry Andric   else
91168d75effSDimitry Andric     __ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts);
91268d75effSDimitry Andric }
91368d75effSDimitry Andric 
91468d75effSDimitry Andric void __ubsan::__ubsan_handle_cfi_check_fail_abort(CFICheckFailData *Data,
91568d75effSDimitry Andric                                                   ValueHandle Value,
91668d75effSDimitry Andric                                                   uptr ValidVtable) {
91768d75effSDimitry Andric   GET_REPORT_OPTIONS(true);
91868d75effSDimitry Andric   if (Data->CheckKind == CFITCK_ICall || Data->CheckKind == CFITCK_NVMFCall)
91968d75effSDimitry Andric     handleCFIBadIcall(Data, Value, Opts);
92068d75effSDimitry Andric   else
92168d75effSDimitry Andric     __ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts);
92268d75effSDimitry Andric   Die();
92368d75effSDimitry Andric }
92468d75effSDimitry Andric 
92506c3fb27SDimitry Andric static bool handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
92606c3fb27SDimitry Andric                                        ValueHandle Function,
92706c3fb27SDimitry Andric                                        ReportOptions Opts) {
92806c3fb27SDimitry Andric   SourceLocation CallLoc = Data->Loc.acquire();
92906c3fb27SDimitry Andric   ErrorType ET = ErrorType::FunctionTypeMismatch;
93006c3fb27SDimitry Andric   if (ignoreReport(CallLoc, Opts, ET))
93106c3fb27SDimitry Andric     return true;
93206c3fb27SDimitry Andric 
93306c3fb27SDimitry Andric   ScopedReport R(Opts, CallLoc, ET);
93406c3fb27SDimitry Andric 
93506c3fb27SDimitry Andric   SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));
93606c3fb27SDimitry Andric   const char *FName = FLoc.get()->info.function;
93706c3fb27SDimitry Andric   if (!FName)
93806c3fb27SDimitry Andric     FName = "(unknown)";
93906c3fb27SDimitry Andric 
94006c3fb27SDimitry Andric   Diag(CallLoc, DL_Error, ET,
94106c3fb27SDimitry Andric        "call to function %0 through pointer to incorrect function type %1")
94206c3fb27SDimitry Andric       << FName << Data->Type;
94306c3fb27SDimitry Andric   Diag(FLoc, DL_Note, ET, "%0 defined here") << FName;
94406c3fb27SDimitry Andric   return true;
94506c3fb27SDimitry Andric }
94606c3fb27SDimitry Andric 
94706c3fb27SDimitry Andric void __ubsan::__ubsan_handle_function_type_mismatch(
94806c3fb27SDimitry Andric     FunctionTypeMismatchData *Data, ValueHandle Function) {
94906c3fb27SDimitry Andric   GET_REPORT_OPTIONS(false);
95006c3fb27SDimitry Andric   handleFunctionTypeMismatch(Data, Function, Opts);
95106c3fb27SDimitry Andric }
95206c3fb27SDimitry Andric 
95306c3fb27SDimitry Andric void __ubsan::__ubsan_handle_function_type_mismatch_abort(
95406c3fb27SDimitry Andric     FunctionTypeMismatchData *Data, ValueHandle Function) {
95506c3fb27SDimitry Andric   GET_REPORT_OPTIONS(true);
95606c3fb27SDimitry Andric   if (handleFunctionTypeMismatch(Data, Function, Opts))
95706c3fb27SDimitry Andric     Die();
95806c3fb27SDimitry Andric }
95906c3fb27SDimitry Andric 
96068d75effSDimitry Andric #endif  // CAN_SANITIZE_UB
961