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