diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index dff23348729a2..c0b02a104d95e 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -2009,11 +2009,12 @@ Value *CodeGenFunction::EmitCheckedArgForBuiltin(const Expr *E, if (!SanOpts.has(SanitizerKind::Builtin)) return ArgValue; - SanitizerScope SanScope(this); + auto CheckOrdinal = SanitizerKind::SO_Builtin; + auto CheckHandler = SanitizerHandler::InvalidBuiltin; + SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler); Value *Cond = Builder.CreateICmpNE( ArgValue, llvm::Constant::getNullValue(ArgValue->getType())); - EmitCheck(std::make_pair(Cond, SanitizerKind::SO_Builtin), - SanitizerHandler::InvalidBuiltin, + EmitCheck(std::make_pair(Cond, CheckOrdinal), CheckHandler, {EmitCheckSourceLocation(E->getExprLoc()), llvm::ConstantInt::get(Builder.getInt8Ty(), Kind)}, {}); @@ -2025,10 +2026,11 @@ Value *CodeGenFunction::EmitCheckedArgForAssume(const Expr *E) { if (!SanOpts.has(SanitizerKind::Builtin)) return ArgValue; - SanitizerScope SanScope(this); + auto CheckOrdinal = SanitizerKind::SO_Builtin; + auto CheckHandler = SanitizerHandler::InvalidBuiltin; + SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler); EmitCheck( - std::make_pair(ArgValue, SanitizerKind::SO_Builtin), - SanitizerHandler::InvalidBuiltin, + std::make_pair(ArgValue, CheckOrdinal), CheckHandler, {EmitCheckSourceLocation(E->getExprLoc()), llvm::ConstantInt::get(Builder.getInt8Ty(), BCK_AssumePassedFalse)}, std::nullopt); @@ -2051,7 +2053,15 @@ static Value *EmitOverflowCheckedAbs(CodeGenFunction &CGF, const CallExpr *E, return EmitAbs(CGF, ArgValue, true); } - CodeGenFunction::SanitizerScope SanScope(&CGF); + SmallVector Ordinals; + SanitizerHandler CheckHandler; + if (SanitizeOverflow) { + Ordinals.push_back(SanitizerKind::SO_SignedIntegerOverflow); + CheckHandler = SanitizerHandler::NegateOverflow; + } else + CheckHandler = SanitizerHandler::SubOverflow; + + SanitizerDebugLocation SanScope(&CGF, Ordinals, CheckHandler); Constant *Zero = Constant::getNullValue(ArgValue->getType()); Value *ResultAndOverflow = CGF.Builder.CreateBinaryIntrinsic( @@ -2063,12 +2073,12 @@ static Value *EmitOverflowCheckedAbs(CodeGenFunction &CGF, const CallExpr *E, // TODO: support -ftrapv-handler. if (SanitizeOverflow) { CGF.EmitCheck({{NotOverflow, SanitizerKind::SO_SignedIntegerOverflow}}, - SanitizerHandler::NegateOverflow, + CheckHandler, {CGF.EmitCheckSourceLocation(E->getArg(0)->getExprLoc()), CGF.EmitCheckTypeDescriptor(E->getType())}, {ArgValue}); } else - CGF.EmitTrapCheck(NotOverflow, SanitizerHandler::SubOverflow); + CGF.EmitTrapCheck(NotOverflow, CheckHandler); Value *CmpResult = CGF.Builder.CreateICmpSLT(ArgValue, Zero, "abscond"); return CGF.Builder.CreateSelect(CmpResult, Result, ArgValue, "abs"); diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 46a5d64412275..75df821ed536d 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -4184,7 +4184,7 @@ void CodeGenFunction::EmitReturnValueCheck(llvm::Value *RV) { Handler = SanitizerHandler::NullabilityReturn; } - SanitizerScope SanScope(this); + SanitizerDebugLocation SanScope(this, {CheckKind}, Handler); // Make sure the "return" source location is valid. If we're checking a // nullability annotation, make sure the preconditions for the check are met. @@ -4569,7 +4569,7 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType, Handler = SanitizerHandler::NullabilityArg; } - SanitizerScope SanScope(this); + SanitizerDebugLocation SanScope(this, {CheckKind}, Handler); llvm::Value *Cond = EmitNonNullRValueCheck(RV, ArgType); llvm::Constant *StaticData[] = { EmitCheckSourceLocation(ArgLoc), diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 251b059c256f6..13792c1042046 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -2817,7 +2817,8 @@ void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXRecordDecl *RD, RD = LeastDerivedClassWithSameLayout(RD); auto [Ordinal, _] = SanitizerInfoFromCFICheckKind(TCK); - ApplyDebugLocation ApplyTrapDI(*this, SanitizerAnnotateDebugInfo(Ordinal)); + SanitizerDebugLocation SanScope(this, {Ordinal}, + SanitizerHandler::CFICheckFail); EmitVTablePtrCheck(RD, VTable, TCK, Loc); } @@ -2842,7 +2843,8 @@ void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T, Address Derived, ClassDecl = LeastDerivedClassWithSameLayout(ClassDecl); auto [Ordinal, _] = SanitizerInfoFromCFICheckKind(TCK); - ApplyDebugLocation ApplyTrapDI(*this, SanitizerAnnotateDebugInfo(Ordinal)); + SanitizerDebugLocation SanScope(this, {Ordinal}, + SanitizerHandler::CFICheckFail); llvm::BasicBlock *ContBlock = nullptr; @@ -2874,6 +2876,8 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD, llvm::Value *VTable, CFITypeCheckKind TCK, SourceLocation Loc) { + assert(IsSanitizerScope); + if (!CGM.getCodeGenOpts().SanitizeCfiCrossDso && !CGM.HasHiddenLTOVisibility(RD)) return; @@ -2885,7 +2889,6 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD, SanitizerMask::bitPosToMask(M), TypeName)) return; - SanitizerScope SanScope(this); EmitSanitizerStatReport(SSK); llvm::Metadata *MD = @@ -2942,11 +2945,11 @@ bool CodeGenFunction::ShouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *RD) { llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad( const CXXRecordDecl *RD, llvm::Value *VTable, llvm::Type *VTableTy, uint64_t VTableByteOffset) { - SanitizerScope SanScope(this); + auto CheckOrdinal = SanitizerKind::SO_CFIVCall; + auto CheckHandler = SanitizerHandler::CFICheckFail; + SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler); EmitSanitizerStatReport(llvm::SanStat_CFI_VCall); - ApplyDebugLocation ApplyTrapDI( - *this, SanitizerAnnotateDebugInfo(SanitizerKind::SO_CFIVCall)); llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0)); @@ -2965,8 +2968,7 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad( if (SanOpts.has(SanitizerKind::CFIVCall) && !getContext().getNoSanitizeList().containsType(SanitizerKind::CFIVCall, TypeName)) { - EmitCheck(std::make_pair(CheckResult, SanitizerKind::SO_CFIVCall), - SanitizerHandler::CFICheckFail, {}, {}); + EmitCheck(std::make_pair(CheckResult, CheckOrdinal), CheckHandler, {}, {}); } return Builder.CreateBitCast(Builder.CreateExtractValue(CheckedLoad, 0), diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index fbcc330aca6bb..001b208e1c3ff 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -58,6 +58,13 @@ using namespace clang; using namespace clang::CodeGen; +// TODO: consider deprecating ClArrayBoundsPseudoFn; functionality is subsumed +// by -fsanitize-annotate-debug-info +static llvm::cl::opt ClArrayBoundsPseudoFn( + "array-bounds-pseudofn", llvm::cl::Hidden, llvm::cl::Optional, + llvm::cl::desc("Emit debug info that places array-bounds instrumentation " + "in an inline function called __ubsan_check_array_bounds.")); + static uint32_t getTypeAlignIfRequired(const Type *Ty, const ASTContext &Ctx) { auto TI = Ctx.getTypeInfo(Ty); if (TI.isAlignRequired()) @@ -6412,3 +6419,78 @@ CodeGenFunction::LexicalScope::~LexicalScope() { ForceCleanup(); } } + +static std::string SanitizerHandlerToCheckLabel(SanitizerHandler Handler) { + std::string Label; + switch (Handler) { +#define SANITIZER_CHECK(Enum, Name, Version) \ + case Enum: \ + Label = "__ubsan_check_" #Name; \ + break; + + LIST_SANITIZER_CHECKS +#undef SANITIZER_CHECK + }; + + // Label doesn't require sanitization + return Label; +} + +static std::string +SanitizerOrdinalToCheckLabel(SanitizerKind::SanitizerOrdinal Ordinal) { + std::string Label; + switch (Ordinal) { +#define SANITIZER(NAME, ID) \ + case SanitizerKind::SO_##ID: \ + Label = "__ubsan_check_" NAME; \ + break; +#include "clang/Basic/Sanitizers.def" + default: + llvm_unreachable("unexpected sanitizer kind"); + } + + // Sanitize label (convert hyphens to underscores; also futureproof against + // non-alpha) + for (unsigned int i = 0; i < Label.length(); i++) + if (!std::isalpha(Label[i])) + Label[i] = '_'; + + return Label; +} + +llvm::DILocation *CodeGenFunction::SanitizerAnnotateDebugInfo( + ArrayRef Ordinals, + SanitizerHandler Handler) { + std::string Label; + if (Ordinals.size() == 1) + Label = SanitizerOrdinalToCheckLabel(Ordinals[0]); + else + Label = SanitizerHandlerToCheckLabel(Handler); + + llvm::DILocation *CheckDI = Builder.getCurrentDebugLocation(); + + for (auto Ord : Ordinals) { + // TODO: deprecate ClArrayBoundsPseudoFn + if (((ClArrayBoundsPseudoFn && Ord == SanitizerKind::SO_ArrayBounds) || + CGM.getCodeGenOpts().SanitizeAnnotateDebugInfo.has(Ord)) && + CheckDI) { + return getDebugInfo()->CreateSyntheticInlineAt(CheckDI, Label); + } + } + + return CheckDI; +} + +SanitizerDebugLocation::SanitizerDebugLocation( + CodeGenFunction *CGF, ArrayRef Ordinals, + SanitizerHandler Handler) + : CGF(CGF), + Apply(*CGF, CGF->SanitizerAnnotateDebugInfo(Ordinals, Handler)) { + assert(!CGF->IsSanitizerScope); + CGF->IsSanitizerScope = true; +} + +SanitizerDebugLocation::~SanitizerDebugLocation() { + assert(CGF->IsSanitizerScope); + CGF->IsSanitizerScope = false; +} diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index 855881744237c..16759f25123cd 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -14,6 +14,7 @@ #define LLVM_CLANG_LIB_CODEGEN_CGDEBUGINFO_H #include "CGBuilder.h" +#include "SanitizerHandler.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" #include "clang/AST/ExternalASTSource.h" @@ -974,6 +975,17 @@ class ApplyInlineDebugLocation { ~ApplyInlineDebugLocation(); }; +class SanitizerDebugLocation { + CodeGenFunction *CGF; + ApplyDebugLocation Apply; + +public: + SanitizerDebugLocation(CodeGenFunction *CGF, + ArrayRef Ordinals, + SanitizerHandler Handler); + ~SanitizerDebugLocation(); +}; + } // namespace CodeGen } // namespace clang diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index e487a2bc0353d..04f13c7d7a6a3 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -766,14 +766,15 @@ void CodeGenFunction::EmitNullabilityCheck(LValue LHS, llvm::Value *RHS, // Check if the right hand side of the assignment is nonnull, if the left // hand side must be nonnull. - SanitizerScope SanScope(this); + auto CheckOrdinal = SanitizerKind::SO_NullabilityAssign; + auto CheckHandler = SanitizerHandler::TypeMismatch; + SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler); llvm::Value *IsNotNull = Builder.CreateIsNotNull(RHS); llvm::Constant *StaticData[] = { EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(LHS.getType()), llvm::ConstantInt::get(Int8Ty, 0), // The LogAlignment info is unused. llvm::ConstantInt::get(Int8Ty, TCK_NonnullAssign)}; - EmitCheck({{IsNotNull, SanitizerKind::SO_NullabilityAssign}}, - SanitizerHandler::TypeMismatch, StaticData, RHS); + EmitCheck({{IsNotNull, CheckOrdinal}}, CheckHandler, StaticData, RHS); } void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D, diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 1099a547caa5a..6cb348ffdf55f 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -65,13 +65,6 @@ llvm::cl::opt ClSanitizeGuardChecks( } // namespace clang -// TODO: consider deprecating ClArrayBoundsPseudoFn; functionality is subsumed -// by -fsanitize-annotate-debug-info -static llvm::cl::opt ClArrayBoundsPseudoFn( - "array-bounds-pseudofn", llvm::cl::Hidden, llvm::cl::Optional, - llvm::cl::desc("Emit debug info that places array-bounds instrumentation " - "in an inline function called __ubsan_check_array_bounds.")); - //===--------------------------------------------------------------------===// // Defines for metadata //===--------------------------------------------------------------------===// @@ -751,104 +744,116 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, if (Ty.isVolatileQualified()) return; - SanitizerScope SanScope(this); - - SmallVector, 3> - Checks; - llvm::BasicBlock *Done = nullptr; - // Quickly determine whether we have a pointer to an alloca. It's possible // to skip null checks, and some alignment checks, for these pointers. This // can reduce compile-time significantly. auto PtrToAlloca = dyn_cast(Ptr->stripPointerCasts()); - llvm::Value *True = llvm::ConstantInt::getTrue(getLLVMContext()); llvm::Value *IsNonNull = nullptr; bool IsGuaranteedNonNull = SkippedChecks.has(SanitizerKind::Null) || PtrToAlloca; - bool AllowNullPointers = isNullPointerAllowed(TCK); - if ((SanOpts.has(SanitizerKind::Null) || AllowNullPointers) && - !IsGuaranteedNonNull) { - // The glvalue must not be an empty glvalue. - IsNonNull = Builder.CreateIsNotNull(Ptr); - // The IR builder can constant-fold the null check if the pointer points to - // a constant. - IsGuaranteedNonNull = IsNonNull == True; - - // Skip the null check if the pointer is known to be non-null. - if (!IsGuaranteedNonNull) { - if (AllowNullPointers) { - // When performing pointer casts, it's OK if the value is null. - // Skip the remaining checks in that case. - Done = createBasicBlock("null"); - llvm::BasicBlock *Rest = createBasicBlock("not.null"); - Builder.CreateCondBr(IsNonNull, Rest, Done); - EmitBlock(Rest); - } else { - Checks.push_back(std::make_pair(IsNonNull, SanitizerKind::SO_Null)); + llvm::BasicBlock *Done = nullptr; + bool DoneViaNullSanitize = false; + + { + auto CheckHandler = SanitizerHandler::TypeMismatch; + SanitizerDebugLocation SanScope(this, + {SanitizerKind::SO_Null, + SanitizerKind::SO_ObjectSize, + SanitizerKind::SO_Alignment}, + CheckHandler); + + SmallVector, 3> + Checks; + + llvm::Value *True = llvm::ConstantInt::getTrue(getLLVMContext()); + bool AllowNullPointers = isNullPointerAllowed(TCK); + if ((SanOpts.has(SanitizerKind::Null) || AllowNullPointers) && + !IsGuaranteedNonNull) { + // The glvalue must not be an empty glvalue. + IsNonNull = Builder.CreateIsNotNull(Ptr); + + // The IR builder can constant-fold the null check if the pointer points + // to a constant. + IsGuaranteedNonNull = IsNonNull == True; + + // Skip the null check if the pointer is known to be non-null. + if (!IsGuaranteedNonNull) { + if (AllowNullPointers) { + // When performing pointer casts, it's OK if the value is null. + // Skip the remaining checks in that case. + Done = createBasicBlock("null"); + DoneViaNullSanitize = true; + llvm::BasicBlock *Rest = createBasicBlock("not.null"); + Builder.CreateCondBr(IsNonNull, Rest, Done); + EmitBlock(Rest); + } else { + Checks.push_back(std::make_pair(IsNonNull, SanitizerKind::SO_Null)); + } } } - } - if (SanOpts.has(SanitizerKind::ObjectSize) && - !SkippedChecks.has(SanitizerKind::ObjectSize) && - !Ty->isIncompleteType()) { - uint64_t TySize = CGM.getMinimumObjectSize(Ty).getQuantity(); - llvm::Value *Size = llvm::ConstantInt::get(IntPtrTy, TySize); - if (ArraySize) - Size = Builder.CreateMul(Size, ArraySize); - - // Degenerate case: new X[0] does not need an objectsize check. - llvm::Constant *ConstantSize = dyn_cast(Size); - if (!ConstantSize || !ConstantSize->isNullValue()) { - // The glvalue must refer to a large enough storage region. - // FIXME: If Address Sanitizer is enabled, insert dynamic instrumentation - // to check this. - // FIXME: Get object address space - llvm::Type *Tys[2] = { IntPtrTy, Int8PtrTy }; - llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, Tys); - llvm::Value *Min = Builder.getFalse(); - llvm::Value *NullIsUnknown = Builder.getFalse(); - llvm::Value *Dynamic = Builder.getFalse(); - llvm::Value *LargeEnough = Builder.CreateICmpUGE( - Builder.CreateCall(F, {Ptr, Min, NullIsUnknown, Dynamic}), Size); - Checks.push_back( - std::make_pair(LargeEnough, SanitizerKind::SO_ObjectSize)); + if (SanOpts.has(SanitizerKind::ObjectSize) && + !SkippedChecks.has(SanitizerKind::ObjectSize) && + !Ty->isIncompleteType()) { + uint64_t TySize = CGM.getMinimumObjectSize(Ty).getQuantity(); + llvm::Value *Size = llvm::ConstantInt::get(IntPtrTy, TySize); + if (ArraySize) + Size = Builder.CreateMul(Size, ArraySize); + + // Degenerate case: new X[0] does not need an objectsize check. + llvm::Constant *ConstantSize = dyn_cast(Size); + if (!ConstantSize || !ConstantSize->isNullValue()) { + // The glvalue must refer to a large enough storage region. + // FIXME: If Address Sanitizer is enabled, insert dynamic + // instrumentation + // to check this. + // FIXME: Get object address space + llvm::Type *Tys[2] = {IntPtrTy, Int8PtrTy}; + llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, Tys); + llvm::Value *Min = Builder.getFalse(); + llvm::Value *NullIsUnknown = Builder.getFalse(); + llvm::Value *Dynamic = Builder.getFalse(); + llvm::Value *LargeEnough = Builder.CreateICmpUGE( + Builder.CreateCall(F, {Ptr, Min, NullIsUnknown, Dynamic}), Size); + Checks.push_back( + std::make_pair(LargeEnough, SanitizerKind::SO_ObjectSize)); + } } - } - llvm::MaybeAlign AlignVal; - llvm::Value *PtrAsInt = nullptr; - - if (SanOpts.has(SanitizerKind::Alignment) && - !SkippedChecks.has(SanitizerKind::Alignment)) { - AlignVal = Alignment.getAsMaybeAlign(); - if (!Ty->isIncompleteType() && !AlignVal) - AlignVal = CGM.getNaturalTypeAlignment(Ty, nullptr, nullptr, - /*ForPointeeType=*/true) - .getAsMaybeAlign(); - - // The glvalue must be suitably aligned. - if (AlignVal && *AlignVal > llvm::Align(1) && - (!PtrToAlloca || PtrToAlloca->getAlign() < *AlignVal)) { - PtrAsInt = Builder.CreatePtrToInt(Ptr, IntPtrTy); - llvm::Value *Align = Builder.CreateAnd( - PtrAsInt, llvm::ConstantInt::get(IntPtrTy, AlignVal->value() - 1)); - llvm::Value *Aligned = - Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0)); - if (Aligned != True) - Checks.push_back(std::make_pair(Aligned, SanitizerKind::SO_Alignment)); + llvm::MaybeAlign AlignVal; + llvm::Value *PtrAsInt = nullptr; + + if (SanOpts.has(SanitizerKind::Alignment) && + !SkippedChecks.has(SanitizerKind::Alignment)) { + AlignVal = Alignment.getAsMaybeAlign(); + if (!Ty->isIncompleteType() && !AlignVal) + AlignVal = CGM.getNaturalTypeAlignment(Ty, nullptr, nullptr, + /*ForPointeeType=*/true) + .getAsMaybeAlign(); + + // The glvalue must be suitably aligned. + if (AlignVal && *AlignVal > llvm::Align(1) && + (!PtrToAlloca || PtrToAlloca->getAlign() < *AlignVal)) { + PtrAsInt = Builder.CreatePtrToInt(Ptr, IntPtrTy); + llvm::Value *Align = Builder.CreateAnd( + PtrAsInt, llvm::ConstantInt::get(IntPtrTy, AlignVal->value() - 1)); + llvm::Value *Aligned = + Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0)); + if (Aligned != True) + Checks.push_back( + std::make_pair(Aligned, SanitizerKind::SO_Alignment)); + } } - } - if (Checks.size() > 0) { - llvm::Constant *StaticData[] = { - EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(Ty), - llvm::ConstantInt::get(Int8Ty, AlignVal ? llvm::Log2(*AlignVal) : 1), - llvm::ConstantInt::get(Int8Ty, TCK)}; - EmitCheck(Checks, SanitizerHandler::TypeMismatch, StaticData, - PtrAsInt ? PtrAsInt : Ptr); + if (Checks.size() > 0) { + llvm::Constant *StaticData[] = { + EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(Ty), + llvm::ConstantInt::get(Int8Ty, AlignVal ? llvm::Log2(*AlignVal) : 1), + llvm::ConstantInt::get(Int8Ty, TCK)}; + EmitCheck(Checks, CheckHandler, StaticData, PtrAsInt ? PtrAsInt : Ptr); + } } // If possible, check that the vptr indicates that there is a subobject of @@ -861,6 +866,9 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, // or call a non-static member function if (SanOpts.has(SanitizerKind::Vptr) && !SkippedChecks.has(SanitizerKind::Vptr) && isVptrCheckRequired(TCK, Ty)) { + SanitizerDebugLocation SanScope(this, {SanitizerKind::SO_Vptr}, + SanitizerHandler::DynamicTypeCacheMiss); + // Ensure that the pointer is non-null before loading it. If there is no // compile-time guarantee, reuse the run-time null check or emit a new one. if (!IsGuaranteedNonNull) { @@ -929,6 +937,11 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, } if (Done) { + SanitizerDebugLocation SanScope( + this, + {DoneViaNullSanitize ? SanitizerKind::SO_Null : SanitizerKind::SO_Vptr}, + DoneViaNullSanitize ? SanitizerHandler::TypeMismatch + : SanitizerHandler::DynamicTypeCacheMiss); Builder.CreateBr(Done); EmitBlock(Done); } @@ -1227,10 +1240,9 @@ void CodeGenFunction::EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound, if (!Bound) return; - SanitizerScope SanScope(this); - auto CheckKind = SanitizerKind::SO_ArrayBounds; - ApplyDebugLocation ApplyTrapDI(*this, SanitizerAnnotateDebugInfo(CheckKind)); + auto CheckHandler = SanitizerHandler::OutOfBounds; + SanitizerDebugLocation SanScope(this, {CheckKind}, CheckHandler); bool IndexSigned = IndexType->isSignedIntegerOrEnumerationType(); llvm::Value *IndexVal = Builder.CreateIntCast(Index, SizeTy, IndexSigned); @@ -1243,37 +1255,7 @@ void CodeGenFunction::EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound, }; llvm::Value *Check = Accessed ? Builder.CreateICmpULT(IndexVal, BoundVal) : Builder.CreateICmpULE(IndexVal, BoundVal); - EmitCheck(std::make_pair(Check, CheckKind), SanitizerHandler::OutOfBounds, - StaticData, Index); -} - -llvm::DILocation *CodeGenFunction::SanitizerAnnotateDebugInfo( - SanitizerKind::SanitizerOrdinal CheckKindOrdinal) { - std::string Label; - switch (CheckKindOrdinal) { -#define SANITIZER(NAME, ID) \ - case SanitizerKind::SO_##ID: \ - Label = "__ubsan_check_" NAME; \ - break; -#include "clang/Basic/Sanitizers.def" - default: - llvm_unreachable("unexpected sanitizer kind"); - } - - // Sanitize label - for (unsigned int i = 0; i < Label.length(); i++) - if (!std::isalpha(Label[i])) - Label[i] = '_'; - - llvm::DILocation *CheckDI = Builder.getCurrentDebugLocation(); - // TODO: deprecate ClArrayBoundsPseudoFn - if (((ClArrayBoundsPseudoFn && - CheckKindOrdinal == SanitizerKind::SO_ArrayBounds) || - CGM.getCodeGenOpts().SanitizeAnnotateDebugInfo.has(CheckKindOrdinal)) && - CheckDI) - CheckDI = getDebugInfo()->CreateSyntheticInlineAt(CheckDI, Label); - - return CheckDI; + EmitCheck(std::make_pair(Check, CheckKind), CheckHandler, StaticData, Index); } CodeGenFunction::ComplexPairTy CodeGenFunction:: @@ -1997,8 +1979,12 @@ bool CodeGenFunction::EmitScalarRangeCheck(llvm::Value *Value, QualType Ty, if (!getRangeForType(*this, Ty, Min, End, /*StrictEnums=*/true, IsBool)) return true; + SanitizerKind::SanitizerOrdinal Kind = + NeedsEnumCheck ? SanitizerKind::SO_Enum : SanitizerKind::SO_Bool; + auto &Ctx = getLLVMContext(); - SanitizerScope SanScope(this); + auto CheckHandler = SanitizerHandler::LoadInvalidValue; + SanitizerDebugLocation SanScope(this, {Kind}, CheckHandler); llvm::Value *Check; --End; if (!Min) { @@ -2012,10 +1998,7 @@ bool CodeGenFunction::EmitScalarRangeCheck(llvm::Value *Value, QualType Ty, } llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(Ty)}; - SanitizerKind::SanitizerOrdinal Kind = - NeedsEnumCheck ? SanitizerKind::SO_Enum : SanitizerKind::SO_Bool; - EmitCheck(std::make_pair(Check, Kind), SanitizerHandler::LoadInvalidValue, - StaticArgs, Value); + EmitCheck(std::make_pair(Check, Kind), CheckHandler, StaticArgs, Value); return true; } @@ -3938,7 +3921,17 @@ void CodeGenFunction::EmitCfiCheckStub() { // can be nullptr if the calling module has -fsanitize-trap behavior for this // check kind; in this case __cfi_check_fail traps as well. void CodeGenFunction::EmitCfiCheckFail() { - SanitizerScope SanScope(this); + auto CheckHandler = SanitizerHandler::CFICheckFail; + // TODO: the SanitizerKind is not yet determined for this check (and might + // not even be available, if Data == nullptr). However, we still want to + // annotate the instrumentation. We approximate this by using all the CFI + // kinds. + SanitizerDebugLocation SanScope( + this, + {SanitizerKind::SO_CFIVCall, SanitizerKind::SO_CFINVCall, + SanitizerKind::SO_CFIDerivedCast, SanitizerKind::SO_CFIUnrelatedCast, + SanitizerKind::SO_CFIICall}, + CheckHandler); FunctionArgList Args; ImplicitParamDecl ArgData(getContext(), getContext().VoidPtrTy, ImplicitParamKind::Other); @@ -4001,8 +3994,6 @@ void CodeGenFunction::EmitCfiCheckFail() { {Addr, AllVtables}), IntPtrTy); - // TODO: the instructions above are not annotated with debug info. It is - // inconvenient to do so because we have not determined SanitizerKind yet. const std::pair CheckKinds[] = { {CFITCK_VCall, SanitizerKind::SO_CFIVCall}, {CFITCK_NVCall, SanitizerKind::SO_CFINVCall}, @@ -4014,7 +4005,8 @@ void CodeGenFunction::EmitCfiCheckFail() { int Kind = CheckKindOrdinalPair.first; SanitizerKind::SanitizerOrdinal Ordinal = CheckKindOrdinalPair.second; - ApplyDebugLocation ApplyTrapDI(*this, SanitizerAnnotateDebugInfo(Ordinal)); + // TODO: we could apply SanitizerAnnotateDebugInfo(Ordinal) instead of + // relying on the SanitizerScope with all CFI ordinals llvm::Value *Cond = Builder.CreateICmpNE(CheckKind, llvm::ConstantInt::get(Int8Ty, Kind)); @@ -4026,7 +4018,7 @@ void CodeGenFunction::EmitCfiCheckFail() { // Although the compiler allows SanitizeMergeHandlers to be set // independently of CGM.getLangOpts().Sanitize, Driver/SanitizerArgs.cpp // requires that SanitizeMergeHandlers is a subset of Sanitize. - EmitTrapCheck(Cond, SanitizerHandler::CFICheckFail, /*NoMerge=*/false); + EmitTrapCheck(Cond, CheckHandler, /*NoMerge=*/false); } FinishFunction(); @@ -4037,11 +4029,12 @@ void CodeGenFunction::EmitCfiCheckFail() { void CodeGenFunction::EmitUnreachable(SourceLocation Loc) { if (SanOpts.has(SanitizerKind::Unreachable)) { - SanitizerScope SanScope(this); + auto CheckOrdinal = SanitizerKind::SO_Unreachable; + auto CheckHandler = SanitizerHandler::BuiltinUnreachable; + SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler); EmitCheck(std::make_pair(static_cast(Builder.getFalse()), - SanitizerKind::SO_Unreachable), - SanitizerHandler::BuiltinUnreachable, - EmitCheckSourceLocation(Loc), {}); + CheckOrdinal), + CheckHandler, EmitCheckSourceLocation(Loc), {}); } Builder.CreateUnreachable(); } @@ -6303,7 +6296,9 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, !isa(PointeeType)) { if (llvm::Constant *PrefixSig = CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM)) { - SanitizerScope SanScope(this); + auto CheckOrdinal = SanitizerKind::SO_Function; + auto CheckHandler = SanitizerHandler::FunctionTypeMismatch; + SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler); auto *TypeHash = getUBSanFunctionTypeHash(PointeeType); llvm::Type *PrefixSigType = PrefixSig->getType(); @@ -6363,9 +6358,8 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, Builder.CreateICmpEQ(CalleeTypeHash, TypeHash); llvm::Constant *StaticData[] = {EmitCheckSourceLocation(E->getBeginLoc()), EmitCheckTypeDescriptor(CalleeType)}; - EmitCheck(std::make_pair(CalleeTypeHashMatch, SanitizerKind::SO_Function), - SanitizerHandler::FunctionTypeMismatch, StaticData, - {CalleePtr}); + EmitCheck(std::make_pair(CalleeTypeHashMatch, CheckOrdinal), CheckHandler, + StaticData, {CalleePtr}); Builder.CreateBr(Cont); EmitBlock(Cont); @@ -6385,10 +6379,10 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, // function pointer is a member of the bit set for the function type. if (SanOpts.has(SanitizerKind::CFIICall) && (!TargetDecl || !isa(TargetDecl)) && !CFIUnchecked) { - SanitizerScope SanScope(this); + auto CheckOrdinal = SanitizerKind::SO_CFIICall; + auto CheckHandler = SanitizerHandler::CFICheckFail; + SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler); EmitSanitizerStatReport(llvm::SanStat_CFI_ICall); - ApplyDebugLocation ApplyTrapDI( - *this, SanitizerAnnotateDebugInfo(SanitizerKind::SO_CFIICall)); llvm::Metadata *MD; if (CGM.getCodeGenOpts().SanitizeCfiICallGeneralizePointers) @@ -6409,12 +6403,11 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, EmitCheckTypeDescriptor(QualType(FnType, 0)), }; if (CGM.getCodeGenOpts().SanitizeCfiCrossDso && CrossDsoTypeId) { - EmitCfiSlowPathCheck(SanitizerKind::SO_CFIICall, TypeTest, CrossDsoTypeId, - CalleePtr, StaticData); + EmitCfiSlowPathCheck(CheckOrdinal, TypeTest, CrossDsoTypeId, CalleePtr, + StaticData); } else { - EmitCheck(std::make_pair(TypeTest, SanitizerKind::SO_CFIICall), - SanitizerHandler::CFICheckFail, StaticData, - {CalleePtr, llvm::UndefValue::get(IntPtrTy)}); + EmitCheck(std::make_pair(TypeTest, CheckOrdinal), CheckHandler, + StaticData, {CalleePtr, llvm::UndefValue::get(IntPtrTy)}); } } diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 111b5805c6a94..193710bef2d16 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -999,7 +999,9 @@ void ScalarExprEmitter::EmitFloatConversionCheck( if (!isa(DstTy)) return; - CodeGenFunction::SanitizerScope SanScope(&CGF); + auto CheckOrdinal = SanitizerKind::SO_FloatCastOverflow; + auto CheckHandler = SanitizerHandler::FloatCastOverflow; + SanitizerDebugLocation SanScope(&CGF, {CheckOrdinal}, CheckHandler); using llvm::APFloat; using llvm::APSInt; @@ -1056,8 +1058,8 @@ void ScalarExprEmitter::EmitFloatConversionCheck( llvm::Constant *StaticArgs[] = {CGF.EmitCheckSourceLocation(Loc), CGF.EmitCheckTypeDescriptor(OrigSrcType), CGF.EmitCheckTypeDescriptor(DstType)}; - CGF.EmitCheck(std::make_pair(Check, SanitizerKind::SO_FloatCastOverflow), - SanitizerHandler::FloatCastOverflow, StaticArgs, OrigSrc); + CGF.EmitCheck(std::make_pair(Check, CheckOrdinal), CheckHandler, StaticArgs, + OrigSrc); } // Should be called within CodeGenFunction::SanitizerScope RAII scope. @@ -1134,18 +1136,31 @@ void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType, (!SrcSigned && DstSigned)) return; - CodeGenFunction::SanitizerScope SanScope(&CGF); - std::pair> - Check = - EmitIntegerTruncationCheckHelper(Src, SrcType, Dst, DstType, Builder); - // If the comparison result is 'i1 false', then the truncation was lossy. + Check; + + auto CheckHandler = SanitizerHandler::ImplicitConversion; + { + // We don't know the check kind until we call + // EmitIntegerTruncationCheckHelper, but we want to annotate + // EmitIntegerTruncationCheckHelper's instructions too. + SanitizerDebugLocation SanScope( + &CGF, + {SanitizerKind::SO_ImplicitUnsignedIntegerTruncation, + SanitizerKind::SO_ImplicitSignedIntegerTruncation}, + CheckHandler); + Check = + EmitIntegerTruncationCheckHelper(Src, SrcType, Dst, DstType, Builder); + // If the comparison result is 'i1 false', then the truncation was lossy. + } // Do we care about this type of truncation? if (!CGF.SanOpts.has(Check.second.second)) return; + SanitizerDebugLocation SanScope(&CGF, {Check.second.second}, CheckHandler); + // Does some SSCL ignore this type? if (CGF.getContext().isTypeIgnoredBySanitizer( SanitizerMask::bitPosToMask(Check.second.second), DstType)) @@ -1157,8 +1172,7 @@ void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType, llvm::ConstantInt::get(Builder.getInt8Ty(), Check.first), llvm::ConstantInt::get(Builder.getInt32Ty(), 0)}; - CGF.EmitCheck(Check.second, SanitizerHandler::ImplicitConversion, StaticArgs, - {Src, Dst}); + CGF.EmitCheck(Check.second, CheckHandler, StaticArgs, {Src, Dst}); } static llvm::Value *EmitIsNegativeTestHelper(Value *V, QualType VType, @@ -1272,7 +1286,13 @@ void ScalarExprEmitter::EmitIntegerSignChangeCheck(Value *Src, QualType SrcType, return; // That's it. We can't rule out any more cases with the data we have. - CodeGenFunction::SanitizerScope SanScope(&CGF); + auto CheckHandler = SanitizerHandler::ImplicitConversion; + SanitizerDebugLocation SanScope( + &CGF, + {SanitizerKind::SO_ImplicitIntegerSignChange, + SanitizerKind::SO_ImplicitUnsignedIntegerTruncation, + SanitizerKind::SO_ImplicitSignedIntegerTruncation}, + CheckHandler); std::pair> @@ -1308,8 +1328,7 @@ void ScalarExprEmitter::EmitIntegerSignChangeCheck(Value *Src, QualType SrcType, llvm::ConstantInt::get(Builder.getInt8Ty(), CheckKind), llvm::ConstantInt::get(Builder.getInt32Ty(), 0)}; // EmitCheck() will 'and' all the checks together. - CGF.EmitCheck(Checks, SanitizerHandler::ImplicitConversion, StaticArgs, - {Src, Dst}); + CGF.EmitCheck(Checks, CheckHandler, StaticArgs, {Src, Dst}); } // Should be called within CodeGenFunction::SanitizerScope RAII scope. @@ -1393,7 +1412,9 @@ void CodeGenFunction::EmitBitfieldConversionCheck(Value *Src, QualType SrcType, bool SrcSigned = SrcType->isSignedIntegerOrEnumerationType(); bool DstSigned = DstType->isSignedIntegerOrEnumerationType(); - CodeGenFunction::SanitizerScope SanScope(this); + auto CheckHandler = SanitizerHandler::ImplicitConversion; + SanitizerDebugLocation SanScope( + this, {SanitizerKind::SO_ImplicitBitfieldConversion}, CheckHandler); std::pair> @@ -1439,8 +1460,7 @@ void CodeGenFunction::EmitBitfieldConversionCheck(Value *Src, QualType SrcType, llvm::ConstantInt::get(Builder.getInt8Ty(), CheckKind), llvm::ConstantInt::get(Builder.getInt32Ty(), Info.Size)}; - EmitCheck(Check.second, SanitizerHandler::ImplicitConversion, StaticArgs, - {Src, Dst}); + EmitCheck(Check.second, CheckHandler, StaticArgs, {Src, Dst}); } Value *ScalarExprEmitter::EmitScalarCast(Value *Src, QualType SrcType, @@ -3975,7 +3995,11 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck( Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { { - CodeGenFunction::SanitizerScope SanScope(&CGF); + SanitizerDebugLocation SanScope(&CGF, + {SanitizerKind::SO_IntegerDivideByZero, + SanitizerKind::SO_SignedIntegerOverflow, + SanitizerKind::SO_FloatDivideByZero}, + SanitizerHandler::DivremOverflow); if ((CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero) || CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) && Ops.Ty->isIntegerType() && @@ -4029,7 +4053,10 @@ Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) { CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) && Ops.Ty->isIntegerType() && (Ops.mayHaveIntegerDivisionByZero() || Ops.mayHaveIntegerOverflow())) { - CodeGenFunction::SanitizerScope SanScope(&CGF); + SanitizerDebugLocation SanScope(&CGF, + {SanitizerKind::SO_IntegerDivideByZero, + SanitizerKind::SO_SignedIntegerOverflow}, + SanitizerHandler::DivremOverflow); llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty)); EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, false); } @@ -4078,7 +4105,10 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { if (isSigned) OpID |= 1; - CodeGenFunction::SanitizerScope SanScope(&CGF); + SanitizerDebugLocation SanScope(&CGF, + {SanitizerKind::SO_SignedIntegerOverflow, + SanitizerKind::SO_UnsignedIntegerOverflow}, + OverflowKind); llvm::Type *opTy = CGF.CGM.getTypes().ConvertType(Ops.Ty); llvm::Function *intrinsic = CGF.CGM.getIntrinsic(IID, opTy); @@ -4204,7 +4234,9 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF, PtrTy->getPointerAddressSpace())) return Ptr; // The inbounds GEP of null is valid iff the index is zero. - CodeGenFunction::SanitizerScope SanScope(&CGF); + auto CheckOrdinal = SanitizerKind::SO_PointerOverflow; + auto CheckHandler = SanitizerHandler::PointerOverflow; + SanitizerDebugLocation SanScope(&CGF, {CheckOrdinal}, CheckHandler); Value *IsZeroIndex = CGF.Builder.CreateIsNull(index); llvm::Constant *StaticArgs[] = { CGF.EmitCheckSourceLocation(op.E->getExprLoc())}; @@ -4212,8 +4244,8 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF, Value *IntPtr = llvm::Constant::getNullValue(IntPtrTy); Value *ComputedGEP = CGF.Builder.CreateZExtOrTrunc(index, IntPtrTy); Value *DynamicArgs[] = {IntPtr, ComputedGEP}; - CGF.EmitCheck({{IsZeroIndex, SanitizerKind::SO_PointerOverflow}}, - SanitizerHandler::PointerOverflow, StaticArgs, DynamicArgs); + CGF.EmitCheck({{IsZeroIndex, CheckOrdinal}}, CheckHandler, StaticArgs, + DynamicArgs); return Ptr; } @@ -4734,7 +4766,16 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) { RHS = ConstrainShiftValue(Ops.LHS, RHS, "shl.mask"); else if ((SanitizeBase || SanitizeExponent) && isa(Ops.LHS->getType())) { - CodeGenFunction::SanitizerScope SanScope(&CGF); + SmallVector Ordinals; + if (SanitizeSignedBase) + Ordinals.push_back(SanitizerKind::SO_ShiftBase); + if (SanitizeUnsignedBase) + Ordinals.push_back(SanitizerKind::SO_UnsignedShiftBase); + if (SanitizeExponent) + Ordinals.push_back(SanitizerKind::SO_ShiftExponent); + + SanitizerDebugLocation SanScope(&CGF, Ordinals, + SanitizerHandler::ShiftOutOfBounds); SmallVector, 2> Checks; bool RHSIsSigned = Ops.rhsHasSignedIntegerRepresentation(); llvm::Value *WidthMinusOne = @@ -4805,7 +4846,8 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) { RHS = ConstrainShiftValue(Ops.LHS, RHS, "shr.mask"); else if (CGF.SanOpts.has(SanitizerKind::ShiftExponent) && isa(Ops.LHS->getType())) { - CodeGenFunction::SanitizerScope SanScope(&CGF); + SanitizerDebugLocation SanScope(&CGF, {SanitizerKind::SO_ShiftExponent}, + SanitizerHandler::ShiftOutOfBounds); bool RHSIsSigned = Ops.rhsHasSignedIntegerRepresentation(); llvm::Value *Valid = Builder.CreateICmpULE( Ops.RHS, GetMaximumShiftAmount(Ops.LHS, Ops.RHS, RHSIsSigned)); @@ -6037,7 +6079,9 @@ CodeGenFunction::EmitCheckedInBoundsGEP(llvm::Type *ElemTy, Value *Ptr, const auto &DL = CGM.getDataLayout(); - SanitizerScope SanScope(this); + auto CheckOrdinal = SanitizerKind::SO_PointerOverflow; + auto CheckHandler = SanitizerHandler::PointerOverflow; + SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler); llvm::Type *IntPtrTy = DL.getIntPtrType(PtrTy); GEPOffsetAndOverflow EvaluatedGEP = @@ -6074,7 +6118,7 @@ CodeGenFunction::EmitCheckedInBoundsGEP(llvm::Type *ElemTy, Value *Ptr, auto *BaseIsNotNullptr = Builder.CreateIsNotNull(Ptr); auto *ResultIsNotNullptr = Builder.CreateIsNotNull(ComputedGEP); auto *Valid = Builder.CreateICmpEQ(BaseIsNotNullptr, ResultIsNotNullptr); - Checks.emplace_back(Valid, SanitizerKind::SO_PointerOverflow); + Checks.emplace_back(Valid, CheckOrdinal); } if (PerformOverflowCheck) { @@ -6110,7 +6154,7 @@ CodeGenFunction::EmitCheckedInBoundsGEP(llvm::Type *ElemTy, Value *Ptr, ValidGEP = Builder.CreateICmpULE(ComputedGEP, IntPtr); } ValidGEP = Builder.CreateAnd(ValidGEP, NoOffsetOverflow); - Checks.emplace_back(ValidGEP, SanitizerKind::SO_PointerOverflow); + Checks.emplace_back(ValidGEP, CheckOrdinal); } assert(!Checks.empty() && "Should have produced some checks."); @@ -6118,7 +6162,7 @@ CodeGenFunction::EmitCheckedInBoundsGEP(llvm::Type *ElemTy, Value *Ptr, llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc)}; // Pass the computed GEP to the runtime to avoid emitting poisoned arguments. llvm::Value *DynamicArgs[] = {IntPtr, ComputedGEP}; - EmitCheck(Checks, SanitizerHandler::PointerOverflow, StaticArgs, DynamicArgs); + EmitCheck(Checks, CheckHandler, StaticArgs, DynamicArgs); return GEPVal; } diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index ff1dae7de9cb6..8a1b44a0c157c 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -1968,7 +1968,9 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ const ObjCInterfaceType *InterfaceTy = ObjPtrTy ? ObjPtrTy->getInterfaceType() : nullptr; if (InterfaceTy) { - SanitizerScope SanScope(this); + auto CheckOrdinal = SanitizerKind::SO_ObjCCast; + auto CheckHandler = SanitizerHandler::InvalidObjCCast; + SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler); auto &C = CGM.getContext(); assert(InterfaceTy->getDecl() && "No decl for ObjC interface type"); Selector IsKindOfClassSel = GetUnarySelector("isKindOfClass", C); @@ -1985,8 +1987,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ llvm::Constant *StaticData[] = { EmitCheckSourceLocation(S.getBeginLoc()), EmitCheckTypeDescriptor(QualType(InterfaceTy, 0))}; - EmitCheck({{IsClass, SanitizerKind::SO_ObjCCast}}, - SanitizerHandler::InvalidObjCCast, + EmitCheck({{IsClass, CheckOrdinal}}, CheckHandler, ArrayRef(StaticData), CurrentItem); } } diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 3302abad87d65..56562002e7194 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -1636,10 +1636,11 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, CGM.getCodeGenOpts().StrictReturn || !CGM.MayDropFunctionReturn(FD->getASTContext(), FD->getReturnType()); if (SanOpts.has(SanitizerKind::Return)) { - SanitizerScope SanScope(this); + auto CheckOrdinal = SanitizerKind::SO_Return; + auto CheckHandler = SanitizerHandler::MissingReturn; + SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler); llvm::Value *IsFalse = Builder.getFalse(); - EmitCheck(std::make_pair(IsFalse, SanitizerKind::SO_Return), - SanitizerHandler::MissingReturn, + EmitCheck(std::make_pair(IsFalse, CheckOrdinal), CheckHandler, EmitCheckSourceLocation(FD->getLocation()), {}); } else if (ShouldEmitUnreachable) { if (CGM.getCodeGenOpts().OptimizationLevel == 0) @@ -2541,7 +2542,9 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) { // expression [...] each time it is evaluated it shall have a value // greater than zero. if (SanOpts.has(SanitizerKind::VLABound)) { - SanitizerScope SanScope(this); + auto CheckOrdinal = SanitizerKind::SO_VLABound; + auto CheckHandler = SanitizerHandler::VLABoundNotPositive; + SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler); llvm::Value *Zero = llvm::Constant::getNullValue(size->getType()); clang::QualType SEType = sizeExpr->getType(); llvm::Value *CheckCondition = @@ -2551,9 +2554,8 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) { llvm::Constant *StaticArgs[] = { EmitCheckSourceLocation(sizeExpr->getBeginLoc()), EmitCheckTypeDescriptor(SEType)}; - EmitCheck( - std::make_pair(CheckCondition, SanitizerKind::SO_VLABound), - SanitizerHandler::VLABoundNotPositive, StaticArgs, size); + EmitCheck(std::make_pair(CheckCondition, CheckOrdinal), + CheckHandler, StaticArgs, size); } // Always zexting here would be wrong if it weren't @@ -3196,7 +3198,9 @@ void CodeGenFunction::emitAlignmentAssumptionCheck( Assumption->removeFromParent(); { - SanitizerScope SanScope(this); + auto CheckOrdinal = SanitizerKind::SO_Alignment; + auto CheckHandler = SanitizerHandler::AlignmentAssumption; + SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler); if (!OffsetValue) OffsetValue = Builder.getInt1(false); // no offset. @@ -3205,8 +3209,8 @@ void CodeGenFunction::emitAlignmentAssumptionCheck( EmitCheckSourceLocation(SecondaryLoc), EmitCheckTypeDescriptor(Ty)}; llvm::Value *DynamicData[] = {Ptr, Alignment, OffsetValue}; - EmitCheck({std::make_pair(TheCheck, SanitizerKind::SO_Alignment)}, - SanitizerHandler::AlignmentAssumption, StaticData, DynamicData); + EmitCheck({std::make_pair(TheCheck, CheckOrdinal)}, CheckHandler, + StaticData, DynamicData); } // We are now in the (new, empty) "cont" basic block. diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index cecc8c0ade729..a5ab9df01dba9 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3332,10 +3332,12 @@ class CodeGenFunction : public CodeGenTypeCache { llvm::Value *Index, QualType IndexType, QualType IndexedType, bool Accessed); - /// Returns debug info, with additional annotation if enabled by - /// CGM.getCodeGenOpts().SanitizeAnnotateDebugInfo[CheckKindOrdinal]. + /// Returns debug info, with additional annotation if + /// CGM.getCodeGenOpts().SanitizeAnnotateDebugInfo[Ordinal] is enabled for + /// any of the ordinals. llvm::DILocation * - SanitizerAnnotateDebugInfo(SanitizerKind::SanitizerOrdinal CheckKindOrdinal); + SanitizerAnnotateDebugInfo(ArrayRef Ordinals, + SanitizerHandler Handler); llvm::Value *GetCountedByFieldExprGEP(const Expr *Base, const FieldDecl *FD, const FieldDecl *CountDecl); diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index aac7bb7db1550..f4a99467010af 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -713,9 +713,9 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer( llvm::Value *VirtualFn = nullptr; { - CodeGenFunction::SanitizerScope SanScope(&CGF); - ApplyDebugLocation ApplyTrapDI( - CGF, CGF.SanitizerAnnotateDebugInfo(SanitizerKind::SO_CFIMFCall)); + auto CheckOrdinal = SanitizerKind::SO_CFIMFCall; + auto CheckHandler = SanitizerHandler::CFICheckFail; + SanitizerDebugLocation SanScope(&CGF, {CheckOrdinal}, CheckHandler); llvm::Value *TypeId = nullptr; llvm::Value *CheckResult = nullptr; @@ -785,16 +785,15 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer( }; if (CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIMFCall)) { - CGF.EmitTrapCheck(CheckResult, SanitizerHandler::CFICheckFail); + CGF.EmitTrapCheck(CheckResult, CheckHandler); } else { llvm::Value *AllVtables = llvm::MetadataAsValue::get( CGM.getLLVMContext(), llvm::MDString::get(CGM.getLLVMContext(), "all-vtables")); llvm::Value *ValidVtable = Builder.CreateCall( CGM.getIntrinsic(llvm::Intrinsic::type_test), {VTable, AllVtables}); - CGF.EmitCheck(std::make_pair(CheckResult, SanitizerKind::SO_CFIMFCall), - SanitizerHandler::CFICheckFail, StaticData, - {VTable, ValidVtable}); + CGF.EmitCheck(std::make_pair(CheckResult, CheckOrdinal), CheckHandler, + StaticData, {VTable, ValidVtable}); } FnVirtual = Builder.GetInsertBlock(); @@ -813,9 +812,9 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer( if (ShouldEmitCFICheck) { CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl(); if (RD->hasDefinition()) { - CodeGenFunction::SanitizerScope SanScope(&CGF); - ApplyDebugLocation ApplyTrapDI( - CGF, CGF.SanitizerAnnotateDebugInfo(SanitizerKind::SO_CFIMFCall)); + auto CheckOrdinal = SanitizerKind::SO_CFIMFCall; + auto CheckHandler = SanitizerHandler::CFICheckFail; + SanitizerDebugLocation SanScope(&CGF, {CheckOrdinal}, CheckHandler); llvm::Constant *StaticData[] = { llvm::ConstantInt::get(CGF.Int8Ty, CodeGenFunction::CFITCK_NVMFCall), @@ -838,8 +837,7 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer( Bit = Builder.CreateOr(Bit, TypeTest); } - CGF.EmitCheck(std::make_pair(Bit, SanitizerKind::SO_CFIMFCall), - SanitizerHandler::CFICheckFail, StaticData, + CGF.EmitCheck(std::make_pair(Bit, CheckOrdinal), CheckHandler, StaticData, {NonVirtualFn, llvm::UndefValue::get(CGF.IntPtrTy)}); FnNonVirtual = Builder.GetInsertBlock(); diff --git a/clang/test/CodeGen/ubsan-function-debuginfo.c b/clang/test/CodeGen/ubsan-function-debuginfo.c index 21cc7e41e1a37..106aeceadf369 100644 --- a/clang/test/CodeGen/ubsan-function-debuginfo.c +++ b/clang/test/CodeGen/ubsan-function-debuginfo.c @@ -18,26 +18,26 @@ void call_no_prototype(void (*f)()) { f(); } // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: #dbg_value(ptr [[F]], [[META25:![0-9]+]], !DIExpression(), [[META27:![0-9]+]]) // CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[F]], i64 -8, !dbg [[DBG28:![0-9]+]] -// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4, !dbg [[DBG28]], !nosanitize [[META29:![0-9]+]] -// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], -1056584962, !dbg [[DBG28]], !nosanitize [[META29]] -// CHECK-NEXT: br i1 [[TMP2]], label %[[TYPECHECK:.*]], label %[[CONT1:.*]], !dbg [[DBG28]], !nosanitize [[META29]] +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4, !dbg [[DBG28]], !nosanitize [[META32:![0-9]+]] +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], -1056584962, !dbg [[DBG28]], !nosanitize [[META32]] +// CHECK-NEXT: br i1 [[TMP2]], label %[[TYPECHECK:.*]], label %[[CONT1:.*]], !dbg [[DBG28]], !nosanitize [[META32]] // CHECK: [[TYPECHECK]]: // CHECK-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[F]], i64 -4, !dbg [[DBG28]] -// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 8, !dbg [[DBG28]], !nosanitize [[META29]] -// CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 905068220, !dbg [[DBG28]], !nosanitize [[META29]] -// CHECK-NEXT: br i1 [[TMP5]], label %[[CONT1]], label %[[HANDLER_FUNCTION_TYPE_MISMATCH:.*]], !dbg [[DBG28]], !prof [[PROF30:![0-9]+]], !nosanitize [[META29]] +// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 8, !dbg [[DBG28]], !nosanitize [[META32]] +// CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 905068220, !dbg [[DBG28]], !nosanitize [[META32]] +// CHECK-NEXT: br i1 [[TMP5]], label %[[CONT1]], label %[[HANDLER_FUNCTION_TYPE_MISMATCH:.*]], !dbg [[DBG28]], !prof [[PROF33:![0-9]+]], !nosanitize [[META32]] // CHECK: [[HANDLER_FUNCTION_TYPE_MISMATCH]]: -// CHECK-NEXT: [[TMP6:%.*]] = ptrtoint ptr [[F]] to i64, !dbg [[DBG28]], !nosanitize [[META29]] -// CHECK-NEXT: tail call void @__ubsan_handle_function_type_mismatch_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP6]]) #[[ATTR3:[0-9]+]], !dbg [[DBG28]], !nosanitize [[META29]] -// CHECK-NEXT: unreachable, !dbg [[DBG28]], !nosanitize [[META29]] +// CHECK-NEXT: [[TMP6:%.*]] = ptrtoint ptr [[F]] to i64, !dbg [[DBG28]], !nosanitize [[META32]] +// CHECK-NEXT: tail call void @__ubsan_handle_function_type_mismatch_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP6]]) #[[ATTR3:[0-9]+]], !dbg [[DBG28]], !nosanitize [[META32]] +// CHECK-NEXT: unreachable, !dbg [[DBG28]], !nosanitize [[META32]] // CHECK: [[CONT1]]: -// CHECK-NEXT: tail call void [[F]]() #[[ATTR2]], !dbg [[DBG28]] -// CHECK-NEXT: ret void, !dbg [[DBG31:![0-9]+]] +// CHECK-NEXT: tail call void [[F]]() #[[ATTR2]], !dbg [[DBG31:![0-9]+]] +// CHECK-NEXT: ret void, !dbg [[DBG34:![0-9]+]] // void call_prototype(void (*f)(void)) { f(); } //. // CHECK: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) -// CHECK: [[META1]] = !DIFile(filename: "", directory: {{.*}}) +// CHECK: [[META1]] = !DIFile(filename: "{{.*}}", directory: {{.*}}) // CHECK: [[DBG5]] = distinct !DISubprogram(name: "call_no_prototype", scope: [[META6:![0-9]+]], file: [[META6]], line: 14, type: [[META7:![0-9]+]], scopeLine: 14, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]], retainedNodes: [[META12:![0-9]+]]) // CHECK: [[META6]] = !DIFile(filename: "{{.*}}ubsan-function-debuginfo.c", directory: {{.*}}) // CHECK: [[META7]] = !DISubroutineType(types: [[META8:![0-9]+]]) @@ -61,8 +61,11 @@ void call_prototype(void (*f)(void)) { f(); } // CHECK: [[META25]] = !DILocalVariable(name: "f", arg: 1, scope: [[DBG18]], file: [[META6]], line: 37, type: [[META21]]) // CHECK: [[META26]] = !{i32 -1056584962, i32 -747727454} // CHECK: [[META27]] = !DILocation(line: 0, scope: [[DBG18]]) -// CHECK: [[DBG28]] = !DILocation(line: 37, column: 40, scope: [[DBG18]]) -// CHECK: [[META29]] = !{} -// CHECK: [[PROF30]] = !{!"branch_weights", i32 1048575, i32 1} -// CHECK: [[DBG31]] = !DILocation(line: 37, column: 45, scope: [[DBG18]]) +// CHECK: [[DBG28]] = !DILocation(line: 0, scope: [[META29:![0-9]+]], inlinedAt: [[DBG31]]) +// CHECK: [[META29]] = distinct !DISubprogram(name: "__ubsan_check_function", scope: [[META6]], file: [[META6]], type: [[META30:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]]) +// CHECK: [[META30]] = !DISubroutineType(types: null) +// CHECK: [[DBG31]] = !DILocation(line: 37, column: 40, scope: [[DBG18]]) +// CHECK: [[META32]] = !{} +// CHECK: [[PROF33]] = !{!"branch_weights", i32 1048575, i32 1} +// CHECK: [[DBG34]] = !DILocation(line: 37, column: 45, scope: [[DBG18]]) //. diff --git a/clang/test/CodeGen/unsigned-promotion-debuginfo.c b/clang/test/CodeGen/unsigned-promotion-debuginfo.c index 163f306f60a1f..88e691d65334c 100644 --- a/clang/test/CodeGen/unsigned-promotion-debuginfo.c +++ b/clang/test/CodeGen/unsigned-promotion-debuginfo.c @@ -18,19 +18,19 @@ unsigned short si, sj, sk; // CHECKS-NEXT: [[CONV:%.*]] = zext i16 [[TMP0]] to i32, !dbg [[DBG16]] // CHECKS-NEXT: [[TMP1:%.*]] = load i16, ptr @sk, align 2, !dbg [[DBG21:![0-9]+]], !tbaa [[TBAA17]] // CHECKS-NEXT: [[CONV1:%.*]] = zext i16 [[TMP1]] to i32, !dbg [[DBG21]] -// CHECKS-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[CONV]], i32 [[CONV1]]), !dbg [[DBG22:![0-9]+]], !nosanitize [[META23:![0-9]+]] -// CHECKS-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !dbg [[DBG22]], !nosanitize [[META23]] -// CHECKS-NEXT: br i1 [[TMP3]], label %[[HANDLER_MUL_OVERFLOW:.*]], label %[[CONT:.*]], !dbg [[DBG22]], !prof [[PROF24:![0-9]+]], !nosanitize [[META23]] +// CHECKS-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[CONV]], i32 [[CONV1]]), !dbg [[DBG22:![0-9]+]], !nosanitize [[META26:![0-9]+]] +// CHECKS-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !dbg [[DBG22]], !nosanitize [[META26]] +// CHECKS-NEXT: br i1 [[TMP3]], label %[[HANDLER_MUL_OVERFLOW:.*]], label %[[CONT:.*]], !dbg [[DBG22]], !prof [[PROF27:![0-9]+]], !nosanitize [[META26]] // CHECKS: [[HANDLER_MUL_OVERFLOW]]: // CHECKS-NEXT: [[TMP4:%.*]] = zext i16 [[TMP0]] to i64, !dbg [[DBG22]] // CHECKS-NEXT: [[TMP5:%.*]] = zext i16 [[TMP1]] to i64, !dbg [[DBG22]] -// CHECKS-NEXT: tail call void @__ubsan_handle_mul_overflow_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP4]], i64 [[TMP5]]) #[[ATTR3:[0-9]+]], !dbg [[DBG22]], !nosanitize [[META23]] -// CHECKS-NEXT: unreachable, !dbg [[DBG22]], !nosanitize [[META23]] +// CHECKS-NEXT: tail call void @__ubsan_handle_mul_overflow_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP4]], i64 [[TMP5]]) #[[ATTR3:[0-9]+]], !dbg [[DBG22]], !nosanitize [[META26]] +// CHECKS-NEXT: unreachable, !dbg [[DBG22]], !nosanitize [[META26]] // CHECKS: [[CONT]]: -// CHECKS-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !dbg [[DBG22]], !nosanitize [[META23]] +// CHECKS-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !dbg [[DBG22]], !nosanitize [[META26]] // CHECKS-NEXT: [[CONV2:%.*]] = trunc i32 [[TMP6]] to i16, !dbg [[DBG16]] -// CHECKS-NEXT: store i16 [[CONV2]], ptr @si, align 2, !dbg [[DBG25:![0-9]+]], !tbaa [[TBAA17]] -// CHECKS-NEXT: ret void, !dbg [[DBG26:![0-9]+]] +// CHECKS-NEXT: store i16 [[CONV2]], ptr @si, align 2, !dbg [[DBG28:![0-9]+]], !tbaa [[TBAA17]] +// CHECKS-NEXT: ret void, !dbg [[DBG29:![0-9]+]] // // CHECKU-LABEL: define dso_local void @testshortmul( // CHECKU-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !dbg [[DBG13:![0-9]+]] { @@ -67,11 +67,14 @@ void testshortmul(void) { // CHECKS: [[META19]] = !{!"omnipotent char", [[META20:![0-9]+]], i64 0} // CHECKS: [[META20]] = !{!"Simple C/C++ TBAA"} // CHECKS: [[DBG21]] = !DILocation(line: 47, column: 13, scope: [[DBG13]]) -// CHECKS: [[DBG22]] = !DILocation(line: 47, column: 11, scope: [[DBG13]]) -// CHECKS: [[META23]] = !{} -// CHECKS: [[PROF24]] = !{!"branch_weights", i32 1, i32 1048575} -// CHECKS: [[DBG25]] = !DILocation(line: 47, column: 6, scope: [[DBG13]]) -// CHECKS: [[DBG26]] = !DILocation(line: 48, column: 1, scope: [[DBG13]]) +// CHECKS: [[DBG22]] = !DILocation(line: 0, scope: [[META23:![0-9]+]], inlinedAt: [[META25:![0-9]+]]) +// CHECKS: [[META23]] = distinct !DISubprogram(name: "__ubsan_check_mul_overflow", scope: [[META7]], file: [[META7]], type: [[META24:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META2]]) +// CHECKS: [[META24]] = !DISubroutineType(types: null) +// CHECKS: [[META25]] = !DILocation(line: 47, column: 11, scope: [[DBG13]]) +// CHECKS: [[META26]] = !{} +// CHECKS: [[PROF27]] = !{!"branch_weights", i32 1, i32 1048575} +// CHECKS: [[DBG28]] = !DILocation(line: 47, column: 6, scope: [[DBG13]]) +// CHECKS: [[DBG29]] = !DILocation(line: 48, column: 1, scope: [[DBG13]]) //. // CHECKU: [[META0:![0-9]+]] = !DIGlobalVariableExpression(var: [[META1:![0-9]+]], expr: !DIExpression()) // CHECKU: [[META1]] = distinct !DIGlobalVariable(name: "sj", scope: [[META2:![0-9]+]], file: [[META7:![0-9]+]], line: 12, type: [[META8:![0-9]+]], isLocal: false, isDefinition: true)