Author: Bill Wendling Date: 2023-11-09T10:18:17-08:00 New Revision: bc09ec696209b3aea74d49767b15c2f34e363933
URL: https://github.com/llvm/llvm-project/commit/bc09ec696209b3aea74d49767b15c2f34e363933 DIFF: https://github.com/llvm/llvm-project/commit/bc09ec696209b3aea74d49767b15c2f34e363933.diff LOG: [CodeGen] Revamp counted_by calculations (#70606) Break down the counted_by calculations so that they correctly handle anonymous structs, which are specified internally as IndirectFieldDecls. Improves the calculation of __bdos on a different field member in the struct. And also improves support for __bdos in an index into the FAM. If the index is further out than the length of the FAM, then we return __bdos's "can't determine the size" value (zero or negative one, depending on type). Also simplify the code to use helper methods to get the field referenced by counted_by and the flexible array member itself, which also had some issues with FAMs in sub-structs. Added: Modified: clang/lib/CodeGen/CGBuiltin.cpp clang/lib/CodeGen/CGExpr.cpp clang/lib/CodeGen/CodeGenFunction.h clang/test/CodeGen/attr-counted-by.c Removed: ################################################################################ diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index d49c44dbaace3a8..03ea7ad187e53dc 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -25,6 +25,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/OSLog.h" +#include "clang/AST/OperationKinds.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" @@ -858,63 +859,155 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, } } + // LLVM can't handle Type=3 appropriately, and __builtin_object_size shouldn't + // evaluate E for side-effects. In either case, we shouldn't lower to + // @llvm.objectsize. + if (Type == 3 || (!EmittedE && E->HasSideEffects(getContext()))) + return getDefaultBuiltinObjectSizeResult(Type, ResType); + if (IsDynamic) { - LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = - getLangOpts().getStrictFlexArraysLevel(); + // The code generated here calculates the size of a struct with a flexible + // array member that uses the counted_by attribute. There are two instances + // we handle: + // + // struct s { + // unsigned long flags; + // int count; + // int array[] __attribute__((counted_by(count))); + // } + // + // 1) bdos of the flexible array itself: + // + // __builtin_dynamic_object_size(p->array, 1) == + // p->count * sizeof(*p->array) + // + // 2) bdos of a pointer into the flexible array: + // + // __builtin_dynamic_object_size(&p->array[42], 1) == + // (p->count - 42) * sizeof(*p->array) + // + // 2) bdos of the whole struct, including the flexible array: + // + // __builtin_dynamic_object_size(p, 1) == + // max(sizeof(struct s), + // offsetof(struct s, array) + p->count * sizeof(*p->array)) + // const Expr *Base = E->IgnoreParenImpCasts(); - - if (FieldDecl *FD = FindCountedByField(Base, StrictFlexArraysLevel)) { - const auto *ME = dyn_cast<MemberExpr>(Base); - llvm::Value *ObjectSize = nullptr; - - if (!ME) { - const auto *DRE = dyn_cast<DeclRefExpr>(Base); - ValueDecl *VD = nullptr; - - ObjectSize = ConstantInt::get( - ResType, - getContext().getTypeSize(DRE->getType()->getPointeeType()) / 8, - true); - - if (auto *RD = DRE->getType()->getPointeeType()->getAsRecordDecl()) - VD = RD->getLastField(); - - Expr *ICE = ImplicitCastExpr::Create( - getContext(), DRE->getType(), CK_LValueToRValue, - const_cast<Expr *>(cast<Expr>(DRE)), nullptr, VK_PRValue, - FPOptionsOverride()); - ME = MemberExpr::CreateImplicit(getContext(), ICE, true, VD, - VD->getType(), VK_LValue, OK_Ordinary); + const Expr *Idx = nullptr; + if (const auto *UO = dyn_cast<UnaryOperator>(Base); + UO && UO->getOpcode() == UO_AddrOf) { + if (const auto *ASE = + dyn_cast<ArraySubscriptExpr>(UO->getSubExpr()->IgnoreParens())) { + Base = ASE->getBase(); + Idx = ASE->getIdx()->IgnoreParenImpCasts(); + + if (const auto *IL = dyn_cast<IntegerLiteral>(Idx); + IL && !IL->getValue().getSExtValue()) + Idx = nullptr; } + } - // At this point, we know that \p ME is a flexible array member. - const auto *ArrayTy = getContext().getAsArrayType(ME->getType()); - unsigned Size = getContext().getTypeSize(ArrayTy->getElementType()); - - llvm::Value *CountField = - EmitAnyExprToTemp(MemberExpr::CreateImplicit( - getContext(), const_cast<Expr *>(ME->getBase()), - ME->isArrow(), FD, FD->getType(), VK_LValue, - OK_Ordinary)) - .getScalarVal(); + if (const ValueDecl *CountedByFD = FindCountedByField(Base)) { + bool IsSigned = CountedByFD->getType()->isSignedIntegerType(); + const RecordDecl *OuterRD = + CountedByFD->getDeclContext()->getOuterLexicalRecordContext(); + ASTContext &Ctx = getContext(); + + // Load the counted_by field. + const Expr *CountedByExpr = BuildCountedByFieldExpr(Base, CountedByFD); + Value *CountedByInst = EmitAnyExprToTemp(CountedByExpr).getScalarVal(); + llvm::Type *CountedByTy = CountedByInst->getType(); + + if (Idx) { + // There's an index into the array. Remove it from the count. + bool IdxSigned = Idx->getType()->isSignedIntegerType(); + Value *IdxInst = EmitAnyExprToTemp(Idx).getScalarVal(); + IdxInst = IdxSigned ? Builder.CreateSExtOrTrunc(IdxInst, CountedByTy) + : Builder.CreateZExtOrTrunc(IdxInst, CountedByTy); + + // If the index is negative, don't subtract it from the counted_by + // value. The pointer is pointing to something before the FAM. + IdxInst = Builder.CreateNeg(IdxInst, "", !IdxSigned, IdxSigned); + CountedByInst = + Builder.CreateAdd(CountedByInst, IdxInst, "", !IsSigned, IsSigned); + } - llvm::Value *Mul = Builder.CreateMul( - CountField, llvm::ConstantInt::get(CountField->getType(), Size / 8)); - Mul = Builder.CreateZExtOrTrunc(Mul, ResType); + // Get the size of the flexible array member's base type. + const ValueDecl *FAMDecl = nullptr; + if (const auto *ME = dyn_cast<MemberExpr>(Base)) { + const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = + getLangOpts().getStrictFlexArraysLevel(); + if (const ValueDecl *MD = ME->getMemberDecl(); + MD && Decl::isFlexibleArrayMemberLike( + Ctx, MD, MD->getType(), StrictFlexArraysLevel, + /*IgnoreTemplateOrMacroSubstitution=*/true)) + // Base is referencing the FAM itself. + FAMDecl = MD; + } - if (ObjectSize) - return Builder.CreateAdd(ObjectSize, Mul); + if (!FAMDecl) + FAMDecl = FindFlexibleArrayMemberField(Ctx, OuterRD); + + assert(FAMDecl && "Can't find the flexible array member field"); + + const ArrayType *ArrayTy = Ctx.getAsArrayType(FAMDecl->getType()); + CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType()); + llvm::Constant *ElemSize = + llvm::ConstantInt::get(CountedByTy, Size.getQuantity(), IsSigned); + + // Calculate how large the flexible array member is in bytes. + Value *FAMSize = + Builder.CreateMul(CountedByInst, ElemSize, "", !IsSigned, IsSigned); + FAMSize = IsSigned ? Builder.CreateSExtOrTrunc(FAMSize, ResType) + : Builder.CreateZExtOrTrunc(FAMSize, ResType); + Value *Res = FAMSize; + + if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) { + // The whole struct is specificed in the __bdos. + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD); + + // Get the offset of the FAM. + CharUnits Offset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAMDecl)); + llvm::Constant *FAMOffset = + ConstantInt::get(ResType, Offset.getQuantity(), IsSigned); + + // max(sizeof(struct s), + // offsetof(struct s, array) + p->count * sizeof(*p->array)) + Value *OffsetAndFAMSize = + Builder.CreateAdd(FAMOffset, Res, "", !IsSigned, IsSigned); + + // Get the full size of the struct. + llvm::Constant *SizeofStruct = + ConstantInt::get(ResType, Layout.getSize().getQuantity(), IsSigned); + + Res = IsSigned + ? Builder.CreateBinaryIntrinsic( + llvm::Intrinsic::smax, OffsetAndFAMSize, SizeofStruct) + : Builder.CreateBinaryIntrinsic( + llvm::Intrinsic::umax, OffsetAndFAMSize, SizeofStruct); + } else if (const auto *ME = dyn_cast<MemberExpr>(Base)) { + // Pointing to a place before the FAM. Add the diff erence to the FAM's + // size. + if (const ValueDecl *MD = ME->getMemberDecl(); MD != FAMDecl) { + CharUnits Offset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(MD)); + CharUnits FAMOffset = + Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAMDecl)); + + Res = Builder.CreateAdd( + Res, ConstantInt::get(ResType, FAMOffset.getQuantity() - + Offset.getQuantity())); + } + } - return Mul; + // A negative 'FAMSize' means that the index was greater than the count, + // or an improperly set count field. Return -1 (for types 0 and 1) or 0 + // (for types 2 and 3). + return Builder.CreateSelect( + Builder.CreateIsNeg(FAMSize), + getDefaultBuiltinObjectSizeResult(Type, ResType), Res); } } - // LLVM can't handle Type=3 appropriately, and __builtin_object_size shouldn't - // evaluate E for side-effects. In either case, we shouldn't lower to - // @llvm.objectsize. - if (Type == 3 || (!EmittedE && E->HasSideEffects(getContext()))) - return getDefaultBuiltinObjectSizeResult(Type, ResType); - Value *Ptr = EmittedE ? EmittedE : EmitScalarExpr(E); assert(Ptr->getType()->isPointerTy() && "Non-pointer passed to __builtin_object_size?"); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index be30d23a309720f..a75f630e1a4c767 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -938,14 +938,10 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF, // Ignore pass_object_size here. It's not applicable on decayed pointers. } - if (FieldDecl *FD = CGF.FindCountedByField(Base, StrictFlexArraysLevel)) { - const auto *ME = dyn_cast<MemberExpr>(CE->getSubExpr()); + if (const ValueDecl *VD = CGF.FindCountedByField(Base)) { IndexedType = Base->getType(); - return CGF - .EmitAnyExprToTemp(MemberExpr::CreateImplicit( - CGF.getContext(), const_cast<Expr *>(ME->getBase()), - ME->isArrow(), FD, FD->getType(), VK_LValue, OK_Ordinary)) - .getScalarVal(); + const Expr *E = CGF.BuildCountedByFieldExpr(Base, VD); + return CGF.EmitAnyExprToTemp(E).getScalarVal(); } } @@ -960,46 +956,115 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF, return nullptr; } -FieldDecl *CodeGenFunction::FindCountedByField( - const Expr *Base, - LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel) { - const ValueDecl *VD = nullptr; +const Expr * +CodeGenFunction::BuildCountedByFieldExpr(const Expr *Base, + const ValueDecl *CountedByVD) { + // Find the outer struct expr (i.e. p in p->a.b.c.d). + Expr *CountedByExpr = const_cast<Expr *>(Base)->IgnoreParenImpCasts(); + + // Work our way up the expression until we reach the DeclRefExpr. + while (!isa<DeclRefExpr>(CountedByExpr)) + if (const auto *ME = dyn_cast<MemberExpr>(CountedByExpr)) + CountedByExpr = ME->getBase()->IgnoreParenImpCasts(); + + // Add back an implicit cast to create the required pr-value. + CountedByExpr = ImplicitCastExpr::Create( + getContext(), CountedByExpr->getType(), CK_LValueToRValue, CountedByExpr, + nullptr, VK_PRValue, FPOptionsOverride()); + + if (const auto *IFD = dyn_cast<IndirectFieldDecl>(CountedByVD)) { + // The counted_by field is inside an anonymous struct / union. The + // IndirectFieldDecl has the correct order of FieldDecls to build this + // easily. (Yay!) + for (NamedDecl *ND : IFD->chain()) { + auto *VD = cast<ValueDecl>(ND); + CountedByExpr = + MemberExpr::CreateImplicit(getContext(), CountedByExpr, + CountedByExpr->getType()->isPointerType(), + VD, VD->getType(), VK_LValue, OK_Ordinary); + } + } else { + CountedByExpr = MemberExpr::CreateImplicit( + getContext(), const_cast<Expr *>(CountedByExpr), + CountedByExpr->getType()->isPointerType(), + const_cast<ValueDecl *>(CountedByVD), CountedByVD->getType(), VK_LValue, + OK_Ordinary); + } - Base = Base->IgnoreParenImpCasts(); + return CountedByExpr; +} + +const ValueDecl * +CodeGenFunction::FindFlexibleArrayMemberField(ASTContext &Ctx, + const RecordDecl *RD) { + const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = + getLangOpts().getStrictFlexArraysLevel(); + + for (const Decl *D : RD->decls()) { + if (const auto *VD = dyn_cast<ValueDecl>(D); + VD && Decl::isFlexibleArrayMemberLike( + Ctx, VD, VD->getType(), StrictFlexArraysLevel, + /*IgnoreTemplateOrMacroSubstitution=*/true)) + return VD; + + if (const auto *Record = dyn_cast<RecordDecl>(D)) + if (const ValueDecl *VD = FindFlexibleArrayMemberField(Ctx, Record)) + return VD; + } + + return nullptr; +} + +const ValueDecl *CodeGenFunction::FindCountedByField(const Expr *Base) { + ASTContext &Ctx = getContext(); + const RecordDecl *OuterRD = nullptr; + const FieldDecl *FD = nullptr; - if (const auto *ME = dyn_cast<MemberExpr>(Base)) { - VD = dyn_cast<ValueDecl>(ME->getMemberDecl()); - } else if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) { - // Pointing to the full structure. - VD = dyn_cast<ValueDecl>(DRE->getDecl()); + Base = Base->IgnoreParenImpCasts(); - QualType Ty = VD->getType(); + // Get the outer-most lexical RecordDecl. + if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) { + QualType Ty = DRE->getDecl()->getType(); if (Ty->isPointerType()) Ty = Ty->getPointeeType(); if (const auto *RD = Ty->getAsRecordDecl()) - VD = RD->getLastField(); - } else if (const auto *CE = dyn_cast<CastExpr>(Base)) { - if (const auto *ME = dyn_cast<MemberExpr>(CE->getSubExpr())) - VD = dyn_cast<ValueDecl>(ME->getMemberDecl()); + OuterRD = RD->getOuterLexicalRecordContext(); + } else if (const auto *ME = dyn_cast<MemberExpr>(Base)) { + if (const ValueDecl *MD = ME->getMemberDecl()) { + OuterRD = MD->getDeclContext()->getOuterLexicalRecordContext(); + + const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = + getLangOpts().getStrictFlexArraysLevel(); + if (Decl::isFlexibleArrayMemberLike( + Ctx, MD, MD->getType(), StrictFlexArraysLevel, + /*IgnoreTemplateOrMacroSubstitution=*/true)) + // Base is referencing the FAM itself. + FD = dyn_cast<FieldDecl>(MD); + } } - const auto *FD = dyn_cast_if_present<FieldDecl>(VD); - if (!FD || !FD->getParent() || - !Decl::isFlexibleArrayMemberLike(getContext(), FD, FD->getType(), - StrictFlexArraysLevel, true)) + if (!OuterRD) return nullptr; + if (!FD) { + const ValueDecl *VD = FindFlexibleArrayMemberField(Ctx, OuterRD); + FD = dyn_cast_if_present<FieldDecl>(VD); + if (!FD) + return nullptr; + } + const auto *CBA = FD->getAttr<CountedByAttr>(); if (!CBA) return nullptr; - StringRef FieldName = CBA->getCountedByField()->getName(); - auto It = - llvm::find_if(FD->getParent()->fields(), [&](const FieldDecl *Field) { - return FieldName == Field->getName(); - }); - return It != FD->getParent()->field_end() ? *It : nullptr; + DeclarationName DName(CBA->getCountedByField()); + DeclContext::lookup_result Lookup = OuterRD->lookup(DName); + + if (Lookup.empty()) + return nullptr; + + return dyn_cast<ValueDecl>(Lookup.front()); } void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base, diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index dc6773eb83f5ece..bb8c14401032b5d 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3022,11 +3022,18 @@ class CodeGenFunction : public CodeGenTypeCache { void EmitBoundsCheck(const Expr *E, const Expr *Base, llvm::Value *Index, QualType IndexType, bool Accessed); + // Find a struct's flexible array member. It may be embedded inside multiple + // sub-structs, but must still be the last field. + const ValueDecl *FindFlexibleArrayMemberField(ASTContext &Ctx, + const RecordDecl *RD); + /// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns /// \p nullptr if either the attribute or the field doesn't exist. - FieldDecl *FindCountedByField( - const Expr *Base, - LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel); + const ValueDecl *FindCountedByField(const Expr *Base); + + /// Build an expression accessing the "counted_by" field. + const Expr *BuildCountedByFieldExpr(const Expr *Base, + const ValueDecl *CountedByVD); llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre); diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c index a7eb0da6dd282a7..3d3ce572ba62c00 100644 --- a/clang/test/CodeGen/attr-counted-by.c +++ b/clang/test/CodeGen/attr-counted-by.c @@ -14,6 +14,24 @@ #define __counted_by(member) #endif +#define DECLARE_FLEX_ARRAY(TYPE, NAME) \ + struct { \ + struct { } __empty_ ## NAME; \ + TYPE NAME[]; \ + } + +#define DECLARE_BOUNDED_FLEX_ARRAY(COUNT_TYPE, COUNT, TYPE, NAME) \ + struct { \ + COUNT_TYPE COUNT; \ + TYPE NAME[] __counted_by(COUNT); \ + } + +#define DECLARE_FLEX_ARRAY_COUNTED_BY(TYPE, NAME, COUNTED_BY) \ + struct { \ + struct { } __empty_ ## NAME; \ + TYPE NAME[] __counted_by(COUNTED_BY); \ + } + typedef long unsigned int size_t; struct annotated { @@ -22,6 +40,22 @@ struct annotated { int array[] __counted_by(count); }; +struct union_of_fams { + unsigned long flags; + union { + /* count member type intentionally mismatched to induce padding */ + DECLARE_BOUNDED_FLEX_ARRAY(int, count_bytes, unsigned char, bytes); + DECLARE_BOUNDED_FLEX_ARRAY(unsigned char, count_ints, unsigned char, ints); + DECLARE_FLEX_ARRAY(unsigned char, unsafe); + }; +}; + +struct anon_struct { + unsigned long flags; + size_t count; + DECLARE_FLEX_ARRAY_COUNTED_BY(int, array, count); +}; + // SANITIZE-WITH-ATTR-LABEL: define dso_local void @test1( // SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]], i32 noundef [[VAL:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { // SANITIZE-WITH-ATTR-NEXT: entry: @@ -33,7 +67,7 @@ struct annotated { // SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP3]], label [[CONT7:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF7:![0-9]+]], !nosanitize !6 // SANITIZE-WITH-ATTR: handler.out_of_bounds: // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize !6 -// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB2:[0-9]+]], i64 [[TMP4]]) #[[ATTR2:[0-9]+]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB2:[0-9]+]], i64 [[TMP4]]) #[[ATTR4:[0-9]+]], !nosanitize !6 // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 // SANITIZE-WITH-ATTR: cont7: // SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[TMP1]] @@ -77,12 +111,14 @@ void test1(struct annotated *p, int index, int val) { // SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = icmp ugt i64 [[TMP1]], [[INDEX]], !nosanitize !6 // SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label [[CONT12:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF7]], !nosanitize !6 // SANITIZE-WITH-ATTR: handler.out_of_bounds: -// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB4:[0-9]+]], i64 [[INDEX]]) #[[ATTR2]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB4:[0-9]+]], i64 [[INDEX]]) #[[ATTR4]], !nosanitize !6 // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 // SANITIZE-WITH-ATTR: cont12: // SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[INDEX]] -// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = shl i32 [[TMP0]], 2 -// SANITIZE-WITH-ATTR-NEXT: store i32 [[TMP3]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp sgt i32 [[TMP0]], -1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = shl nsw i32 [[TMP0]], 2 +// SANITIZE-WITH-ATTR-NEXT: [[NARROW:%.*]] = select i1 [[DOTINV]], i32 [[TMP3]], i32 -1 +// SANITIZE-WITH-ATTR-NEXT: store i32 [[NARROW]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // SANITIZE-WITH-ATTR-NEXT: ret void // // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test2( @@ -90,9 +126,11 @@ void test1(struct annotated *p, int index, int val) { // NO-SANITIZE-WITH-ATTR-NEXT: entry: // NO-SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED:%.*]], ptr [[P]], i64 0, i32 1 // NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[COUNT]], align 8, !tbaa [[TBAA2]] -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl i32 [[TMP0]], 2 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl nsw i32 [[TMP0]], 2 +// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp sgt i32 [[TMP0]], -1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[NARROW:%.*]] = select i1 [[DOTINV]], i32 [[TMP1]], i32 -1 // NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[INDEX]] -// NO-SANITIZE-WITH-ATTR-NEXT: store i32 [[TMP1]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// NO-SANITIZE-WITH-ATTR-NEXT: store i32 [[NARROW]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // NO-SANITIZE-WITH-ATTR-NEXT: ret void // // SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test2( @@ -122,22 +160,28 @@ void test2(struct annotated *p, size_t index) { // SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = icmp ugt i64 [[TMP1]], [[INDEX]], !nosanitize !6 // SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label [[CONT12:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF7]], !nosanitize !6 // SANITIZE-WITH-ATTR: handler.out_of_bounds: -// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 [[INDEX]]) #[[ATTR2]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 [[INDEX]]) #[[ATTR4]], !nosanitize !6 // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 // SANITIZE-WITH-ATTR: cont12: // SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[INDEX]] -// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = shl i32 [[TMP0]], 2 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i32 [[TMP3]], 16 +// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = shl nsw i32 [[TMP0]], 2 +// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP3]], i32 4) +// SANITIZE-WITH-ATTR-NEXT: [[NARROW:%.*]] = add nuw i32 [[TMP4]], 12 +// SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp sgt i32 [[TMP0]], -1 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i32 [[NARROW]], i32 -1 // SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // SANITIZE-WITH-ATTR-NEXT: ret void // // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test3( -// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] { +// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] { // NO-SANITIZE-WITH-ATTR-NEXT: entry: // NO-SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED:%.*]], ptr [[P]], i64 0, i32 1 // NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[COUNT]], align 8, !tbaa [[TBAA2]] -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl i32 [[TMP0]], 2 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i32 [[TMP1]], 16 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl nsw i32 [[TMP0]], 2 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP1]], i32 4) +// NO-SANITIZE-WITH-ATTR-NEXT: [[NARROW:%.*]] = add nuw i32 [[TMP2]], 12 +// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp sgt i32 [[TMP0]], -1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i32 [[NARROW]], i32 -1 // NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[INDEX]] // NO-SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // NO-SANITIZE-WITH-ATTR-NEXT: ret void @@ -162,66 +206,527 @@ void test3(struct annotated *p, size_t index) { p->array[index] = __builtin_dynamic_object_size(p, 1); } -struct annotated_with_anon_struct { - unsigned long flags; - struct { - unsigned char count; - int array[] __counted_by(count); - }; -}; - // SANITIZE-WITH-ATTR-LABEL: define dso_local void @test4( +// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]], i32 noundef [[FAM_IDX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITH-ATTR-NEXT: entry: +// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED:%.*]], ptr [[P]], i64 0, i32 1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[COUNT]], align 8, !tbaa [[TBAA2]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = sext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = icmp ult i64 [[TMP1]], [[TMP2]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP3]], label [[CONT13:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF7]], !nosanitize !6 +// SANITIZE-WITH-ATTR: handler.out_of_bounds: +// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB6:[0-9]+]], i64 [[TMP4]]) #[[ATTR4]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 +// SANITIZE-WITH-ATTR: cont13: +// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = shl i32 [[TMP0]], 2 +// SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = add i32 [[TMP5]], -12 +// SANITIZE-WITH-ATTR-NEXT: [[NARROW:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP6]], i32 -1) +// SANITIZE-WITH-ATTR-NEXT: [[CONV3:%.*]] = and i32 [[NARROW]], 255 +// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[TMP1]] +// SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV3]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = load i32, ptr [[COUNT]], align 8, !tbaa [[TBAA2]] +// SANITIZE-WITH-ATTR-NEXT: [[ADD:%.*]] = add nsw i32 [[INDEX]], 1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP8:%.*]] = sext i32 [[ADD]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP9:%.*]] = zext i32 [[TMP7]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP10:%.*]] = icmp ult i64 [[TMP8]], [[TMP9]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP10]], label [[CONT34:%.*]], label [[HANDLER_OUT_OF_BOUNDS29:%.*]], !prof [[PROF7]], !nosanitize !6 +// SANITIZE-WITH-ATTR: handler.out_of_bounds29: +// SANITIZE-WITH-ATTR-NEXT: [[TMP11:%.*]] = zext i32 [[ADD]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB7:[0-9]+]], i64 [[TMP11]]) #[[ATTR4]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 +// SANITIZE-WITH-ATTR: cont34: +// SANITIZE-WITH-ATTR-NEXT: [[TMP12:%.*]] = shl i32 [[TMP7]], 2 +// SANITIZE-WITH-ATTR-NEXT: [[TMP13:%.*]] = add i32 [[TMP12]], -16 +// SANITIZE-WITH-ATTR-NEXT: [[NARROW69:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP13]], i32 -1) +// SANITIZE-WITH-ATTR-NEXT: [[CONV20:%.*]] = and i32 [[NARROW69]], 255 +// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX32:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[TMP8]] +// SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV20]], ptr [[ARRAYIDX32]], align 4, !tbaa [[TBAA2]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP14:%.*]] = load i32, ptr [[COUNT]], align 8, !tbaa [[TBAA2]] +// SANITIZE-WITH-ATTR-NEXT: [[ADD45:%.*]] = add nsw i32 [[INDEX]], 2 +// SANITIZE-WITH-ATTR-NEXT: [[TMP15:%.*]] = sext i32 [[ADD45]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP16:%.*]] = zext i32 [[TMP14]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP17:%.*]] = icmp ult i64 [[TMP15]], [[TMP16]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP17]], label [[CONT56:%.*]], label [[HANDLER_OUT_OF_BOUNDS51:%.*]], !prof [[PROF7]], !nosanitize !6 +// SANITIZE-WITH-ATTR: handler.out_of_bounds51: +// SANITIZE-WITH-ATTR-NEXT: [[TMP18:%.*]] = zext i32 [[ADD45]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB8:[0-9]+]], i64 [[TMP18]]) #[[ATTR4]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 +// SANITIZE-WITH-ATTR: cont56: +// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX54:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[TMP15]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP19:%.*]] = sub i32 [[TMP14]], [[FAM_IDX]] +// SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp sgt i32 [[TMP19]], -1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP20:%.*]] = shl i32 [[TMP19]], 2 +// SANITIZE-WITH-ATTR-NEXT: [[TMP21:%.*]] = and i32 [[TMP20]], 252 +// SANITIZE-WITH-ATTR-NEXT: [[CONV41:%.*]] = select i1 [[DOTINV]], i32 [[TMP21]], i32 255 +// SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV41]], ptr [[ARRAYIDX54]], align 4, !tbaa [[TBAA2]] +// SANITIZE-WITH-ATTR-NEXT: ret void +// +// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test4( +// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[INDEX:%.*]], i32 noundef [[FAM_IDX:%.*]]) local_unnamed_addr #[[ATTR2]] { +// NO-SANITIZE-WITH-ATTR-NEXT: entry: +// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED:%.*]], ptr [[P]], i64 0, i32 1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[COUNT]], align 8, !tbaa [[TBAA2]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl i32 [[TMP0]], 2 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], -12 +// NO-SANITIZE-WITH-ATTR-NEXT: [[NARROW:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP2]], i32 -1) +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV1:%.*]] = and i32 [[NARROW]], 255 +// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[IDXPROM]] +// NO-SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV1]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = load i32, ptr [[COUNT]], align 8, !tbaa [[TBAA2]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = shl i32 [[TMP3]], 2 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = add i32 [[TMP4]], -16 +// NO-SANITIZE-WITH-ATTR-NEXT: [[NARROW22:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP5]], i32 -1) +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV4:%.*]] = and i32 [[NARROW22]], 255 +// NO-SANITIZE-WITH-ATTR-NEXT: [[ADD:%.*]] = add nsw i32 [[INDEX]], 1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM6:%.*]] = sext i32 [[ADD]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[IDXPROM6]] +// NO-SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV4]], ptr [[ARRAYIDX7]], align 4, !tbaa [[TBAA2]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = load i32, ptr [[COUNT]], align 8, !tbaa [[TBAA2]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = sub i32 [[TMP6]], [[FAM_IDX]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp sgt i32 [[TMP7]], -1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP8:%.*]] = shl i32 [[TMP7]], 2 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP9:%.*]] = and i32 [[TMP8]], 252 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV10:%.*]] = select i1 [[DOTINV]], i32 [[TMP9]], i32 255 +// NO-SANITIZE-WITH-ATTR-NEXT: [[ADD12:%.*]] = add nsw i32 [[INDEX]], 2 +// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM13:%.*]] = sext i32 [[ADD12]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX14:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[IDXPROM13]] +// NO-SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV10]], ptr [[ARRAYIDX14]], align 4, !tbaa [[TBAA2]] +// NO-SANITIZE-WITH-ATTR-NEXT: ret void +// +// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test4( +// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]], i32 noundef [[FAM_IDX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITHOUT-ATTR-NEXT: entry: +// SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED:%.*]], ptr [[P]], i64 0, i32 2, i64 [[IDXPROM]] +// SANITIZE-WITHOUT-ATTR-NEXT: store i32 255, ptr [[ARRAYIDX5]], align 4, !tbaa [[TBAA2]] +// SANITIZE-WITHOUT-ATTR-NEXT: [[ADD:%.*]] = add nsw i32 [[INDEX]], 1 +// SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM17:%.*]] = sext i32 [[ADD]] to i64 +// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX18:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[IDXPROM17]] +// SANITIZE-WITHOUT-ATTR-NEXT: store i32 255, ptr [[ARRAYIDX18]], align 4, !tbaa [[TBAA2]] +// SANITIZE-WITHOUT-ATTR-NEXT: [[ADD31:%.*]] = add nsw i32 [[INDEX]], 2 +// SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM32:%.*]] = sext i32 [[ADD31]] to i64 +// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX33:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[IDXPROM32]] +// SANITIZE-WITHOUT-ATTR-NEXT: store i32 255, ptr [[ARRAYIDX33]], align 4, !tbaa [[TBAA2]] +// SANITIZE-WITHOUT-ATTR-NEXT: ret void +// +// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test4( +// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]], i32 noundef [[FAM_IDX:%.*]]) local_unnamed_addr #[[ATTR1]] { +// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry: +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED:%.*]], ptr [[P]], i64 0, i32 2, i64 [[IDXPROM]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i32 255, ptr [[ARRAYIDX3]], align 4, !tbaa [[TBAA2]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ADD:%.*]] = add nsw i32 [[INDEX]], 1 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM9:%.*]] = sext i32 [[ADD]] to i64 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX10:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[IDXPROM9]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i32 255, ptr [[ARRAYIDX10]], align 4, !tbaa [[TBAA2]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ADD17:%.*]] = add nsw i32 [[INDEX]], 2 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM18:%.*]] = sext i32 [[ADD17]] to i64 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX19:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[IDXPROM18]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i32 255, ptr [[ARRAYIDX19]], align 4, !tbaa [[TBAA2]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void +// +void test4(struct annotated *p, int index, int fam_idx) { + // This tests calculating the size from a pointer inside the FAM. + p->array[index] = (unsigned char)__builtin_dynamic_object_size(&p->array[3], 1); + p->array[index + 1] = (unsigned char)__builtin_dynamic_object_size(&(p->array[4]), 1); + p->array[index + 2] = (unsigned char)__builtin_dynamic_object_size(&(p->array[fam_idx]), 1); +} + +// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test5( // SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { // SANITIZE-WITH-ATTR-NEXT: entry: -// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED_WITH_ANON_STRUCT:%.*]], ptr [[P]], i64 0, i32 1 -// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load i8, ptr [[TMP0]], align 8, !tbaa [[TBAA8:![0-9]+]] -// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = sext i32 [[INDEX]] to i64, !nosanitize !6 -// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i8 [[TMP1]] to i64, !nosanitize !6 -// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP2]], [[TMP3]], !nosanitize !6 -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP4]], label [[CONT18:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF7]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = getelementptr inbounds [[STRUCT_ANON_STRUCT:%.*]], ptr [[P]], i64 0, i32 1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load i64, ptr [[COUNT]], align 8, !tbaa [[TBAA8:![0-9]+]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = sext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = icmp ugt i64 [[TMP0]], [[TMP1]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label [[CONT12:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF7]], !nosanitize !6 // SANITIZE-WITH-ATTR: handler.out_of_bounds: -// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize !6 -// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB6:[0-9]+]], i64 [[TMP5]]) #[[ATTR2]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB9:[0-9]+]], i64 [[TMP3]]) #[[ATTR4]], !nosanitize !6 // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 -// SANITIZE-WITH-ATTR: cont18: -// SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12 -// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[TMP2]] -// SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = shl i8 [[TMP1]], 2 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = zext i8 [[TMP6]] to i32 +// SANITIZE-WITH-ATTR: cont12: +// SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds [[STRUCT_ANON_STRUCT]], ptr [[P]], i64 1 +// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[TMP1]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = shl nuw i64 [[TMP0]], 2 +// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = tail call i64 @llvm.umax.i64(i64 [[TMP4]], i64 16) +// SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp sgt i64 [[TMP4]], -1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = trunc i64 [[TMP5]] to i32 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i32 [[TMP6]], i32 -1 // SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // SANITIZE-WITH-ATTR-NEXT: ret void // -// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test4( -// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] { +// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test5( +// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR2]] { // NO-SANITIZE-WITH-ATTR-NEXT: entry: -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED_WITH_ANON_STRUCT:%.*]], ptr [[P]], i64 0, i32 1 -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load i8, ptr [[TMP0]], align 8, !tbaa [[TBAA6:![0-9]+]] -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = shl i8 [[TMP1]], 2 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = zext i8 [[TMP2]] to i32 -// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12 +// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = getelementptr inbounds [[STRUCT_ANON_STRUCT:%.*]], ptr [[P]], i64 0, i32 1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load i64, ptr [[COUNT]], align 8, !tbaa [[TBAA6:![0-9]+]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl nuw i64 [[TMP0]], 2 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = tail call i64 @llvm.umax.i64(i64 [[TMP1]], i64 16) +// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp sgt i64 [[TMP1]], -1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = trunc i64 [[TMP2]] to i32 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i32 [[TMP3]], i32 -1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds [[STRUCT_ANON_STRUCT]], ptr [[P]], i64 1 // NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 // NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM]] // NO-SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // NO-SANITIZE-WITH-ATTR-NEXT: ret void // -// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test4( +// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test5( // SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { // SANITIZE-WITHOUT-ATTR-NEXT: entry: -// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12 +// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds [[STRUCT_ANON_STRUCT:%.*]], ptr [[P]], i64 1 // SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 // SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM]] // SANITIZE-WITHOUT-ATTR-NEXT: store i32 -1, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // SANITIZE-WITHOUT-ATTR-NEXT: ret void // -// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test4( +// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test5( // NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] { // NO-SANITIZE-WITHOUT-ATTR-NEXT: entry: -// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds [[STRUCT_ANON_STRUCT:%.*]], ptr [[P]], i64 1 // NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 // NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM]] // NO-SANITIZE-WITHOUT-ATTR-NEXT: store i32 -1, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void // -void test4(struct annotated_with_anon_struct *p, int index) { +void test5(struct anon_struct *p, int index) { + p->array[index] = __builtin_dynamic_object_size(p, 1); +} + +// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test6( +// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITH-ATTR-NEXT: entry: +// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = getelementptr inbounds [[STRUCT_ANON_STRUCT:%.*]], ptr [[P]], i64 0, i32 1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load i64, ptr [[COUNT]], align 8, !tbaa [[TBAA8]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = sext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = icmp ugt i64 [[TMP0]], [[TMP1]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label [[CONT12:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF7]], !nosanitize !6 +// SANITIZE-WITH-ATTR: handler.out_of_bounds: +// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB10:[0-9]+]], i64 [[TMP3]]) #[[ATTR4]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 +// SANITIZE-WITH-ATTR: cont12: +// SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds [[STRUCT_ANON_STRUCT]], ptr [[P]], i64 1 +// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[TMP1]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = shl nuw i64 [[TMP0]], 2 +// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP4]], i64 -1) +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = trunc i64 [[TMP5]] to i32 +// SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// SANITIZE-WITH-ATTR-NEXT: ret void +// +// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test6( +// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR2]] { +// NO-SANITIZE-WITH-ATTR-NEXT: entry: +// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = getelementptr inbounds [[STRUCT_ANON_STRUCT:%.*]], ptr [[P]], i64 0, i32 1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load i64, ptr [[COUNT]], align 8, !tbaa [[TBAA6]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl nuw i64 [[TMP0]], 2 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP1]], i64 -1) +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = trunc i64 [[TMP2]] to i32 +// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds [[STRUCT_ANON_STRUCT]], ptr [[P]], i64 1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM]] +// NO-SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// NO-SANITIZE-WITH-ATTR-NEXT: ret void +// +// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test6( +// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITHOUT-ATTR-NEXT: entry: +// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds [[STRUCT_ANON_STRUCT:%.*]], ptr [[P]], i64 1 +// SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM]] +// SANITIZE-WITHOUT-ATTR-NEXT: store i32 -1, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// SANITIZE-WITHOUT-ATTR-NEXT: ret void +// +// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test6( +// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] { +// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry: +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds [[STRUCT_ANON_STRUCT:%.*]], ptr [[P]], i64 1 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i32 -1, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void +// +void test6(struct anon_struct *p, int index) { p->array[index] = __builtin_dynamic_object_size(p->array, 1); } + +// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test7( +// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITH-ATTR-NEXT: entry: +// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_UNION_OF_FAMS:%.*]], ptr [[P]], i64 0, i32 1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 8 +// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 255 +// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = icmp ugt i32 [[TMP2]], [[INDEX]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP3]], label [[CONT23:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF7]], !nosanitize !6 +// SANITIZE-WITH-ATTR: handler.out_of_bounds: +// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB12:[0-9]+]], i64 [[TMP4]]) #[[ATTR4]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 +// SANITIZE-WITH-ATTR: cont23: +// SANITIZE-WITH-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9 +// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = sext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[TMP5]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = icmp slt i32 [[TMP1]], 0 +// SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP1]], i32 12) +// SANITIZE-WITH-ATTR-NEXT: [[TMP8:%.*]] = trunc i32 [[TMP7]] to i8 +// SANITIZE-WITH-ATTR-NEXT: [[TMP9:%.*]] = add i8 [[TMP8]], 4 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[TMP6]], i8 -1, i8 [[TMP9]] +// SANITIZE-WITH-ATTR-NEXT: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA10:![0-9]+]] +// SANITIZE-WITH-ATTR-NEXT: ret void +// +// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test7( +// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR2]] { +// NO-SANITIZE-WITH-ATTR-NEXT: entry: +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_UNION_OF_FAMS:%.*]], ptr [[P]], i64 0, i32 1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 8, !tbaa [[TBAA8:![0-9]+]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP1]], i32 12) +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = trunc i32 [[TMP2]] to i8 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = add i8 [[TMP4]], 4 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[TMP3]], i8 -1, i8 [[TMP5]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9 +// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[IDXPROM]] +// NO-SANITIZE-WITH-ATTR-NEXT: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA8]] +// NO-SANITIZE-WITH-ATTR-NEXT: ret void +// +// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test7( +// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITHOUT-ATTR-NEXT: entry: +// SANITIZE-WITHOUT-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9 +// SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[IDXPROM]] +// SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6:![0-9]+]] +// SANITIZE-WITHOUT-ATTR-NEXT: ret void +// +// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test7( +// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] { +// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry: +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[IDXPROM]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6:![0-9]+]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void +// +void test7(struct union_of_fams *p, int index) { + p->ints[index] = __builtin_dynamic_object_size(p, 1); +} + +// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test8( +// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITH-ATTR-NEXT: entry: +// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_UNION_OF_FAMS:%.*]], ptr [[P]], i64 0, i32 1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load i8, ptr [[TMP0]], align 8, !tbaa [[TBAA10]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i64 +// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = sext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], [[TMP2]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP4]], label [[CONT24:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF7]], !nosanitize !6 +// SANITIZE-WITH-ATTR: handler.out_of_bounds: +// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB13:[0-9]+]], i64 [[TMP5]]) #[[ATTR4]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 +// SANITIZE-WITH-ATTR: cont24: +// SANITIZE-WITH-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9 +// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[TMP3]] +// SANITIZE-WITH-ATTR-NEXT: store i8 [[TMP1]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA10]] +// SANITIZE-WITH-ATTR-NEXT: ret void +// +// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test8( +// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] { +// NO-SANITIZE-WITH-ATTR-NEXT: entry: +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_UNION_OF_FAMS:%.*]], ptr [[P]], i64 0, i32 1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load i8, ptr [[TMP0]], align 8, !tbaa [[TBAA8]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9 +// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[IDXPROM]] +// NO-SANITIZE-WITH-ATTR-NEXT: store i8 [[TMP1]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA8]] +// NO-SANITIZE-WITH-ATTR-NEXT: ret void +// +// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test8( +// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITHOUT-ATTR-NEXT: entry: +// SANITIZE-WITHOUT-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9 +// SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[IDXPROM]] +// SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]] +// SANITIZE-WITHOUT-ATTR-NEXT: ret void +// +// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test8( +// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] { +// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry: +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[IDXPROM]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void +// +void test8(struct union_of_fams *p, int index) { + p->ints[index] = __builtin_dynamic_object_size(p->ints, 1); +} + +// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test9( +// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITH-ATTR-NEXT: entry: +// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_UNION_OF_FAMS:%.*]], ptr [[P]], i64 0, i32 1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 8, !tbaa [[TBAA10]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = sext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP2]], [[TMP3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP4]], label [[CONT24:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF7]], !nosanitize !6 +// SANITIZE-WITH-ATTR: handler.out_of_bounds: +// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB14:[0-9]+]], i64 [[TMP5]]) #[[ATTR4]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 +// SANITIZE-WITH-ATTR: cont24: +// SANITIZE-WITH-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12 +// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[TMP2]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = icmp slt i32 [[TMP1]], 0 +// SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP1]], i32 12) +// SANITIZE-WITH-ATTR-NEXT: [[TMP8:%.*]] = trunc i32 [[TMP7]] to i8 +// SANITIZE-WITH-ATTR-NEXT: [[TMP9:%.*]] = add i8 [[TMP8]], 4 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[TMP6]], i8 -1, i8 [[TMP9]] +// SANITIZE-WITH-ATTR-NEXT: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA10]] +// SANITIZE-WITH-ATTR-NEXT: ret void +// +// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test9( +// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR2]] { +// NO-SANITIZE-WITH-ATTR-NEXT: entry: +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_UNION_OF_FAMS:%.*]], ptr [[P]], i64 0, i32 1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 8, !tbaa [[TBAA8]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP1]], i32 12) +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP1]], 0 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = trunc i32 [[TMP2]] to i8 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = add i8 [[TMP4]], 4 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[TMP3]], i8 -1, i8 [[TMP5]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12 +// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[IDXPROM]] +// NO-SANITIZE-WITH-ATTR-NEXT: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA8]] +// NO-SANITIZE-WITH-ATTR-NEXT: ret void +// +// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test9( +// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITHOUT-ATTR-NEXT: entry: +// SANITIZE-WITHOUT-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12 +// SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[IDXPROM]] +// SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]] +// SANITIZE-WITHOUT-ATTR-NEXT: ret void +// +// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test9( +// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] { +// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry: +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[IDXPROM]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void +// +void test9(struct union_of_fams *p, int index) { + p->bytes[index] = (unsigned char)__builtin_dynamic_object_size(p, 1); +} + +// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test10( +// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITH-ATTR-NEXT: entry: +// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_UNION_OF_FAMS:%.*]], ptr [[P]], i64 0, i32 1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 8, !tbaa [[TBAA10]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = sext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i32 [[TMP1]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP2]], [[TMP3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP4]], label [[CONT24:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF7]], !nosanitize !6 +// SANITIZE-WITH-ATTR: handler.out_of_bounds: +// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB15:[0-9]+]], i64 [[TMP5]]) #[[ATTR4]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 +// SANITIZE-WITH-ATTR: cont24: +// SANITIZE-WITH-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12 +// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[TMP2]] +// SANITIZE-WITH-ATTR-NEXT: [[NARROW:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP1]], i32 -1) +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = trunc i32 [[NARROW]] to i8 +// SANITIZE-WITH-ATTR-NEXT: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA10]] +// SANITIZE-WITH-ATTR-NEXT: ret void +// +// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test10( +// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR2]] { +// NO-SANITIZE-WITH-ATTR-NEXT: entry: +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_UNION_OF_FAMS:%.*]], ptr [[P]], i64 0, i32 1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 8, !tbaa [[TBAA8]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[NARROW:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP1]], i32 -1) +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = trunc i32 [[NARROW]] to i8 +// NO-SANITIZE-WITH-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12 +// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[IDXPROM]] +// NO-SANITIZE-WITH-ATTR-NEXT: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA8]] +// NO-SANITIZE-WITH-ATTR-NEXT: ret void +// +// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test10( +// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITHOUT-ATTR-NEXT: entry: +// SANITIZE-WITHOUT-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12 +// SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[IDXPROM]] +// SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]] +// SANITIZE-WITHOUT-ATTR-NEXT: ret void +// +// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test10( +// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] { +// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry: +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[IDXPROM]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void +// +void test10(struct union_of_fams *p, int index) { + p->bytes[index] = (unsigned char)__builtin_dynamic_object_size(p->bytes, 1); +} + +// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test11( +// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITH-ATTR-NEXT: entry: +// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED:%.*]], ptr [[P]], i64 0, i32 1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[COUNT]], align 8, !tbaa [[TBAA2]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = sext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = zext i32 [[TMP0]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = icmp ult i64 [[TMP1]], [[TMP2]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP3]], label [[CONT7:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF7]], !nosanitize !6 +// SANITIZE-WITH-ATTR: handler.out_of_bounds: +// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB16:[0-9]+]], i64 [[TMP4]]) #[[ATTR4]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 +// SANITIZE-WITH-ATTR: cont7: +// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[TMP1]] +// SANITIZE-WITH-ATTR-NEXT: store i32 4, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// SANITIZE-WITH-ATTR-NEXT: ret void +// +// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test11( +// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef writeonly [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// NO-SANITIZE-WITH-ATTR-NEXT: entry: +// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED:%.*]], ptr [[P]], i64 0, i32 2, i64 [[IDXPROM]] +// NO-SANITIZE-WITH-ATTR-NEXT: store i32 4, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// NO-SANITIZE-WITH-ATTR-NEXT: ret void +// +// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test11( +// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITHOUT-ATTR-NEXT: entry: +// SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED:%.*]], ptr [[P]], i64 0, i32 2, i64 [[IDXPROM]] +// SANITIZE-WITHOUT-ATTR-NEXT: store i32 4, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// SANITIZE-WITHOUT-ATTR-NEXT: ret void +// +// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test11( +// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef writeonly [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry: +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED:%.*]], ptr [[P]], i64 0, i32 2, i64 [[IDXPROM]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i32 4, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void +// +void test11(struct annotated *p, int index) { + p->array[index] = __builtin_dynamic_object_size(&p->count, 1); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits