Path: blob/main/contrib/llvm-project/compiler-rt/lib/ubsan/ubsan_handlers.cpp
35233 views
//===-- ubsan_handlers.cpp ------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Error logging entry points for the UBSan runtime.9//10//===----------------------------------------------------------------------===//1112#include "ubsan_platform.h"13#if CAN_SANITIZE_UB14#include "ubsan_handlers.h"15#include "ubsan_diag.h"16#include "ubsan_flags.h"17#include "ubsan_monitor.h"18#include "ubsan_value.h"1920#include "sanitizer_common/sanitizer_common.h"2122using namespace __sanitizer;23using namespace __ubsan;2425namespace __ubsan {26bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) {27// We are not allowed to skip error report: if we are in unrecoverable28// handler, we have to terminate the program right now, and therefore29// have to print some diagnostic.30//31// Even if source location is disabled, it doesn't mean that we have32// already report an error to the user: some concurrently running33// thread could have acquired it, but not yet printed the report.34if (Opts.FromUnrecoverableHandler)35return false;36return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc, SLoc.getFilename());37}3839/// Situations in which we might emit a check for the suitability of a40/// pointer or glvalue. Needs to be kept in sync with CodeGenFunction.h in41/// clang.42enum TypeCheckKind {43/// Checking the operand of a load. Must be suitably sized and aligned.44TCK_Load,45/// Checking the destination of a store. Must be suitably sized and aligned.46TCK_Store,47/// Checking the bound value in a reference binding. Must be suitably sized48/// and aligned, but is not required to refer to an object (until the49/// reference is used), per core issue 453.50TCK_ReferenceBinding,51/// Checking the object expression in a non-static data member access. Must52/// be an object within its lifetime.53TCK_MemberAccess,54/// Checking the 'this' pointer for a call to a non-static member function.55/// Must be an object within its lifetime.56TCK_MemberCall,57/// Checking the 'this' pointer for a constructor call.58TCK_ConstructorCall,59/// Checking the operand of a static_cast to a derived pointer type. Must be60/// null or an object within its lifetime.61TCK_DowncastPointer,62/// Checking the operand of a static_cast to a derived reference type. Must63/// be an object within its lifetime.64TCK_DowncastReference,65/// Checking the operand of a cast to a base object. Must be suitably sized66/// and aligned.67TCK_Upcast,68/// Checking the operand of a cast to a virtual base object. Must be an69/// object within its lifetime.70TCK_UpcastToVirtualBase,71/// Checking the value assigned to a _Nonnull pointer. Must not be null.72TCK_NonnullAssign,73/// Checking the operand of a dynamic_cast or a typeid expression. Must be74/// null or an object within its lifetime.75TCK_DynamicOperation76};7778extern const char *const TypeCheckKinds[] = {79"load of", "store to", "reference binding to", "member access within",80"member call on", "constructor call on", "downcast of", "downcast of",81"upcast of", "cast to virtual base of", "_Nonnull binding to",82"dynamic operation on"};83}8485static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,86ReportOptions Opts) {87Location Loc = Data->Loc.acquire();8889uptr Alignment = (uptr)1 << Data->LogAlignment;90ErrorType ET;91if (!Pointer)92ET = (Data->TypeCheckKind == TCK_NonnullAssign)93? ErrorType::NullPointerUseWithNullability94: ErrorType::NullPointerUse;95else if (Pointer & (Alignment - 1))96ET = ErrorType::MisalignedPointerUse;97else98ET = ErrorType::InsufficientObjectSize;99100// Use the SourceLocation from Data to track deduplication, even if it's101// invalid.102if (ignoreReport(Loc.getSourceLocation(), Opts, ET))103return;104105SymbolizedStackHolder FallbackLoc;106if (Data->Loc.isInvalid()) {107FallbackLoc.reset(getCallerLocation(Opts.pc));108Loc = FallbackLoc;109}110111ScopedReport R(Opts, Loc, ET);112113switch (ET) {114case ErrorType::NullPointerUse:115case ErrorType::NullPointerUseWithNullability:116Diag(Loc, DL_Error, ET, "%0 null pointer of type %1")117<< TypeCheckKinds[Data->TypeCheckKind] << Data->Type;118break;119case ErrorType::MisalignedPointerUse:120Diag(Loc, DL_Error, ET, "%0 misaligned address %1 for type %3, "121"which requires %2 byte alignment")122<< TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Alignment123<< Data->Type;124break;125case ErrorType::InsufficientObjectSize:126Diag(Loc, DL_Error, ET, "%0 address %1 with insufficient space "127"for an object of type %2")128<< TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Data->Type;129break;130default:131UNREACHABLE("unexpected error type!");132}133134if (Pointer)135Diag(Pointer, DL_Note, ET, "pointer points here");136}137138void __ubsan::__ubsan_handle_type_mismatch_v1(TypeMismatchData *Data,139ValueHandle Pointer) {140GET_REPORT_OPTIONS(false);141handleTypeMismatchImpl(Data, Pointer, Opts);142}143void __ubsan::__ubsan_handle_type_mismatch_v1_abort(TypeMismatchData *Data,144ValueHandle Pointer) {145GET_REPORT_OPTIONS(true);146handleTypeMismatchImpl(Data, Pointer, Opts);147Die();148}149150static void handleAlignmentAssumptionImpl(AlignmentAssumptionData *Data,151ValueHandle Pointer,152ValueHandle Alignment,153ValueHandle Offset,154ReportOptions Opts) {155Location Loc = Data->Loc.acquire();156SourceLocation AssumptionLoc = Data->AssumptionLoc.acquire();157158ErrorType ET = ErrorType::AlignmentAssumption;159160if (ignoreReport(Loc.getSourceLocation(), Opts, ET))161return;162163ScopedReport R(Opts, Loc, ET);164165uptr RealPointer = Pointer - Offset;166uptr LSB = LeastSignificantSetBitIndex(RealPointer);167uptr ActualAlignment = uptr(1) << LSB;168169uptr Mask = Alignment - 1;170uptr MisAlignmentOffset = RealPointer & Mask;171172if (!Offset) {173Diag(Loc, DL_Error, ET,174"assumption of %0 byte alignment for pointer of type %1 failed")175<< Alignment << Data->Type;176} else {177Diag(Loc, DL_Error, ET,178"assumption of %0 byte alignment (with offset of %1 byte) for pointer "179"of type %2 failed")180<< Alignment << Offset << Data->Type;181}182183if (!AssumptionLoc.isInvalid())184Diag(AssumptionLoc, DL_Note, ET, "alignment assumption was specified here");185186Diag(RealPointer, DL_Note, ET,187"%0address is %1 aligned, misalignment offset is %2 bytes")188<< (Offset ? "offset " : "") << ActualAlignment << MisAlignmentOffset;189}190191void __ubsan::__ubsan_handle_alignment_assumption(AlignmentAssumptionData *Data,192ValueHandle Pointer,193ValueHandle Alignment,194ValueHandle Offset) {195GET_REPORT_OPTIONS(false);196handleAlignmentAssumptionImpl(Data, Pointer, Alignment, Offset, Opts);197}198void __ubsan::__ubsan_handle_alignment_assumption_abort(199AlignmentAssumptionData *Data, ValueHandle Pointer, ValueHandle Alignment,200ValueHandle Offset) {201GET_REPORT_OPTIONS(true);202handleAlignmentAssumptionImpl(Data, Pointer, Alignment, Offset, Opts);203Die();204}205206/// \brief Common diagnostic emission for various forms of integer overflow.207template <typename T>208static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS,209const char *Operator, T RHS,210ReportOptions Opts) {211SourceLocation Loc = Data->Loc.acquire();212bool IsSigned = Data->Type.isSignedIntegerTy();213ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow214: ErrorType::UnsignedIntegerOverflow;215216if (ignoreReport(Loc, Opts, ET))217return;218219// If this is an unsigned overflow in non-fatal mode, potentially ignore it.220if (!IsSigned && !Opts.FromUnrecoverableHandler &&221flags()->silence_unsigned_overflow)222return;223224ScopedReport R(Opts, Loc, ET);225226Diag(Loc, DL_Error, ET, "%0 integer overflow: "227"%1 %2 %3 cannot be represented in type %4")228<< (IsSigned ? "signed" : "unsigned") << Value(Data->Type, LHS)229<< Operator << RHS << Data->Type;230}231232#define UBSAN_OVERFLOW_HANDLER(handler_name, op, unrecoverable) \233void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \234ValueHandle RHS) { \235GET_REPORT_OPTIONS(unrecoverable); \236handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \237if (unrecoverable) \238Die(); \239}240241UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false)242UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow_abort, "+", true)243UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "-", false)244UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow_abort, "-", true)245UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "*", false)246UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true)247248static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal,249ReportOptions Opts) {250SourceLocation Loc = Data->Loc.acquire();251bool IsSigned = Data->Type.isSignedIntegerTy();252ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow253: ErrorType::UnsignedIntegerOverflow;254255if (ignoreReport(Loc, Opts, ET))256return;257258if (!IsSigned && flags()->silence_unsigned_overflow)259return;260261ScopedReport R(Opts, Loc, ET);262263if (IsSigned)264Diag(Loc, DL_Error, ET,265"negation of %0 cannot be represented in type %1; "266"cast to an unsigned type to negate this value to itself")267<< Value(Data->Type, OldVal) << Data->Type;268else269Diag(Loc, DL_Error, ET, "negation of %0 cannot be represented in type %1")270<< Value(Data->Type, OldVal) << Data->Type;271}272273void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,274ValueHandle OldVal) {275GET_REPORT_OPTIONS(false);276handleNegateOverflowImpl(Data, OldVal, Opts);277}278void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data,279ValueHandle OldVal) {280GET_REPORT_OPTIONS(true);281handleNegateOverflowImpl(Data, OldVal, Opts);282Die();283}284285static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS,286ValueHandle RHS, ReportOptions Opts) {287SourceLocation Loc = Data->Loc.acquire();288Value LHSVal(Data->Type, LHS);289Value RHSVal(Data->Type, RHS);290291ErrorType ET;292if (RHSVal.isMinusOne())293ET = ErrorType::SignedIntegerOverflow;294else if (Data->Type.isIntegerTy())295ET = ErrorType::IntegerDivideByZero;296else297ET = ErrorType::FloatDivideByZero;298299if (ignoreReport(Loc, Opts, ET))300return;301302ScopedReport R(Opts, Loc, ET);303304switch (ET) {305case ErrorType::SignedIntegerOverflow:306Diag(Loc, DL_Error, ET,307"division of %0 by -1 cannot be represented in type %1")308<< LHSVal << Data->Type;309break;310default:311Diag(Loc, DL_Error, ET, "division by zero");312break;313}314}315316void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data,317ValueHandle LHS, ValueHandle RHS) {318GET_REPORT_OPTIONS(false);319handleDivremOverflowImpl(Data, LHS, RHS, Opts);320}321void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data,322ValueHandle LHS,323ValueHandle RHS) {324GET_REPORT_OPTIONS(true);325handleDivremOverflowImpl(Data, LHS, RHS, Opts);326Die();327}328329static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data,330ValueHandle LHS, ValueHandle RHS,331ReportOptions Opts) {332SourceLocation Loc = Data->Loc.acquire();333Value LHSVal(Data->LHSType, LHS);334Value RHSVal(Data->RHSType, RHS);335336ErrorType ET;337if (RHSVal.isNegative() ||338RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth())339ET = ErrorType::InvalidShiftExponent;340else341ET = ErrorType::InvalidShiftBase;342343if (ignoreReport(Loc, Opts, ET))344return;345346ScopedReport R(Opts, Loc, ET);347348if (ET == ErrorType::InvalidShiftExponent) {349if (RHSVal.isNegative())350Diag(Loc, DL_Error, ET, "shift exponent %0 is negative") << RHSVal;351else352Diag(Loc, DL_Error, ET,353"shift exponent %0 is too large for %1-bit type %2")354<< RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType;355} else {356if (LHSVal.isNegative())357Diag(Loc, DL_Error, ET, "left shift of negative value %0") << LHSVal;358else359Diag(Loc, DL_Error, ET,360"left shift of %0 by %1 places cannot be represented in type %2")361<< LHSVal << RHSVal << Data->LHSType;362}363}364365void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,366ValueHandle LHS,367ValueHandle RHS) {368GET_REPORT_OPTIONS(false);369handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);370}371void __ubsan::__ubsan_handle_shift_out_of_bounds_abort(372ShiftOutOfBoundsData *Data,373ValueHandle LHS,374ValueHandle RHS) {375GET_REPORT_OPTIONS(true);376handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);377Die();378}379380static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,381ReportOptions Opts) {382SourceLocation Loc = Data->Loc.acquire();383ErrorType ET = ErrorType::OutOfBoundsIndex;384385if (ignoreReport(Loc, Opts, ET))386return;387388ScopedReport R(Opts, Loc, ET);389390Value IndexVal(Data->IndexType, Index);391Diag(Loc, DL_Error, ET, "index %0 out of bounds for type %1")392<< IndexVal << Data->ArrayType;393}394395void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data,396ValueHandle Index) {397GET_REPORT_OPTIONS(false);398handleOutOfBoundsImpl(Data, Index, Opts);399}400void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data,401ValueHandle Index) {402GET_REPORT_OPTIONS(true);403handleOutOfBoundsImpl(Data, Index, Opts);404Die();405}406407static void handleBuiltinUnreachableImpl(UnreachableData *Data,408ReportOptions Opts) {409ErrorType ET = ErrorType::UnreachableCall;410ScopedReport R(Opts, Data->Loc, ET);411Diag(Data->Loc, DL_Error, ET,412"execution reached an unreachable program point");413}414415void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {416GET_REPORT_OPTIONS(true);417handleBuiltinUnreachableImpl(Data, Opts);418Die();419}420421static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) {422ErrorType ET = ErrorType::MissingReturn;423ScopedReport R(Opts, Data->Loc, ET);424Diag(Data->Loc, DL_Error, ET,425"execution reached the end of a value-returning function "426"without returning a value");427}428429void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {430GET_REPORT_OPTIONS(true);431handleMissingReturnImpl(Data, Opts);432Die();433}434435static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,436ReportOptions Opts) {437SourceLocation Loc = Data->Loc.acquire();438ErrorType ET = ErrorType::NonPositiveVLAIndex;439440if (ignoreReport(Loc, Opts, ET))441return;442443ScopedReport R(Opts, Loc, ET);444445Diag(Loc, DL_Error, ET, "variable length array bound evaluates to "446"non-positive value %0")447<< Value(Data->Type, Bound);448}449450void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data,451ValueHandle Bound) {452GET_REPORT_OPTIONS(false);453handleVLABoundNotPositive(Data, Bound, Opts);454}455void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data,456ValueHandle Bound) {457GET_REPORT_OPTIONS(true);458handleVLABoundNotPositive(Data, Bound, Opts);459Die();460}461462static bool looksLikeFloatCastOverflowDataV1(void *Data) {463// First field is either a pointer to filename or a pointer to a464// TypeDescriptor.465u8 *FilenameOrTypeDescriptor;466internal_memcpy(&FilenameOrTypeDescriptor, Data,467sizeof(FilenameOrTypeDescriptor));468469// Heuristic: For float_cast_overflow, the TypeKind will be either TK_Integer470// (0x0), TK_Float (0x1) or TK_Unknown (0xff). If both types are known,471// adding both bytes will be 0 or 1 (for BE or LE). If it were a filename,472// adding two printable characters will not yield such a value. Otherwise,473// if one of them is 0xff, this is most likely TK_Unknown type descriptor.474u16 MaybeFromTypeKind =475FilenameOrTypeDescriptor[0] + FilenameOrTypeDescriptor[1];476return MaybeFromTypeKind < 2 || FilenameOrTypeDescriptor[0] == 0xff ||477FilenameOrTypeDescriptor[1] == 0xff;478}479480static void handleFloatCastOverflow(void *DataPtr, ValueHandle From,481ReportOptions Opts) {482SymbolizedStackHolder CallerLoc;483Location Loc;484const TypeDescriptor *FromType, *ToType;485ErrorType ET = ErrorType::FloatCastOverflow;486487if (looksLikeFloatCastOverflowDataV1(DataPtr)) {488auto Data = reinterpret_cast<FloatCastOverflowData *>(DataPtr);489CallerLoc.reset(getCallerLocation(Opts.pc));490Loc = CallerLoc;491FromType = &Data->FromType;492ToType = &Data->ToType;493} else {494auto Data = reinterpret_cast<FloatCastOverflowDataV2 *>(DataPtr);495SourceLocation SLoc = Data->Loc.acquire();496if (ignoreReport(SLoc, Opts, ET))497return;498Loc = SLoc;499FromType = &Data->FromType;500ToType = &Data->ToType;501}502503ScopedReport R(Opts, Loc, ET);504505Diag(Loc, DL_Error, ET,506"%0 is outside the range of representable values of type %2")507<< Value(*FromType, From) << *FromType << *ToType;508}509510void __ubsan::__ubsan_handle_float_cast_overflow(void *Data, ValueHandle From) {511GET_REPORT_OPTIONS(false);512handleFloatCastOverflow(Data, From, Opts);513}514void __ubsan::__ubsan_handle_float_cast_overflow_abort(void *Data,515ValueHandle From) {516GET_REPORT_OPTIONS(true);517handleFloatCastOverflow(Data, From, Opts);518Die();519}520521static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,522ReportOptions Opts) {523SourceLocation Loc = Data->Loc.acquire();524// This check could be more precise if we used different handlers for525// -fsanitize=bool and -fsanitize=enum.526bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'")) ||527(0 == internal_strncmp(Data->Type.getTypeName(), "'BOOL'", 6));528ErrorType ET =529IsBool ? ErrorType::InvalidBoolLoad : ErrorType::InvalidEnumLoad;530531if (ignoreReport(Loc, Opts, ET))532return;533534ScopedReport R(Opts, Loc, ET);535536Diag(Loc, DL_Error, ET,537"load of value %0, which is not a valid value for type %1")538<< Value(Data->Type, Val) << Data->Type;539}540541void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,542ValueHandle Val) {543GET_REPORT_OPTIONS(false);544handleLoadInvalidValue(Data, Val, Opts);545}546void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data,547ValueHandle Val) {548GET_REPORT_OPTIONS(true);549handleLoadInvalidValue(Data, Val, Opts);550Die();551}552553static void handleImplicitConversion(ImplicitConversionData *Data,554ReportOptions Opts, ValueHandle Src,555ValueHandle Dst) {556SourceLocation Loc = Data->Loc.acquire();557const TypeDescriptor &SrcTy = Data->FromType;558const TypeDescriptor &DstTy = Data->ToType;559bool SrcSigned = SrcTy.isSignedIntegerTy();560bool DstSigned = DstTy.isSignedIntegerTy();561ErrorType ET = ErrorType::GenericUB;562563switch (Data->Kind) {564case ICCK_IntegerTruncation: { // Legacy, no longer used.565// Let's figure out what it should be as per the new types, and upgrade.566// If both types are unsigned, then it's an unsigned truncation.567// Else, it is a signed truncation.568if (!SrcSigned && !DstSigned) {569ET = ErrorType::ImplicitUnsignedIntegerTruncation;570} else {571ET = ErrorType::ImplicitSignedIntegerTruncation;572}573break;574}575case ICCK_UnsignedIntegerTruncation:576ET = ErrorType::ImplicitUnsignedIntegerTruncation;577break;578case ICCK_SignedIntegerTruncation:579ET = ErrorType::ImplicitSignedIntegerTruncation;580break;581case ICCK_IntegerSignChange:582ET = ErrorType::ImplicitIntegerSignChange;583break;584case ICCK_SignedIntegerTruncationOrSignChange:585ET = ErrorType::ImplicitSignedIntegerTruncationOrSignChange;586break;587}588589if (ignoreReport(Loc, Opts, ET))590return;591592ScopedReport R(Opts, Loc, ET);593594// In the case we have a bitfield, we want to explicitly say so in the595// error message.596// FIXME: is it possible to dump the values as hex with fixed width?597if (Data->BitfieldBits)598Diag(Loc, DL_Error, ET,599"implicit conversion from type %0 of value %1 (%2-bit, %3signed) to "600"type %4 changed the value to %5 (%6-bit bitfield, %7signed)")601<< SrcTy << Value(SrcTy, Src) << SrcTy.getIntegerBitWidth()602<< (SrcSigned ? "" : "un") << DstTy << Value(DstTy, Dst)603<< Data->BitfieldBits << (DstSigned ? "" : "un");604else605Diag(Loc, DL_Error, ET,606"implicit conversion from type %0 of value %1 (%2-bit, %3signed) to "607"type %4 changed the value to %5 (%6-bit, %7signed)")608<< SrcTy << Value(SrcTy, Src) << SrcTy.getIntegerBitWidth()609<< (SrcSigned ? "" : "un") << DstTy << Value(DstTy, Dst)610<< DstTy.getIntegerBitWidth() << (DstSigned ? "" : "un");611}612613void __ubsan::__ubsan_handle_implicit_conversion(ImplicitConversionData *Data,614ValueHandle Src,615ValueHandle Dst) {616GET_REPORT_OPTIONS(false);617handleImplicitConversion(Data, Opts, Src, Dst);618}619void __ubsan::__ubsan_handle_implicit_conversion_abort(620ImplicitConversionData *Data, ValueHandle Src, ValueHandle Dst) {621GET_REPORT_OPTIONS(true);622handleImplicitConversion(Data, Opts, Src, Dst);623Die();624}625626static void handleInvalidBuiltin(InvalidBuiltinData *Data, ReportOptions Opts) {627SourceLocation Loc = Data->Loc.acquire();628ErrorType ET = ErrorType::InvalidBuiltin;629630if (ignoreReport(Loc, Opts, ET))631return;632633ScopedReport R(Opts, Loc, ET);634635Diag(Loc, DL_Error, ET,636"passing zero to %0, which is not a valid argument")637<< ((Data->Kind == BCK_CTZPassedZero) ? "ctz()" : "clz()");638}639640void __ubsan::__ubsan_handle_invalid_builtin(InvalidBuiltinData *Data) {641GET_REPORT_OPTIONS(true);642handleInvalidBuiltin(Data, Opts);643}644void __ubsan::__ubsan_handle_invalid_builtin_abort(InvalidBuiltinData *Data) {645GET_REPORT_OPTIONS(true);646handleInvalidBuiltin(Data, Opts);647Die();648}649650static void handleInvalidObjCCast(InvalidObjCCast *Data, ValueHandle Pointer,651ReportOptions Opts) {652SourceLocation Loc = Data->Loc.acquire();653ErrorType ET = ErrorType::InvalidObjCCast;654655if (ignoreReport(Loc, Opts, ET))656return;657658ScopedReport R(Opts, Loc, ET);659660const char *GivenClass = getObjCClassName(Pointer);661const char *GivenClassStr = GivenClass ? GivenClass : "<unknown type>";662663Diag(Loc, DL_Error, ET,664"invalid ObjC cast, object is a '%0', but expected a %1")665<< GivenClassStr << Data->ExpectedType;666}667668void __ubsan::__ubsan_handle_invalid_objc_cast(InvalidObjCCast *Data,669ValueHandle Pointer) {670GET_REPORT_OPTIONS(false);671handleInvalidObjCCast(Data, Pointer, Opts);672}673void __ubsan::__ubsan_handle_invalid_objc_cast_abort(InvalidObjCCast *Data,674ValueHandle Pointer) {675GET_REPORT_OPTIONS(true);676handleInvalidObjCCast(Data, Pointer, Opts);677Die();678}679680static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr,681ReportOptions Opts, bool IsAttr) {682if (!LocPtr)683UNREACHABLE("source location pointer is null!");684685SourceLocation Loc = LocPtr->acquire();686ErrorType ET = IsAttr ? ErrorType::InvalidNullReturn687: ErrorType::InvalidNullReturnWithNullability;688689if (ignoreReport(Loc, Opts, ET))690return;691692ScopedReport R(Opts, Loc, ET);693694Diag(Loc, DL_Error, ET,695"null pointer returned from function declared to never return null");696if (!Data->AttrLoc.isInvalid())697Diag(Data->AttrLoc, DL_Note, ET, "%0 specified here")698<< (IsAttr ? "returns_nonnull attribute"699: "_Nonnull return type annotation");700}701702void __ubsan::__ubsan_handle_nonnull_return_v1(NonNullReturnData *Data,703SourceLocation *LocPtr) {704GET_REPORT_OPTIONS(false);705handleNonNullReturn(Data, LocPtr, Opts, true);706}707708void __ubsan::__ubsan_handle_nonnull_return_v1_abort(NonNullReturnData *Data,709SourceLocation *LocPtr) {710GET_REPORT_OPTIONS(true);711handleNonNullReturn(Data, LocPtr, Opts, true);712Die();713}714715void __ubsan::__ubsan_handle_nullability_return_v1(NonNullReturnData *Data,716SourceLocation *LocPtr) {717GET_REPORT_OPTIONS(false);718handleNonNullReturn(Data, LocPtr, Opts, false);719}720721void __ubsan::__ubsan_handle_nullability_return_v1_abort(722NonNullReturnData *Data, SourceLocation *LocPtr) {723GET_REPORT_OPTIONS(true);724handleNonNullReturn(Data, LocPtr, Opts, false);725Die();726}727728static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts,729bool IsAttr) {730SourceLocation Loc = Data->Loc.acquire();731ErrorType ET = IsAttr ? ErrorType::InvalidNullArgument732: ErrorType::InvalidNullArgumentWithNullability;733734if (ignoreReport(Loc, Opts, ET))735return;736737ScopedReport R(Opts, Loc, ET);738739Diag(Loc, DL_Error, ET,740"null pointer passed as argument %0, which is declared to "741"never be null")742<< Data->ArgIndex;743if (!Data->AttrLoc.isInvalid())744Diag(Data->AttrLoc, DL_Note, ET, "%0 specified here")745<< (IsAttr ? "nonnull attribute" : "_Nonnull type annotation");746}747748void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) {749GET_REPORT_OPTIONS(false);750handleNonNullArg(Data, Opts, true);751}752753void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) {754GET_REPORT_OPTIONS(true);755handleNonNullArg(Data, Opts, true);756Die();757}758759void __ubsan::__ubsan_handle_nullability_arg(NonNullArgData *Data) {760GET_REPORT_OPTIONS(false);761handleNonNullArg(Data, Opts, false);762}763764void __ubsan::__ubsan_handle_nullability_arg_abort(NonNullArgData *Data) {765GET_REPORT_OPTIONS(true);766handleNonNullArg(Data, Opts, false);767Die();768}769770static void handlePointerOverflowImpl(PointerOverflowData *Data,771ValueHandle Base,772ValueHandle Result,773ReportOptions Opts) {774SourceLocation Loc = Data->Loc.acquire();775ErrorType ET;776777if (Base == 0 && Result == 0)778ET = ErrorType::NullptrWithOffset;779else if (Base == 0 && Result != 0)780ET = ErrorType::NullptrWithNonZeroOffset;781else if (Base != 0 && Result == 0)782ET = ErrorType::NullptrAfterNonZeroOffset;783else784ET = ErrorType::PointerOverflow;785786if (ignoreReport(Loc, Opts, ET))787return;788789ScopedReport R(Opts, Loc, ET);790791if (ET == ErrorType::NullptrWithOffset) {792Diag(Loc, DL_Error, ET, "applying zero offset to null pointer");793} else if (ET == ErrorType::NullptrWithNonZeroOffset) {794Diag(Loc, DL_Error, ET, "applying non-zero offset %0 to null pointer")795<< Result;796} else if (ET == ErrorType::NullptrAfterNonZeroOffset) {797Diag(798Loc, DL_Error, ET,799"applying non-zero offset to non-null pointer %0 produced null pointer")800<< (void *)Base;801} else if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) {802if (Base > Result)803Diag(Loc, DL_Error, ET,804"addition of unsigned offset to %0 overflowed to %1")805<< (void *)Base << (void *)Result;806else807Diag(Loc, DL_Error, ET,808"subtraction of unsigned offset from %0 overflowed to %1")809<< (void *)Base << (void *)Result;810} else {811Diag(Loc, DL_Error, ET,812"pointer index expression with base %0 overflowed to %1")813<< (void *)Base << (void *)Result;814}815}816817void __ubsan::__ubsan_handle_pointer_overflow(PointerOverflowData *Data,818ValueHandle Base,819ValueHandle Result) {820GET_REPORT_OPTIONS(false);821handlePointerOverflowImpl(Data, Base, Result, Opts);822}823824void __ubsan::__ubsan_handle_pointer_overflow_abort(PointerOverflowData *Data,825ValueHandle Base,826ValueHandle Result) {827GET_REPORT_OPTIONS(true);828handlePointerOverflowImpl(Data, Base, Result, Opts);829Die();830}831832static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function,833ReportOptions Opts) {834if (Data->CheckKind != CFITCK_ICall && Data->CheckKind != CFITCK_NVMFCall)835Die();836837SourceLocation Loc = Data->Loc.acquire();838ErrorType ET = ErrorType::CFIBadType;839840if (ignoreReport(Loc, Opts, ET))841return;842843ScopedReport R(Opts, Loc, ET);844845const char *CheckKindStr = Data->CheckKind == CFITCK_NVMFCall846? "non-virtual pointer to member function call"847: "indirect function call";848Diag(Loc, DL_Error, ET,849"control flow integrity check for type %0 failed during %1")850<< Data->Type << CheckKindStr;851852SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));853const char *FName = FLoc.get()->info.function;854if (!FName)855FName = "(unknown)";856Diag(FLoc, DL_Note, ET, "%0 defined here") << FName;857858// If the failure involved different DSOs for the check location and icall859// target, report the DSO names.860const char *DstModule = FLoc.get()->info.module;861if (!DstModule)862DstModule = "(unknown)";863864const char *SrcModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Opts.pc);865if (!SrcModule)866SrcModule = "(unknown)";867868if (internal_strcmp(SrcModule, DstModule))869Diag(Loc, DL_Note, ET,870"check failed in %0, destination function located in %1")871<< SrcModule << DstModule;872}873874namespace __ubsan {875876#ifdef UBSAN_CAN_USE_CXXABI877878#ifdef _WIN32879880extern "C" void __ubsan_handle_cfi_bad_type_default(CFICheckFailData *Data,881ValueHandle Vtable,882bool ValidVtable,883ReportOptions Opts) {884Die();885}886887WIN_WEAK_ALIAS(__ubsan_handle_cfi_bad_type, __ubsan_handle_cfi_bad_type_default)888#else889SANITIZER_WEAK_ATTRIBUTE890#endif891void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,892bool ValidVtable, ReportOptions Opts);893894#else895void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,896bool ValidVtable, ReportOptions Opts) {897Die();898}899#endif900901} // namespace __ubsan902903void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,904ValueHandle Value,905uptr ValidVtable) {906GET_REPORT_OPTIONS(false);907if (Data->CheckKind == CFITCK_ICall || Data->CheckKind == CFITCK_NVMFCall)908handleCFIBadIcall(Data, Value, Opts);909else910__ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts);911}912913void __ubsan::__ubsan_handle_cfi_check_fail_abort(CFICheckFailData *Data,914ValueHandle Value,915uptr ValidVtable) {916GET_REPORT_OPTIONS(true);917if (Data->CheckKind == CFITCK_ICall || Data->CheckKind == CFITCK_NVMFCall)918handleCFIBadIcall(Data, Value, Opts);919else920__ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts);921Die();922}923924static bool handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,925ValueHandle Function,926ReportOptions Opts) {927SourceLocation CallLoc = Data->Loc.acquire();928ErrorType ET = ErrorType::FunctionTypeMismatch;929if (ignoreReport(CallLoc, Opts, ET))930return true;931932ScopedReport R(Opts, CallLoc, ET);933934SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));935const char *FName = FLoc.get()->info.function;936if (!FName)937FName = "(unknown)";938939Diag(CallLoc, DL_Error, ET,940"call to function %0 through pointer to incorrect function type %1")941<< FName << Data->Type;942Diag(FLoc, DL_Note, ET, "%0 defined here") << FName;943return true;944}945946void __ubsan::__ubsan_handle_function_type_mismatch(947FunctionTypeMismatchData *Data, ValueHandle Function) {948GET_REPORT_OPTIONS(false);949handleFunctionTypeMismatch(Data, Function, Opts);950}951952void __ubsan::__ubsan_handle_function_type_mismatch_abort(953FunctionTypeMismatchData *Data, ValueHandle Function) {954GET_REPORT_OPTIONS(true);955if (handleFunctionTypeMismatch(Data, Function, Opts))956Die();957}958959#endif // CAN_SANITIZE_UB960961962