llvm-project
960 строк · 33.9 Кб
1//===-- ubsan_handlers.cpp ------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Error logging entry points for the UBSan runtime.
10//
11//===----------------------------------------------------------------------===//
12
13#include "ubsan_platform.h"14#if CAN_SANITIZE_UB15#include "ubsan_handlers.h"16#include "ubsan_diag.h"17#include "ubsan_flags.h"18#include "ubsan_monitor.h"19#include "ubsan_value.h"20
21#include "sanitizer_common/sanitizer_common.h"22
23using namespace __sanitizer;24using namespace __ubsan;25
26namespace __ubsan {27bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) {28// We are not allowed to skip error report: if we are in unrecoverable29// handler, we have to terminate the program right now, and therefore30// have to print some diagnostic.31//32// Even if source location is disabled, it doesn't mean that we have33// already report an error to the user: some concurrently running34// thread could have acquired it, but not yet printed the report.35if (Opts.FromUnrecoverableHandler)36return false;37return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc, SLoc.getFilename());38}
39
40/// Situations in which we might emit a check for the suitability of a
41/// pointer or glvalue. Needs to be kept in sync with CodeGenFunction.h in
42/// clang.
43enum TypeCheckKind {44/// Checking the operand of a load. Must be suitably sized and aligned.45TCK_Load,46/// Checking the destination of a store. Must be suitably sized and aligned.47TCK_Store,48/// Checking the bound value in a reference binding. Must be suitably sized49/// and aligned, but is not required to refer to an object (until the50/// reference is used), per core issue 453.51TCK_ReferenceBinding,52/// Checking the object expression in a non-static data member access. Must53/// be an object within its lifetime.54TCK_MemberAccess,55/// Checking the 'this' pointer for a call to a non-static member function.56/// Must be an object within its lifetime.57TCK_MemberCall,58/// Checking the 'this' pointer for a constructor call.59TCK_ConstructorCall,60/// Checking the operand of a static_cast to a derived pointer type. Must be61/// null or an object within its lifetime.62TCK_DowncastPointer,63/// Checking the operand of a static_cast to a derived reference type. Must64/// be an object within its lifetime.65TCK_DowncastReference,66/// Checking the operand of a cast to a base object. Must be suitably sized67/// and aligned.68TCK_Upcast,69/// Checking the operand of a cast to a virtual base object. Must be an70/// object within its lifetime.71TCK_UpcastToVirtualBase,72/// Checking the value assigned to a _Nonnull pointer. Must not be null.73TCK_NonnullAssign,74/// Checking the operand of a dynamic_cast or a typeid expression. Must be75/// null or an object within its lifetime.76TCK_DynamicOperation
77};78
79extern const char *const TypeCheckKinds[] = {80"load of", "store to", "reference binding to", "member access within",81"member call on", "constructor call on", "downcast of", "downcast of",82"upcast of", "cast to virtual base of", "_Nonnull binding to",83"dynamic operation on"};84}
85
86static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,87ReportOptions Opts) {88Location Loc = Data->Loc.acquire();89
90uptr Alignment = (uptr)1 << Data->LogAlignment;91ErrorType ET;92if (!Pointer)93ET = (Data->TypeCheckKind == TCK_NonnullAssign)94? ErrorType::NullPointerUseWithNullability95: ErrorType::NullPointerUse;96else if (Pointer & (Alignment - 1))97ET = ErrorType::MisalignedPointerUse;98else99ET = ErrorType::InsufficientObjectSize;100
101// Use the SourceLocation from Data to track deduplication, even if it's102// invalid.103if (ignoreReport(Loc.getSourceLocation(), Opts, ET))104return;105
106SymbolizedStackHolder FallbackLoc;107if (Data->Loc.isInvalid()) {108FallbackLoc.reset(getCallerLocation(Opts.pc));109Loc = FallbackLoc;110}111
112ScopedReport R(Opts, Loc, ET);113
114switch (ET) {115case ErrorType::NullPointerUse:116case ErrorType::NullPointerUseWithNullability:117Diag(Loc, DL_Error, ET, "%0 null pointer of type %1")118<< TypeCheckKinds[Data->TypeCheckKind] << Data->Type;119break;120case ErrorType::MisalignedPointerUse:121Diag(Loc, DL_Error, ET, "%0 misaligned address %1 for type %3, "122"which requires %2 byte alignment")123<< TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Alignment124<< Data->Type;125break;126case ErrorType::InsufficientObjectSize:127Diag(Loc, DL_Error, ET, "%0 address %1 with insufficient space "128"for an object of type %2")129<< TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Data->Type;130break;131default:132UNREACHABLE("unexpected error type!");133}134
135if (Pointer)136Diag(Pointer, DL_Note, ET, "pointer points here");137}
138
139void __ubsan::__ubsan_handle_type_mismatch_v1(TypeMismatchData *Data,140ValueHandle Pointer) {141GET_REPORT_OPTIONS(false);142handleTypeMismatchImpl(Data, Pointer, Opts);143}
144void __ubsan::__ubsan_handle_type_mismatch_v1_abort(TypeMismatchData *Data,145ValueHandle Pointer) {146GET_REPORT_OPTIONS(true);147handleTypeMismatchImpl(Data, Pointer, Opts);148Die();149}
150
151static void handleAlignmentAssumptionImpl(AlignmentAssumptionData *Data,152ValueHandle Pointer,153ValueHandle Alignment,154ValueHandle Offset,155ReportOptions Opts) {156Location Loc = Data->Loc.acquire();157SourceLocation AssumptionLoc = Data->AssumptionLoc.acquire();158
159ErrorType ET = ErrorType::AlignmentAssumption;160
161if (ignoreReport(Loc.getSourceLocation(), Opts, ET))162return;163
164ScopedReport R(Opts, Loc, ET);165
166uptr RealPointer = Pointer - Offset;167uptr LSB = LeastSignificantSetBitIndex(RealPointer);168uptr ActualAlignment = uptr(1) << LSB;169
170uptr Mask = Alignment - 1;171uptr MisAlignmentOffset = RealPointer & Mask;172
173if (!Offset) {174Diag(Loc, DL_Error, ET,175"assumption of %0 byte alignment for pointer of type %1 failed")176<< Alignment << Data->Type;177} else {178Diag(Loc, DL_Error, ET,179"assumption of %0 byte alignment (with offset of %1 byte) for pointer "180"of type %2 failed")181<< Alignment << Offset << Data->Type;182}183
184if (!AssumptionLoc.isInvalid())185Diag(AssumptionLoc, DL_Note, ET, "alignment assumption was specified here");186
187Diag(RealPointer, DL_Note, ET,188"%0address is %1 aligned, misalignment offset is %2 bytes")189<< (Offset ? "offset " : "") << ActualAlignment << MisAlignmentOffset;190}
191
192void __ubsan::__ubsan_handle_alignment_assumption(AlignmentAssumptionData *Data,193ValueHandle Pointer,194ValueHandle Alignment,195ValueHandle Offset) {196GET_REPORT_OPTIONS(false);197handleAlignmentAssumptionImpl(Data, Pointer, Alignment, Offset, Opts);198}
199void __ubsan::__ubsan_handle_alignment_assumption_abort(200AlignmentAssumptionData *Data, ValueHandle Pointer, ValueHandle Alignment,201ValueHandle Offset) {202GET_REPORT_OPTIONS(true);203handleAlignmentAssumptionImpl(Data, Pointer, Alignment, Offset, Opts);204Die();205}
206
207/// \brief Common diagnostic emission for various forms of integer overflow.
208template <typename T>209static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS,210const char *Operator, T RHS,211ReportOptions Opts) {212SourceLocation Loc = Data->Loc.acquire();213bool IsSigned = Data->Type.isSignedIntegerTy();214ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow215: ErrorType::UnsignedIntegerOverflow;216
217if (ignoreReport(Loc, Opts, ET))218return;219
220// If this is an unsigned overflow in non-fatal mode, potentially ignore it.221if (!IsSigned && !Opts.FromUnrecoverableHandler &&222flags()->silence_unsigned_overflow)223return;224
225ScopedReport R(Opts, Loc, ET);226
227Diag(Loc, DL_Error, ET, "%0 integer overflow: "228"%1 %2 %3 cannot be represented in type %4")229<< (IsSigned ? "signed" : "unsigned") << Value(Data->Type, LHS)230<< Operator << RHS << Data->Type;231}
232
233#define UBSAN_OVERFLOW_HANDLER(handler_name, op, unrecoverable) \234void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \235ValueHandle RHS) { \236GET_REPORT_OPTIONS(unrecoverable); \237handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \238if (unrecoverable) \239Die(); \240}241
242UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false)243UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow_abort, "+", true)244UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "-", false)245UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow_abort, "-", true)246UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "*", false)247UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true)248
249static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal,250ReportOptions Opts) {251SourceLocation Loc = Data->Loc.acquire();252bool IsSigned = Data->Type.isSignedIntegerTy();253ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow254: ErrorType::UnsignedIntegerOverflow;255
256if (ignoreReport(Loc, Opts, ET))257return;258
259if (!IsSigned && flags()->silence_unsigned_overflow)260return;261
262ScopedReport R(Opts, Loc, ET);263
264if (IsSigned)265Diag(Loc, DL_Error, ET,266"negation of %0 cannot be represented in type %1; "267"cast to an unsigned type to negate this value to itself")268<< Value(Data->Type, OldVal) << Data->Type;269else270Diag(Loc, DL_Error, ET, "negation of %0 cannot be represented in type %1")271<< Value(Data->Type, OldVal) << Data->Type;272}
273
274void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data,275ValueHandle OldVal) {276GET_REPORT_OPTIONS(false);277handleNegateOverflowImpl(Data, OldVal, Opts);278}
279void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data,280ValueHandle OldVal) {281GET_REPORT_OPTIONS(true);282handleNegateOverflowImpl(Data, OldVal, Opts);283Die();284}
285
286static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS,287ValueHandle RHS, ReportOptions Opts) {288SourceLocation Loc = Data->Loc.acquire();289Value LHSVal(Data->Type, LHS);290Value RHSVal(Data->Type, RHS);291
292ErrorType ET;293if (RHSVal.isMinusOne())294ET = ErrorType::SignedIntegerOverflow;295else if (Data->Type.isIntegerTy())296ET = ErrorType::IntegerDivideByZero;297else298ET = ErrorType::FloatDivideByZero;299
300if (ignoreReport(Loc, Opts, ET))301return;302
303ScopedReport R(Opts, Loc, ET);304
305switch (ET) {306case ErrorType::SignedIntegerOverflow:307Diag(Loc, DL_Error, ET,308"division of %0 by -1 cannot be represented in type %1")309<< LHSVal << Data->Type;310break;311default:312Diag(Loc, DL_Error, ET, "division by zero");313break;314}315}
316
317void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data,318ValueHandle LHS, ValueHandle RHS) {319GET_REPORT_OPTIONS(false);320handleDivremOverflowImpl(Data, LHS, RHS, Opts);321}
322void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data,323ValueHandle LHS,324ValueHandle RHS) {325GET_REPORT_OPTIONS(true);326handleDivremOverflowImpl(Data, LHS, RHS, Opts);327Die();328}
329
330static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data,331ValueHandle LHS, ValueHandle RHS,332ReportOptions Opts) {333SourceLocation Loc = Data->Loc.acquire();334Value LHSVal(Data->LHSType, LHS);335Value RHSVal(Data->RHSType, RHS);336
337ErrorType ET;338if (RHSVal.isNegative() ||339RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth())340ET = ErrorType::InvalidShiftExponent;341else342ET = ErrorType::InvalidShiftBase;343
344if (ignoreReport(Loc, Opts, ET))345return;346
347ScopedReport R(Opts, Loc, ET);348
349if (ET == ErrorType::InvalidShiftExponent) {350if (RHSVal.isNegative())351Diag(Loc, DL_Error, ET, "shift exponent %0 is negative") << RHSVal;352else353Diag(Loc, DL_Error, ET,354"shift exponent %0 is too large for %1-bit type %2")355<< RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType;356} else {357if (LHSVal.isNegative())358Diag(Loc, DL_Error, ET, "left shift of negative value %0") << LHSVal;359else360Diag(Loc, DL_Error, ET,361"left shift of %0 by %1 places cannot be represented in type %2")362<< LHSVal << RHSVal << Data->LHSType;363}364}
365
366void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data,367ValueHandle LHS,368ValueHandle RHS) {369GET_REPORT_OPTIONS(false);370handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);371}
372void __ubsan::__ubsan_handle_shift_out_of_bounds_abort(373ShiftOutOfBoundsData *Data,374ValueHandle LHS,375ValueHandle RHS) {376GET_REPORT_OPTIONS(true);377handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts);378Die();379}
380
381static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,382ReportOptions Opts) {383SourceLocation Loc = Data->Loc.acquire();384ErrorType ET = ErrorType::OutOfBoundsIndex;385
386if (ignoreReport(Loc, Opts, ET))387return;388
389ScopedReport R(Opts, Loc, ET);390
391Value IndexVal(Data->IndexType, Index);392Diag(Loc, DL_Error, ET, "index %0 out of bounds for type %1")393<< IndexVal << Data->ArrayType;394}
395
396void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data,397ValueHandle Index) {398GET_REPORT_OPTIONS(false);399handleOutOfBoundsImpl(Data, Index, Opts);400}
401void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data,402ValueHandle Index) {403GET_REPORT_OPTIONS(true);404handleOutOfBoundsImpl(Data, Index, Opts);405Die();406}
407
408static void handleBuiltinUnreachableImpl(UnreachableData *Data,409ReportOptions Opts) {410ErrorType ET = ErrorType::UnreachableCall;411ScopedReport R(Opts, Data->Loc, ET);412Diag(Data->Loc, DL_Error, ET,413"execution reached an unreachable program point");414}
415
416void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {417GET_REPORT_OPTIONS(true);418handleBuiltinUnreachableImpl(Data, Opts);419Die();420}
421
422static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) {423ErrorType ET = ErrorType::MissingReturn;424ScopedReport R(Opts, Data->Loc, ET);425Diag(Data->Loc, DL_Error, ET,426"execution reached the end of a value-returning function "427"without returning a value");428}
429
430void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {431GET_REPORT_OPTIONS(true);432handleMissingReturnImpl(Data, Opts);433Die();434}
435
436static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,437ReportOptions Opts) {438SourceLocation Loc = Data->Loc.acquire();439ErrorType ET = ErrorType::NonPositiveVLAIndex;440
441if (ignoreReport(Loc, Opts, ET))442return;443
444ScopedReport R(Opts, Loc, ET);445
446Diag(Loc, DL_Error, ET, "variable length array bound evaluates to "447"non-positive value %0")448<< Value(Data->Type, Bound);449}
450
451void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data,452ValueHandle Bound) {453GET_REPORT_OPTIONS(false);454handleVLABoundNotPositive(Data, Bound, Opts);455}
456void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data,457ValueHandle Bound) {458GET_REPORT_OPTIONS(true);459handleVLABoundNotPositive(Data, Bound, Opts);460Die();461}
462
463static bool looksLikeFloatCastOverflowDataV1(void *Data) {464// First field is either a pointer to filename or a pointer to a465// TypeDescriptor.466u8 *FilenameOrTypeDescriptor;467internal_memcpy(&FilenameOrTypeDescriptor, Data,468sizeof(FilenameOrTypeDescriptor));469
470// Heuristic: For float_cast_overflow, the TypeKind will be either TK_Integer471// (0x0), TK_Float (0x1) or TK_Unknown (0xff). If both types are known,472// adding both bytes will be 0 or 1 (for BE or LE). If it were a filename,473// adding two printable characters will not yield such a value. Otherwise,474// if one of them is 0xff, this is most likely TK_Unknown type descriptor.475u16 MaybeFromTypeKind =476FilenameOrTypeDescriptor[0] + FilenameOrTypeDescriptor[1];477return MaybeFromTypeKind < 2 || FilenameOrTypeDescriptor[0] == 0xff ||478FilenameOrTypeDescriptor[1] == 0xff;479}
480
481static void handleFloatCastOverflow(void *DataPtr, ValueHandle From,482ReportOptions Opts) {483SymbolizedStackHolder CallerLoc;484Location Loc;485const TypeDescriptor *FromType, *ToType;486ErrorType ET = ErrorType::FloatCastOverflow;487
488if (looksLikeFloatCastOverflowDataV1(DataPtr)) {489auto Data = reinterpret_cast<FloatCastOverflowData *>(DataPtr);490CallerLoc.reset(getCallerLocation(Opts.pc));491Loc = CallerLoc;492FromType = &Data->FromType;493ToType = &Data->ToType;494} else {495auto Data = reinterpret_cast<FloatCastOverflowDataV2 *>(DataPtr);496SourceLocation SLoc = Data->Loc.acquire();497if (ignoreReport(SLoc, Opts, ET))498return;499Loc = SLoc;500FromType = &Data->FromType;501ToType = &Data->ToType;502}503
504ScopedReport R(Opts, Loc, ET);505
506Diag(Loc, DL_Error, ET,507"%0 is outside the range of representable values of type %2")508<< Value(*FromType, From) << *FromType << *ToType;509}
510
511void __ubsan::__ubsan_handle_float_cast_overflow(void *Data, ValueHandle From) {512GET_REPORT_OPTIONS(false);513handleFloatCastOverflow(Data, From, Opts);514}
515void __ubsan::__ubsan_handle_float_cast_overflow_abort(void *Data,516ValueHandle From) {517GET_REPORT_OPTIONS(true);518handleFloatCastOverflow(Data, From, Opts);519Die();520}
521
522static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,523ReportOptions Opts) {524SourceLocation Loc = Data->Loc.acquire();525// This check could be more precise if we used different handlers for526// -fsanitize=bool and -fsanitize=enum.527bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'")) ||528(0 == internal_strncmp(Data->Type.getTypeName(), "'BOOL'", 6));529ErrorType ET =530IsBool ? ErrorType::InvalidBoolLoad : ErrorType::InvalidEnumLoad;531
532if (ignoreReport(Loc, Opts, ET))533return;534
535ScopedReport R(Opts, Loc, ET);536
537Diag(Loc, DL_Error, ET,538"load of value %0, which is not a valid value for type %1")539<< Value(Data->Type, Val) << Data->Type;540}
541
542void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,543ValueHandle Val) {544GET_REPORT_OPTIONS(false);545handleLoadInvalidValue(Data, Val, Opts);546}
547void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data,548ValueHandle Val) {549GET_REPORT_OPTIONS(true);550handleLoadInvalidValue(Data, Val, Opts);551Die();552}
553
554static void handleImplicitConversion(ImplicitConversionData *Data,555ReportOptions Opts, ValueHandle Src,556ValueHandle Dst) {557SourceLocation Loc = Data->Loc.acquire();558const TypeDescriptor &SrcTy = Data->FromType;559const TypeDescriptor &DstTy = Data->ToType;560bool SrcSigned = SrcTy.isSignedIntegerTy();561bool DstSigned = DstTy.isSignedIntegerTy();562ErrorType ET = ErrorType::GenericUB;563
564switch (Data->Kind) {565case ICCK_IntegerTruncation: { // Legacy, no longer used.566// Let's figure out what it should be as per the new types, and upgrade.567// If both types are unsigned, then it's an unsigned truncation.568// Else, it is a signed truncation.569if (!SrcSigned && !DstSigned) {570ET = ErrorType::ImplicitUnsignedIntegerTruncation;571} else {572ET = ErrorType::ImplicitSignedIntegerTruncation;573}574break;575}576case ICCK_UnsignedIntegerTruncation:577ET = ErrorType::ImplicitUnsignedIntegerTruncation;578break;579case ICCK_SignedIntegerTruncation:580ET = ErrorType::ImplicitSignedIntegerTruncation;581break;582case ICCK_IntegerSignChange:583ET = ErrorType::ImplicitIntegerSignChange;584break;585case ICCK_SignedIntegerTruncationOrSignChange:586ET = ErrorType::ImplicitSignedIntegerTruncationOrSignChange;587break;588}589
590if (ignoreReport(Loc, Opts, ET))591return;592
593ScopedReport R(Opts, Loc, ET);594
595// In the case we have a bitfield, we want to explicitly say so in the596// error message.597// FIXME: is it possible to dump the values as hex with fixed width?598if (Data->BitfieldBits)599Diag(Loc, DL_Error, ET,600"implicit conversion from type %0 of value %1 (%2-bit, %3signed) to "601"type %4 changed the value to %5 (%6-bit bitfield, %7signed)")602<< SrcTy << Value(SrcTy, Src) << SrcTy.getIntegerBitWidth()603<< (SrcSigned ? "" : "un") << DstTy << Value(DstTy, Dst)604<< Data->BitfieldBits << (DstSigned ? "" : "un");605else606Diag(Loc, DL_Error, ET,607"implicit conversion from type %0 of value %1 (%2-bit, %3signed) to "608"type %4 changed the value to %5 (%6-bit, %7signed)")609<< SrcTy << Value(SrcTy, Src) << SrcTy.getIntegerBitWidth()610<< (SrcSigned ? "" : "un") << DstTy << Value(DstTy, Dst)611<< DstTy.getIntegerBitWidth() << (DstSigned ? "" : "un");612}
613
614void __ubsan::__ubsan_handle_implicit_conversion(ImplicitConversionData *Data,615ValueHandle Src,616ValueHandle Dst) {617GET_REPORT_OPTIONS(false);618handleImplicitConversion(Data, Opts, Src, Dst);619}
620void __ubsan::__ubsan_handle_implicit_conversion_abort(621ImplicitConversionData *Data, ValueHandle Src, ValueHandle Dst) {622GET_REPORT_OPTIONS(true);623handleImplicitConversion(Data, Opts, Src, Dst);624Die();625}
626
627static void handleInvalidBuiltin(InvalidBuiltinData *Data, ReportOptions Opts) {628SourceLocation Loc = Data->Loc.acquire();629ErrorType ET = ErrorType::InvalidBuiltin;630
631if (ignoreReport(Loc, Opts, ET))632return;633
634ScopedReport R(Opts, Loc, ET);635
636Diag(Loc, DL_Error, ET,637"passing zero to %0, which is not a valid argument")638<< ((Data->Kind == BCK_CTZPassedZero) ? "ctz()" : "clz()");639}
640
641void __ubsan::__ubsan_handle_invalid_builtin(InvalidBuiltinData *Data) {642GET_REPORT_OPTIONS(true);643handleInvalidBuiltin(Data, Opts);644}
645void __ubsan::__ubsan_handle_invalid_builtin_abort(InvalidBuiltinData *Data) {646GET_REPORT_OPTIONS(true);647handleInvalidBuiltin(Data, Opts);648Die();649}
650
651static void handleInvalidObjCCast(InvalidObjCCast *Data, ValueHandle Pointer,652ReportOptions Opts) {653SourceLocation Loc = Data->Loc.acquire();654ErrorType ET = ErrorType::InvalidObjCCast;655
656if (ignoreReport(Loc, Opts, ET))657return;658
659ScopedReport R(Opts, Loc, ET);660
661const char *GivenClass = getObjCClassName(Pointer);662const char *GivenClassStr = GivenClass ? GivenClass : "<unknown type>";663
664Diag(Loc, DL_Error, ET,665"invalid ObjC cast, object is a '%0', but expected a %1")666<< GivenClassStr << Data->ExpectedType;667}
668
669void __ubsan::__ubsan_handle_invalid_objc_cast(InvalidObjCCast *Data,670ValueHandle Pointer) {671GET_REPORT_OPTIONS(false);672handleInvalidObjCCast(Data, Pointer, Opts);673}
674void __ubsan::__ubsan_handle_invalid_objc_cast_abort(InvalidObjCCast *Data,675ValueHandle Pointer) {676GET_REPORT_OPTIONS(true);677handleInvalidObjCCast(Data, Pointer, Opts);678Die();679}
680
681static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr,682ReportOptions Opts, bool IsAttr) {683if (!LocPtr)684UNREACHABLE("source location pointer is null!");685
686SourceLocation Loc = LocPtr->acquire();687ErrorType ET = IsAttr ? ErrorType::InvalidNullReturn688: ErrorType::InvalidNullReturnWithNullability;689
690if (ignoreReport(Loc, Opts, ET))691return;692
693ScopedReport R(Opts, Loc, ET);694
695Diag(Loc, DL_Error, ET,696"null pointer returned from function declared to never return null");697if (!Data->AttrLoc.isInvalid())698Diag(Data->AttrLoc, DL_Note, ET, "%0 specified here")699<< (IsAttr ? "returns_nonnull attribute"700: "_Nonnull return type annotation");701}
702
703void __ubsan::__ubsan_handle_nonnull_return_v1(NonNullReturnData *Data,704SourceLocation *LocPtr) {705GET_REPORT_OPTIONS(false);706handleNonNullReturn(Data, LocPtr, Opts, true);707}
708
709void __ubsan::__ubsan_handle_nonnull_return_v1_abort(NonNullReturnData *Data,710SourceLocation *LocPtr) {711GET_REPORT_OPTIONS(true);712handleNonNullReturn(Data, LocPtr, Opts, true);713Die();714}
715
716void __ubsan::__ubsan_handle_nullability_return_v1(NonNullReturnData *Data,717SourceLocation *LocPtr) {718GET_REPORT_OPTIONS(false);719handleNonNullReturn(Data, LocPtr, Opts, false);720}
721
722void __ubsan::__ubsan_handle_nullability_return_v1_abort(723NonNullReturnData *Data, SourceLocation *LocPtr) {724GET_REPORT_OPTIONS(true);725handleNonNullReturn(Data, LocPtr, Opts, false);726Die();727}
728
729static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts,730bool IsAttr) {731SourceLocation Loc = Data->Loc.acquire();732ErrorType ET = IsAttr ? ErrorType::InvalidNullArgument733: ErrorType::InvalidNullArgumentWithNullability;734
735if (ignoreReport(Loc, Opts, ET))736return;737
738ScopedReport R(Opts, Loc, ET);739
740Diag(Loc, DL_Error, ET,741"null pointer passed as argument %0, which is declared to "742"never be null")743<< Data->ArgIndex;744if (!Data->AttrLoc.isInvalid())745Diag(Data->AttrLoc, DL_Note, ET, "%0 specified here")746<< (IsAttr ? "nonnull attribute" : "_Nonnull type annotation");747}
748
749void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) {750GET_REPORT_OPTIONS(false);751handleNonNullArg(Data, Opts, true);752}
753
754void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) {755GET_REPORT_OPTIONS(true);756handleNonNullArg(Data, Opts, true);757Die();758}
759
760void __ubsan::__ubsan_handle_nullability_arg(NonNullArgData *Data) {761GET_REPORT_OPTIONS(false);762handleNonNullArg(Data, Opts, false);763}
764
765void __ubsan::__ubsan_handle_nullability_arg_abort(NonNullArgData *Data) {766GET_REPORT_OPTIONS(true);767handleNonNullArg(Data, Opts, false);768Die();769}
770
771static void handlePointerOverflowImpl(PointerOverflowData *Data,772ValueHandle Base,773ValueHandle Result,774ReportOptions Opts) {775SourceLocation Loc = Data->Loc.acquire();776ErrorType ET;777
778if (Base == 0 && Result == 0)779ET = ErrorType::NullptrWithOffset;780else if (Base == 0 && Result != 0)781ET = ErrorType::NullptrWithNonZeroOffset;782else if (Base != 0 && Result == 0)783ET = ErrorType::NullptrAfterNonZeroOffset;784else785ET = ErrorType::PointerOverflow;786
787if (ignoreReport(Loc, Opts, ET))788return;789
790ScopedReport R(Opts, Loc, ET);791
792if (ET == ErrorType::NullptrWithOffset) {793Diag(Loc, DL_Error, ET, "applying zero offset to null pointer");794} else if (ET == ErrorType::NullptrWithNonZeroOffset) {795Diag(Loc, DL_Error, ET, "applying non-zero offset %0 to null pointer")796<< Result;797} else if (ET == ErrorType::NullptrAfterNonZeroOffset) {798Diag(799Loc, DL_Error, ET,800"applying non-zero offset to non-null pointer %0 produced null pointer")801<< (void *)Base;802} else if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) {803if (Base > Result)804Diag(Loc, DL_Error, ET,805"addition of unsigned offset to %0 overflowed to %1")806<< (void *)Base << (void *)Result;807else808Diag(Loc, DL_Error, ET,809"subtraction of unsigned offset from %0 overflowed to %1")810<< (void *)Base << (void *)Result;811} else {812Diag(Loc, DL_Error, ET,813"pointer index expression with base %0 overflowed to %1")814<< (void *)Base << (void *)Result;815}816}
817
818void __ubsan::__ubsan_handle_pointer_overflow(PointerOverflowData *Data,819ValueHandle Base,820ValueHandle Result) {821GET_REPORT_OPTIONS(false);822handlePointerOverflowImpl(Data, Base, Result, Opts);823}
824
825void __ubsan::__ubsan_handle_pointer_overflow_abort(PointerOverflowData *Data,826ValueHandle Base,827ValueHandle Result) {828GET_REPORT_OPTIONS(true);829handlePointerOverflowImpl(Data, Base, Result, Opts);830Die();831}
832
833static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function,834ReportOptions Opts) {835if (Data->CheckKind != CFITCK_ICall && Data->CheckKind != CFITCK_NVMFCall)836Die();837
838SourceLocation Loc = Data->Loc.acquire();839ErrorType ET = ErrorType::CFIBadType;840
841if (ignoreReport(Loc, Opts, ET))842return;843
844ScopedReport R(Opts, Loc, ET);845
846const char *CheckKindStr = Data->CheckKind == CFITCK_NVMFCall847? "non-virtual pointer to member function call"848: "indirect function call";849Diag(Loc, DL_Error, ET,850"control flow integrity check for type %0 failed during %1")851<< Data->Type << CheckKindStr;852
853SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));854const char *FName = FLoc.get()->info.function;855if (!FName)856FName = "(unknown)";857Diag(FLoc, DL_Note, ET, "%0 defined here") << FName;858
859// If the failure involved different DSOs for the check location and icall860// target, report the DSO names.861const char *DstModule = FLoc.get()->info.module;862if (!DstModule)863DstModule = "(unknown)";864
865const char *SrcModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Opts.pc);866if (!SrcModule)867SrcModule = "(unknown)";868
869if (internal_strcmp(SrcModule, DstModule))870Diag(Loc, DL_Note, ET,871"check failed in %0, destination function located in %1")872<< SrcModule << DstModule;873}
874
875namespace __ubsan {876
877#ifdef UBSAN_CAN_USE_CXXABI878
879#ifdef _WIN32880
881extern "C" void __ubsan_handle_cfi_bad_type_default(CFICheckFailData *Data,882ValueHandle Vtable,883bool ValidVtable,884ReportOptions Opts) {885Die();886}
887
888WIN_WEAK_ALIAS(__ubsan_handle_cfi_bad_type, __ubsan_handle_cfi_bad_type_default)889#else890SANITIZER_WEAK_ATTRIBUTE
891#endif892void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,893bool ValidVtable, ReportOptions Opts);894
895#else896void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,897bool ValidVtable, ReportOptions Opts) {898Die();899}
900#endif901
902} // namespace __ubsan903
904void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,905ValueHandle Value,906uptr ValidVtable) {907GET_REPORT_OPTIONS(false);908if (Data->CheckKind == CFITCK_ICall || Data->CheckKind == CFITCK_NVMFCall)909handleCFIBadIcall(Data, Value, Opts);910else911__ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts);912}
913
914void __ubsan::__ubsan_handle_cfi_check_fail_abort(CFICheckFailData *Data,915ValueHandle Value,916uptr ValidVtable) {917GET_REPORT_OPTIONS(true);918if (Data->CheckKind == CFITCK_ICall || Data->CheckKind == CFITCK_NVMFCall)919handleCFIBadIcall(Data, Value, Opts);920else921__ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts);922Die();923}
924
925static bool handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,926ValueHandle Function,927ReportOptions Opts) {928SourceLocation CallLoc = Data->Loc.acquire();929ErrorType ET = ErrorType::FunctionTypeMismatch;930if (ignoreReport(CallLoc, Opts, ET))931return true;932
933ScopedReport R(Opts, CallLoc, ET);934
935SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));936const char *FName = FLoc.get()->info.function;937if (!FName)938FName = "(unknown)";939
940Diag(CallLoc, DL_Error, ET,941"call to function %0 through pointer to incorrect function type %1")942<< FName << Data->Type;943Diag(FLoc, DL_Note, ET, "%0 defined here") << FName;944return true;945}
946
947void __ubsan::__ubsan_handle_function_type_mismatch(948FunctionTypeMismatchData *Data, ValueHandle Function) {949GET_REPORT_OPTIONS(false);950handleFunctionTypeMismatch(Data, Function, Opts);951}
952
953void __ubsan::__ubsan_handle_function_type_mismatch_abort(954FunctionTypeMismatchData *Data, ValueHandle Function) {955GET_REPORT_OPTIONS(true);956if (handleFunctionTypeMismatch(Data, Function, Opts))957Die();958}
959
960#endif // CAN_SANITIZE_UB961