From 19dd7db8ab5f98a618c717944c96b34e604fbc30 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 29 Oct 2023 14:58:04 -0700 Subject: [PATCH 01/19] [CodeGen] Revamp counted_by calculations Break down the counted_by calculations so that they correctly handle anonymous structs, which are specified internally as IndirectFieldDecls. 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. --- clang/lib/CodeGen/CGBuiltin.cpp | 91 +++++++++++++++------------- clang/lib/CodeGen/CGExpr.cpp | 93 +++++++++++++++++++++++------ clang/lib/CodeGen/CodeGenFunction.h | 12 +++- 3 files changed, 134 insertions(+), 62 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index dce5ee5888c45..acee2c1af1ab3 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -859,53 +859,60 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, } if (IsDynamic) { - LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = - getLangOpts().getStrictFlexArraysLevel(); - const Expr *Base = E->IgnoreParenImpCasts(); - - if (FieldDecl *FD = FindCountedByField(Base, StrictFlexArraysLevel)) { - const auto *ME = dyn_cast(Base); - llvm::Value *ObjectSize = nullptr; - - if (!ME) { - const auto *DRE = dyn_cast(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(cast(DRE)), nullptr, VK_PRValue, - FPOptionsOverride()); - ME = MemberExpr::CreateImplicit(getContext(), ICE, true, VD, - VD->getType(), VK_LValue, OK_Ordinary); - } - - // At this point, we know that \p ME is a flexible array member. - const auto *ArrayTy = getContext().getAsArrayType(ME->getType()); + // 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 the whole struct, including the flexible array: + // + // __builtin_dynamic_object_size(p, 1) == + // sizeof(*p) + p->count * sizeof(*p->array) + // + if (const ValueDecl *CountedByFD = FindCountedByField(E)) { + // Find the flexible array member. + const RecordDecl *OuterRD = + CountedByFD->getDeclContext()->getOuterLexicalRecordContext(); + const ValueDecl *FAM = FindFlexibleArrayMemberField(getContext(), + OuterRD); + + // Get the size of the flexible array member's base type. + const auto *ArrayTy = getContext().getAsArrayType(FAM->getType()); unsigned Size = getContext().getTypeSize(ArrayTy->getElementType()); - llvm::Value *CountField = - EmitAnyExprToTemp(MemberExpr::CreateImplicit( - getContext(), const_cast(ME->getBase()), - ME->isArrow(), FD, FD->getType(), VK_LValue, - OK_Ordinary)) - .getScalarVal(); + // Find the outer struct expr (i.e. p in p->a.b.c.d). + Expr *CountedByExpr = BuildCountedByFieldExpr(const_cast(E), + CountedByFD); + + llvm::Value *CountedByInstr = + EmitAnyExprToTemp(CountedByExpr).getScalarVal(); - llvm::Value *Mul = Builder.CreateMul( - CountField, llvm::ConstantInt::get(CountField->getType(), Size / 8)); - Mul = Builder.CreateZExtOrTrunc(Mul, ResType); + llvm::Constant *ArraySize = + llvm::ConstantInt::get(CountedByInstr->getType(), Size / 8); - if (ObjectSize) - return Builder.CreateAdd(ObjectSize, Mul); + llvm::Value *ObjectSize = Builder.CreateMul(CountedByInstr, ArraySize); + ObjectSize = Builder.CreateZExtOrTrunc(ObjectSize, ResType); + + if (const auto *DRE = dyn_cast(E->IgnoreImpCasts())) { + // The whole struct is specificed in the __bdos. + QualType StructTy = DRE->getType()->getPointeeType(); + llvm::Value *StructSize = ConstantInt::get( + ResType, getContext().getTypeSize(StructTy) / 8, true); + ObjectSize = Builder.CreateAdd(StructSize, ObjectSize); + } - return Mul; + // PULL THE STRING!! + return ObjectSize; } } diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 54a1d300a9ac7..2b39194e18ed8 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -944,14 +944,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(CE->getSubExpr()); + if (const ValueDecl *VD = CGF.FindCountedByField(Base)) { IndexedType = Base->getType(); - return CGF - .EmitAnyExprToTemp(MemberExpr::CreateImplicit( - CGF.getContext(), const_cast(ME->getBase()), - ME->isArrow(), FD, FD->getType(), VK_LValue, OK_Ordinary)) - .getScalarVal(); + Expr *E = CGF.BuildCountedByFieldExpr(const_cast(Base), VD); + return CGF.EmitAnyExprToTemp(E).getScalarVal(); } } @@ -966,9 +962,68 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF, return nullptr; } -FieldDecl *CodeGenFunction::FindCountedByField( - const Expr *Base, - LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel) { +Expr *CodeGenFunction::BuildCountedByFieldExpr(Expr *Base, + const ValueDecl *CountedByVD) { + // Find the outer struct expr (i.e. p in p->a.b.c.d). + Base = Base->IgnoreImpCasts(); + Base = Base->IgnoreParenNoopCasts(getContext()); + + // Work our way up the expression until we reach the DeclRefExpr. + while (!isa(Base)) + if (auto *ME = dyn_cast(Base->IgnoreImpCasts())) { + Base = ME->getBase()->IgnoreImpCasts(); + Base = Base->IgnoreParenNoopCasts(getContext()); + } + + // Add back an implicit cast to create the required pr-value. + Base = ImplicitCastExpr::Create( + getContext(), Base->getType(), CK_LValueToRValue, Base, + nullptr, VK_PRValue, FPOptionsOverride()); + + Expr *CountedByExpr = Base; + + if (const auto *IFD = dyn_cast(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()) { + ValueDecl *VD = cast(ND); + CountedByExpr = MemberExpr::CreateImplicit( + getContext(), CountedByExpr, + CountedByExpr->getType()->isPointerType(), VD, VD->getType(), + VK_LValue, OK_Ordinary); + } + } else { + CountedByExpr = MemberExpr::CreateImplicit( + getContext(), CountedByExpr, + CountedByExpr->getType()->isPointerType(), + const_cast(CountedByVD), CountedByVD->getType(), + VK_LValue, OK_Ordinary); + } + + return CountedByExpr; +} + +const ValueDecl *CodeGenFunction::FindFlexibleArrayMemberField( + ASTContext &Ctx, const RecordDecl *RD) { + LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = + getLangOpts().getStrictFlexArraysLevel(); + + for (const Decl *D : RD->decls()) { + if (const ValueDecl *VD = dyn_cast(D); + VD && Decl::isFlexibleArrayMemberLike(Ctx, VD, VD->getType(), + StrictFlexArraysLevel, true)) + return VD; + + if (const auto *Record = dyn_cast(D)) + if (const ValueDecl *VD = FindFlexibleArrayMemberField(Ctx, Record)) + return VD; + } + + return nullptr; +} + +const ValueDecl *CodeGenFunction::FindCountedByField(const Expr *Base) { const ValueDecl *VD = nullptr; Base = Base->IgnoreParenImpCasts(); @@ -984,12 +1039,14 @@ FieldDecl *CodeGenFunction::FindCountedByField( Ty = Ty->getPointeeType(); if (const auto *RD = Ty->getAsRecordDecl()) - VD = RD->getLastField(); + VD = FindFlexibleArrayMemberField(getContext(), RD); } else if (const auto *CE = dyn_cast(Base)) { if (const auto *ME = dyn_cast(CE->getSubExpr())) VD = dyn_cast(ME->getMemberDecl()); } + LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = + getLangOpts().getStrictFlexArraysLevel(); const auto *FD = dyn_cast_if_present(VD); if (!FD || !FD->getParent() || !Decl::isFlexibleArrayMemberLike(getContext(), FD, FD->getType(), @@ -1000,12 +1057,14 @@ FieldDecl *CodeGenFunction::FindCountedByField( 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; + const RecordDecl *RD = FD->getDeclContext()->getOuterLexicalRecordContext(); + DeclarationName DName(CBA->getCountedByField()); + DeclContext::lookup_result Lookup = RD->lookup(DName); + + if (Lookup.empty()) + return nullptr; + + return dyn_cast(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 e82115e2d706c..64f192037ec8c 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3022,11 +3022,17 @@ 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. + Expr *BuildCountedByFieldExpr(Expr *Base, const ValueDecl *CountedByVD); llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre); From 36b5271a7729c626a93a7fec9ff3bbd325436a02 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 29 Oct 2023 15:22:29 -0700 Subject: [PATCH 02/19] Reformat with clang-format --- clang/lib/CodeGen/CGBuiltin.cpp | 14 +++++++------- clang/lib/CodeGen/CGExpr.cpp | 26 +++++++++++++------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index acee2c1af1ab3..26c73d07c7038 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -882,23 +882,23 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, if (const ValueDecl *CountedByFD = FindCountedByField(E)) { // Find the flexible array member. const RecordDecl *OuterRD = - CountedByFD->getDeclContext()->getOuterLexicalRecordContext(); - const ValueDecl *FAM = FindFlexibleArrayMemberField(getContext(), - OuterRD); + CountedByFD->getDeclContext()->getOuterLexicalRecordContext(); + const ValueDecl *FAM = + FindFlexibleArrayMemberField(getContext(), OuterRD); // Get the size of the flexible array member's base type. const auto *ArrayTy = getContext().getAsArrayType(FAM->getType()); unsigned Size = getContext().getTypeSize(ArrayTy->getElementType()); // Find the outer struct expr (i.e. p in p->a.b.c.d). - Expr *CountedByExpr = BuildCountedByFieldExpr(const_cast(E), - CountedByFD); + Expr *CountedByExpr = + BuildCountedByFieldExpr(const_cast(E), CountedByFD); llvm::Value *CountedByInstr = - EmitAnyExprToTemp(CountedByExpr).getScalarVal(); + EmitAnyExprToTemp(CountedByExpr).getScalarVal(); llvm::Constant *ArraySize = - llvm::ConstantInt::get(CountedByInstr->getType(), Size / 8); + llvm::ConstantInt::get(CountedByInstr->getType(), Size / 8); llvm::Value *ObjectSize = Builder.CreateMul(CountedByInstr, ArraySize); ObjectSize = Builder.CreateZExtOrTrunc(ObjectSize, ResType); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 2b39194e18ed8..b39cd8b45fe8f 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -976,9 +976,9 @@ Expr *CodeGenFunction::BuildCountedByFieldExpr(Expr *Base, } // Add back an implicit cast to create the required pr-value. - Base = ImplicitCastExpr::Create( - getContext(), Base->getType(), CK_LValueToRValue, Base, - nullptr, VK_PRValue, FPOptionsOverride()); + Base = + ImplicitCastExpr::Create(getContext(), Base->getType(), CK_LValueToRValue, + Base, nullptr, VK_PRValue, FPOptionsOverride()); Expr *CountedByExpr = Base; @@ -988,24 +988,24 @@ Expr *CodeGenFunction::BuildCountedByFieldExpr(Expr *Base, // easily. (Yay!) for (NamedDecl *ND : IFD->chain()) { ValueDecl *VD = cast(ND); - CountedByExpr = MemberExpr::CreateImplicit( - getContext(), CountedByExpr, - CountedByExpr->getType()->isPointerType(), VD, VD->getType(), - VK_LValue, OK_Ordinary); + CountedByExpr = + MemberExpr::CreateImplicit(getContext(), CountedByExpr, + CountedByExpr->getType()->isPointerType(), + VD, VD->getType(), VK_LValue, OK_Ordinary); } } else { CountedByExpr = MemberExpr::CreateImplicit( - getContext(), CountedByExpr, - CountedByExpr->getType()->isPointerType(), - const_cast(CountedByVD), CountedByVD->getType(), - VK_LValue, OK_Ordinary); + getContext(), CountedByExpr, CountedByExpr->getType()->isPointerType(), + const_cast(CountedByVD), CountedByVD->getType(), VK_LValue, + OK_Ordinary); } return CountedByExpr; } -const ValueDecl *CodeGenFunction::FindFlexibleArrayMemberField( - ASTContext &Ctx, const RecordDecl *RD) { +const ValueDecl * +CodeGenFunction::FindFlexibleArrayMemberField(ASTContext &Ctx, + const RecordDecl *RD) { LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = getLangOpts().getStrictFlexArraysLevel(); From 8c6880b04839cfb146762ac90c0de61f0ee8f20a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 30 Oct 2023 13:30:31 -0700 Subject: [PATCH 03/19] Update testcase with anonymous structs and a union --- clang/test/CodeGen/attr-counted-by.c | 358 ++++++++++++++++++++++++--- 1 file changed, 329 insertions(+), 29 deletions(-) diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c index a7eb0da6dd282..1440ec819f6b1 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: @@ -162,43 +196,36 @@ 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:%.*]]) 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 @[[GLOB6:[0-9]+]], i64 [[TMP3]]) #[[ATTR2]], !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: [[DOTTR:%.*]] = trunc i64 [[TMP0]] to i32 +// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = shl i32 [[DOTTR]], 2 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i32 [[TMP4]], 16 // 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-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: [[DOTTR:%.*]] = trunc i64 [[TMP0]] to i32 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl i32 [[DOTTR]], 2 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i32 [[TMP1]], 16 +// 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]] @@ -207,7 +234,7 @@ struct annotated_with_anon_struct { // SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test4( // 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]] @@ -216,12 +243,285 @@ struct annotated_with_anon_struct { // NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test4( // 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 anon_struct *p, int index) { + p->array[index] = __builtin_dynamic_object_size(p, 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: [[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 @[[GLOB7:[0-9]+]], i64 [[TMP3]]) #[[ATTR2]], !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: [[DOTTR:%.*]] = trunc i64 [[TMP0]] to i32 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[DOTTR]], 2 +// 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 @test5( +// 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: [[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: [[DOTTR:%.*]] = trunc i64 [[TMP0]] to i32 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[DOTTR]], 2 +// 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 @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 [[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 @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 [[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->array, 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: [[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: [[DOTMASK:%.*]] = and i32 [[TMP1]], 255 +// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = icmp ugt i32 [[DOTMASK]], [[INDEX]] +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label [[CONT23:%.*]], 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 @[[GLOB9:[0-9]+]], i64 [[TMP3]]) #[[ATTR2]], !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: [[TMP4:%.*]] = sext i32 [[INDEX]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[TMP4]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = trunc i32 [[TMP1]] to i8 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP5]], 16 +// 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 @test6( +// 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 i32, ptr [[TMP0]], align 8, !tbaa [[TBAA8:![0-9]+]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = trunc i32 [[TMP1]] to i8 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP2]], 16 +// 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 @test6( +// 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 @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: [[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 test6(struct union_of_fams *p, int index) { + p->ints[index] = __builtin_dynamic_object_size(p, 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 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 @[[GLOB10:[0-9]+]], i64 [[TMP5]]) #[[ATTR2]], !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 @test7( +// 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 @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]] +// 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]] +// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void +// +void test7(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 @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 i32, ptr [[TMP0]], align 8, !tbaa [[TBAA10]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = zext i32 [[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 @[[GLOB11:[0-9]+]], i64 [[TMP5]]) #[[ATTR2]], !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 [[TMP3]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = trunc i32 [[TMP1]] to i8 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP6]], 16 +// 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 @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 i32, ptr [[TMP0]], align 8, !tbaa [[TBAA8]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = trunc i32 [[TMP1]] to i8 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP2]], 16 +// 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 @test8( +// 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 @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: [[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 test8(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 @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:%.*]] = zext i32 [[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 @[[GLOB12:[0-9]+]], i64 [[TMP5]]) #[[ATTR2]], !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 [[TMP3]] +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = trunc i32 [[TMP1]] 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 @test9( +// 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 i32, ptr [[TMP0]], align 8, !tbaa [[TBAA8]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = trunc i32 [[TMP1]] 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 @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->bytes, 1); +} From a5fac56d656a44d062a9fbc18e3e29d3b10ef426 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 30 Oct 2023 13:58:12 -0700 Subject: [PATCH 04/19] Use 'IgnoreParenImpCasts' instead of just 'IgnoreImpCasts' --- clang/lib/CodeGen/CGBuiltin.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 26c73d07c7038..c4c31019c031f 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -886,24 +886,24 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, const ValueDecl *FAM = FindFlexibleArrayMemberField(getContext(), OuterRD); - // Get the size of the flexible array member's base type. - const auto *ArrayTy = getContext().getAsArrayType(FAM->getType()); - unsigned Size = getContext().getTypeSize(ArrayTy->getElementType()); - // Find the outer struct expr (i.e. p in p->a.b.c.d). Expr *CountedByExpr = BuildCountedByFieldExpr(const_cast(E), CountedByFD); + // Load the counted_by field. llvm::Value *CountedByInstr = EmitAnyExprToTemp(CountedByExpr).getScalarVal(); + // Get the size of the flexible array member's base type. + const auto *ArrayTy = getContext().getAsArrayType(FAM->getType()); + unsigned Size = getContext().getTypeSize(ArrayTy->getElementType()); llvm::Constant *ArraySize = llvm::ConstantInt::get(CountedByInstr->getType(), Size / 8); llvm::Value *ObjectSize = Builder.CreateMul(CountedByInstr, ArraySize); ObjectSize = Builder.CreateZExtOrTrunc(ObjectSize, ResType); - if (const auto *DRE = dyn_cast(E->IgnoreImpCasts())) { + if (const auto *DRE = dyn_cast(E->IgnoreParenImpCasts())) { // The whole struct is specificed in the __bdos. QualType StructTy = DRE->getType()->getPointeeType(); llvm::Value *StructSize = ConstantInt::get( From 4d2e39c873b067c5ea337d3e0be6b2115c5cf76e Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 30 Oct 2023 14:58:57 -0700 Subject: [PATCH 05/19] Use 'IgnoreParenImpCasts' and adjust code to use fewer 'Expr' variables. --- clang/lib/CodeGen/CGExpr.cpp | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index b39cd8b45fe8f..a9bf2d5a8bf38 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -965,42 +965,36 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF, Expr *CodeGenFunction::BuildCountedByFieldExpr(Expr *Base, const ValueDecl *CountedByVD) { // Find the outer struct expr (i.e. p in p->a.b.c.d). - Base = Base->IgnoreImpCasts(); - Base = Base->IgnoreParenNoopCasts(getContext()); + Base = Base->IgnoreParenImpCasts(); // Work our way up the expression until we reach the DeclRefExpr. while (!isa(Base)) - if (auto *ME = dyn_cast(Base->IgnoreImpCasts())) { - Base = ME->getBase()->IgnoreImpCasts(); - Base = Base->IgnoreParenNoopCasts(getContext()); - } + if (auto *ME = dyn_cast(Base)) + Base = ME->getBase()->IgnoreParenImpCasts(); // Add back an implicit cast to create the required pr-value. Base = ImplicitCastExpr::Create(getContext(), Base->getType(), CK_LValueToRValue, Base, nullptr, VK_PRValue, FPOptionsOverride()); - Expr *CountedByExpr = Base; - if (const auto *IFD = dyn_cast(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()) { - ValueDecl *VD = cast(ND); - CountedByExpr = - MemberExpr::CreateImplicit(getContext(), CountedByExpr, - CountedByExpr->getType()->isPointerType(), - VD, VD->getType(), VK_LValue, OK_Ordinary); + auto *VD = cast(ND); + Base = MemberExpr::CreateImplicit(getContext(), Base, + Base->getType()->isPointerType(), VD, + VD->getType(), VK_LValue, OK_Ordinary); } } else { - CountedByExpr = MemberExpr::CreateImplicit( - getContext(), CountedByExpr, CountedByExpr->getType()->isPointerType(), + Base = MemberExpr::CreateImplicit( + getContext(), Base, Base->getType()->isPointerType(), const_cast(CountedByVD), CountedByVD->getType(), VK_LValue, OK_Ordinary); } - return CountedByExpr; + return Base; } const ValueDecl * @@ -1010,7 +1004,7 @@ CodeGenFunction::FindFlexibleArrayMemberField(ASTContext &Ctx, getLangOpts().getStrictFlexArraysLevel(); for (const Decl *D : RD->decls()) { - if (const ValueDecl *VD = dyn_cast(D); + if (const auto *VD = dyn_cast(D); VD && Decl::isFlexibleArrayMemberLike(Ctx, VD, VD->getType(), StrictFlexArraysLevel, true)) return VD; From e70b48752f0228c5412503b1bef6d6946b686b62 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Mon, 30 Oct 2023 15:29:58 -0700 Subject: [PATCH 06/19] Reduce number of const_casts. --- clang/lib/CodeGen/CGBuiltin.cpp | 3 +-- clang/lib/CodeGen/CGExpr.cpp | 35 ++++++++++++++++------------- clang/lib/CodeGen/CodeGenFunction.h | 3 ++- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index c4c31019c031f..ebd270be8b428 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -887,8 +887,7 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, FindFlexibleArrayMemberField(getContext(), OuterRD); // Find the outer struct expr (i.e. p in p->a.b.c.d). - Expr *CountedByExpr = - BuildCountedByFieldExpr(const_cast(E), CountedByFD); + const Expr *CountedByExpr = BuildCountedByFieldExpr(E, CountedByFD); // Load the counted_by field. llvm::Value *CountedByInstr = diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index a9bf2d5a8bf38..4861179412102 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -946,7 +946,7 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF, if (const ValueDecl *VD = CGF.FindCountedByField(Base)) { IndexedType = Base->getType(); - Expr *E = CGF.BuildCountedByFieldExpr(const_cast(Base), VD); + const Expr *E = CGF.BuildCountedByFieldExpr(Base, VD); return CGF.EmitAnyExprToTemp(E).getScalarVal(); } } @@ -962,20 +962,21 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF, return nullptr; } -Expr *CodeGenFunction::BuildCountedByFieldExpr(Expr *Base, - const ValueDecl *CountedByVD) { +const Expr * +CodeGenFunction::BuildCountedByFieldExpr(const Expr *Base, + const ValueDecl *CountedByVD) { // Find the outer struct expr (i.e. p in p->a.b.c.d). - Base = Base->IgnoreParenImpCasts(); + Expr *CountedByExpr = const_cast(Base)->IgnoreParenImpCasts(); // Work our way up the expression until we reach the DeclRefExpr. - while (!isa(Base)) - if (auto *ME = dyn_cast(Base)) - Base = ME->getBase()->IgnoreParenImpCasts(); + while (!isa(CountedByExpr)) + if (const auto *ME = dyn_cast(CountedByExpr)) + CountedByExpr = ME->getBase()->IgnoreParenImpCasts(); // Add back an implicit cast to create the required pr-value. - Base = - ImplicitCastExpr::Create(getContext(), Base->getType(), CK_LValueToRValue, - Base, nullptr, VK_PRValue, FPOptionsOverride()); + CountedByExpr = ImplicitCastExpr::Create( + getContext(), CountedByExpr->getType(), CK_LValueToRValue, CountedByExpr, + nullptr, VK_PRValue, FPOptionsOverride()); if (const auto *IFD = dyn_cast(CountedByVD)) { // The counted_by field is inside an anonymous struct / union. The @@ -983,18 +984,20 @@ Expr *CodeGenFunction::BuildCountedByFieldExpr(Expr *Base, // easily. (Yay!) for (NamedDecl *ND : IFD->chain()) { auto *VD = cast(ND); - Base = MemberExpr::CreateImplicit(getContext(), Base, - Base->getType()->isPointerType(), VD, - VD->getType(), VK_LValue, OK_Ordinary); + CountedByExpr = + MemberExpr::CreateImplicit(getContext(), CountedByExpr, + CountedByExpr->getType()->isPointerType(), + VD, VD->getType(), VK_LValue, OK_Ordinary); } } else { - Base = MemberExpr::CreateImplicit( - getContext(), Base, Base->getType()->isPointerType(), + CountedByExpr = MemberExpr::CreateImplicit( + getContext(), const_cast(CountedByExpr), + CountedByExpr->getType()->isPointerType(), const_cast(CountedByVD), CountedByVD->getType(), VK_LValue, OK_Ordinary); } - return Base; + return CountedByExpr; } const ValueDecl * diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 64f192037ec8c..af0faf10a62a5 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3032,7 +3032,8 @@ class CodeGenFunction : public CodeGenTypeCache { const ValueDecl *FindCountedByField(const Expr *Base); /// Build an expression accessing the "counted_by" field. - Expr *BuildCountedByFieldExpr(Expr *Base, const ValueDecl *CountedByVD); + const Expr *BuildCountedByFieldExpr(const Expr *Base, + const ValueDecl *CountedByVD); llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre); From 3f98e8ee7a2ad640e78c588c30e5b96ba33d68bf Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 31 Oct 2023 13:15:21 -0700 Subject: [PATCH 07/19] Use 'getTypeSizeInChars' instead of dividing by 8 --- clang/lib/CodeGen/CGBuiltin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index ebd270be8b428..5d6e9f5efe952 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -906,7 +906,8 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, // The whole struct is specificed in the __bdos. QualType StructTy = DRE->getType()->getPointeeType(); llvm::Value *StructSize = ConstantInt::get( - ResType, getContext().getTypeSize(StructTy) / 8, true); + ResType, getContext().getTypeSizeInChars(StructTy).getQuantity(), + true); ObjectSize = Builder.CreateAdd(StructSize, ObjectSize); } From b503de029db1425d3296c419f8d4532259462084 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 31 Oct 2023 14:54:20 -0700 Subject: [PATCH 08/19] Use 'getTypeSizeInChars' instead of dividing by 8 --- clang/lib/CodeGen/CGBuiltin.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 5d6e9f5efe952..f966d4563b4d1 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -895,9 +895,11 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, // Get the size of the flexible array member's base type. const auto *ArrayTy = getContext().getAsArrayType(FAM->getType()); - unsigned Size = getContext().getTypeSize(ArrayTy->getElementType()); + CharUnits Size = + getContext().getTypeSizeInChars(ArrayTy->getElementType()); llvm::Constant *ArraySize = - llvm::ConstantInt::get(CountedByInstr->getType(), Size / 8); + llvm::ConstantInt::get(CountedByInstr->getType(), + Size.getQuantity()); llvm::Value *ObjectSize = Builder.CreateMul(CountedByInstr, ArraySize); ObjectSize = Builder.CreateZExtOrTrunc(ObjectSize, ResType); From 82588c309f0ec51e30e2b98e989bcbc10a692e3f Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 31 Oct 2023 14:54:45 -0700 Subject: [PATCH 09/19] Format --- clang/lib/CodeGen/CGBuiltin.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index f966d4563b4d1..11d152d612590 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -898,8 +898,7 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, CharUnits Size = getContext().getTypeSizeInChars(ArrayTy->getElementType()); llvm::Constant *ArraySize = - llvm::ConstantInt::get(CountedByInstr->getType(), - Size.getQuantity()); + llvm::ConstantInt::get(CountedByInstr->getType(), Size.getQuantity()); llvm::Value *ObjectSize = Builder.CreateMul(CountedByInstr, ArraySize); ObjectSize = Builder.CreateZExtOrTrunc(ObjectSize, ResType); From dc8f0df02a20d34f59e841d09c358a3ae9ad33f6 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 31 Oct 2023 16:54:54 -0700 Subject: [PATCH 10/19] Use 'offsetof(struct s, array) + p->count * sizeof(*p->array)' instead of sizeof, which could emit an erroneous answer when alignment and padding are taken into account. --- clang/lib/CodeGen/CGBuiltin.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 11d152d612590..177da15f5e998 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -877,14 +877,14 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, // 2) bdos of the whole struct, including the flexible array: // // __builtin_dynamic_object_size(p, 1) == - // sizeof(*p) + p->count * sizeof(*p->array) + // offsetof(struct s, array) + p->count * sizeof(*p->array) // if (const ValueDecl *CountedByFD = FindCountedByField(E)) { // Find the flexible array member. + ASTContext &Ctx = getContext(); const RecordDecl *OuterRD = CountedByFD->getDeclContext()->getOuterLexicalRecordContext(); - const ValueDecl *FAM = - FindFlexibleArrayMemberField(getContext(), OuterRD); + const ValueDecl *FAM = FindFlexibleArrayMemberField(Ctx, OuterRD); // Find the outer struct expr (i.e. p in p->a.b.c.d). const Expr *CountedByExpr = BuildCountedByFieldExpr(E, CountedByFD); @@ -894,9 +894,8 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, EmitAnyExprToTemp(CountedByExpr).getScalarVal(); // Get the size of the flexible array member's base type. - const auto *ArrayTy = getContext().getAsArrayType(FAM->getType()); - CharUnits Size = - getContext().getTypeSizeInChars(ArrayTy->getElementType()); + const auto *ArrayTy = Ctx.getAsArrayType(FAM->getType()); + CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType()); llvm::Constant *ArraySize = llvm::ConstantInt::get(CountedByInstr->getType(), Size.getQuantity()); @@ -905,10 +904,10 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, if (const auto *DRE = dyn_cast(E->IgnoreParenImpCasts())) { // The whole struct is specificed in the __bdos. - QualType StructTy = DRE->getType()->getPointeeType(); - llvm::Value *StructSize = ConstantInt::get( - ResType, getContext().getTypeSizeInChars(StructTy).getQuantity(), - true); + CharUnits FAMOffset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAM)); + llvm::Value *StructSize = + ConstantInt::get(ResType, FAMOffset.getQuantity(), true); + ObjectSize = Builder.CreateAdd(StructSize, ObjectSize); } From 6260945883672c3067aa46331c99d60348c3052a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 31 Oct 2023 17:26:37 -0700 Subject: [PATCH 11/19] Adjust testcase to reflect 'offsetof' change. --- clang/test/CodeGen/attr-counted-by.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c index 1440ec819f6b1..595224303773b 100644 --- a/clang/test/CodeGen/attr-counted-by.c +++ b/clang/test/CodeGen/attr-counted-by.c @@ -17,7 +17,7 @@ #define DECLARE_FLEX_ARRAY(TYPE, NAME) \ struct { \ struct { } __empty_ ## NAME; \ - TYPE NAME[]; \ + TYPE NAME[]; \ } #define DECLARE_BOUNDED_FLEX_ARRAY(COUNT_TYPE, COUNT, TYPE, NAME) \ @@ -161,7 +161,7 @@ void test2(struct annotated *p, size_t index) { // 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: [[CONV:%.*]] = add i32 [[TMP3]], 12 // SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // SANITIZE-WITH-ATTR-NEXT: ret void // @@ -171,7 +171,7 @@ void test2(struct annotated *p, size_t index) { // 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: [[CONV:%.*]] = add i32 [[TMP1]], 12 // 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 @@ -212,8 +212,7 @@ void test3(struct annotated *p, size_t index) { // 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: [[DOTTR:%.*]] = trunc i64 [[TMP0]] to i32 -// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = shl i32 [[DOTTR]], 2 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i32 [[TMP4]], 16 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[DOTTR]], 2 // SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // SANITIZE-WITH-ATTR-NEXT: ret void // @@ -223,8 +222,7 @@ void test3(struct annotated *p, size_t index) { // 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: [[DOTTR:%.*]] = trunc i64 [[TMP0]] to i32 -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl i32 [[DOTTR]], 2 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i32 [[TMP1]], 16 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[DOTTR]], 2 // 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]] @@ -325,7 +323,7 @@ void test5(struct anon_struct *p, int index) { // SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = sext i32 [[INDEX]] to i64, !nosanitize !6 // SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[TMP4]] // SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = trunc i32 [[TMP1]] to i8 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP5]], 16 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP5]], 4 // SANITIZE-WITH-ATTR-NEXT: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA10:![0-9]+]] // SANITIZE-WITH-ATTR-NEXT: ret void // @@ -335,7 +333,7 @@ void test5(struct anon_struct *p, int index) { // 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:%.*]] = trunc i32 [[TMP1]] to i8 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP2]], 16 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP2]], 4 // 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]] @@ -433,7 +431,7 @@ void test7(struct union_of_fams *p, int index) { // 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 [[TMP3]] // SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = trunc i32 [[TMP1]] to i8 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP6]], 16 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP6]], 4 // SANITIZE-WITH-ATTR-NEXT: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA10]] // SANITIZE-WITH-ATTR-NEXT: ret void // @@ -443,7 +441,7 @@ void test7(struct union_of_fams *p, int index) { // 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:%.*]] = trunc i32 [[TMP1]] to i8 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP2]], 16 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP2]], 4 // 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]] From 7a20a343500cacab26c5b0ae62f04fd6d6e59cd9 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 1 Nov 2023 13:35:33 -0700 Subject: [PATCH 12/19] Return the max of the struct size or offset + FAM size. --- clang/lib/CodeGen/CGBuiltin.cpp | 43 ++++++++------- clang/test/CodeGen/attr-counted-by.c | 81 ++++++++++++++++------------ 2 files changed, 73 insertions(+), 51 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 177da15f5e998..a81b2c266d97f 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -877,42 +877,49 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, // 2) bdos of the whole struct, including the flexible array: // // __builtin_dynamic_object_size(p, 1) == - // offsetof(struct s, array) + p->count * sizeof(*p->array) + // max(sizeof(struct s), + // offsetof(struct s, array) + p->count * sizeof(*p->array)) // if (const ValueDecl *CountedByFD = FindCountedByField(E)) { - // Find the flexible array member. - ASTContext &Ctx = getContext(); const RecordDecl *OuterRD = CountedByFD->getDeclContext()->getOuterLexicalRecordContext(); - const ValueDecl *FAM = FindFlexibleArrayMemberField(Ctx, OuterRD); + ASTContext &Ctx = getContext(); - // Find the outer struct expr (i.e. p in p->a.b.c.d). - const Expr *CountedByExpr = BuildCountedByFieldExpr(E, CountedByFD); + // Find the flexible array member. + const ValueDecl *FAM = FindFlexibleArrayMemberField(Ctx, OuterRD); // Load the counted_by field. - llvm::Value *CountedByInstr = + const Expr *CountedByExpr = BuildCountedByFieldExpr(E, CountedByFD); + llvm::Value *CountedByInst = EmitAnyExprToTemp(CountedByExpr).getScalarVal(); // Get the size of the flexible array member's base type. const auto *ArrayTy = Ctx.getAsArrayType(FAM->getType()); CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType()); - llvm::Constant *ArraySize = - llvm::ConstantInt::get(CountedByInstr->getType(), Size.getQuantity()); + llvm::Constant *ElemSize = + llvm::ConstantInt::get(CountedByInst->getType(), Size.getQuantity()); - llvm::Value *ObjectSize = Builder.CreateMul(CountedByInstr, ArraySize); - ObjectSize = Builder.CreateZExtOrTrunc(ObjectSize, ResType); + llvm::Value *FAMSize = Builder.CreateMul(CountedByInst, ElemSize); + llvm::Value *Res = Builder.CreateZExtOrTrunc(FAMSize, ResType); + // The whole struct is specificed in the __bdos. if (const auto *DRE = dyn_cast(E->IgnoreParenImpCasts())) { - // The whole struct is specificed in the __bdos. - CharUnits FAMOffset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAM)); - llvm::Value *StructSize = - ConstantInt::get(ResType, FAMOffset.getQuantity(), true); - - ObjectSize = Builder.CreateAdd(StructSize, ObjectSize); + // Get the full size of the struct. + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD); + llvm::Value *SizeofStruct = + ConstantInt::get(ResType, Layout.getSize().getQuantity(), true); + + CharUnits Offset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAM)); + llvm::Value *FAMOffset = + ConstantInt::get(ResType, Offset.getQuantity(), true); + + llvm::Value *OffsetAndFAMSize = Builder.CreateAdd(FAMOffset, Res); + Res = Builder.CreateBinaryIntrinsic(llvm::Intrinsic::smax, + OffsetAndFAMSize, SizeofStruct); } // PULL THE STRING!! - return ObjectSize; + return Res; } } diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c index 595224303773b..5c5a16f4ca32e 100644 --- a/clang/test/CodeGen/attr-counted-by.c +++ b/clang/test/CodeGen/attr-counted-by.c @@ -67,7 +67,7 @@ struct anon_struct { // 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]]) #[[ATTR3:[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]] @@ -111,7 +111,7 @@ 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]]) #[[ATTR3]], !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]] @@ -156,22 +156,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]]) #[[ATTR3]], !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]], 12 +// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = zext i32 [[TMP3]] to i64 +// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP4]], i64 4) +// SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = trunc i64 [[TMP5]] to i32 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i32 [[TMP6]], 12 // 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]], 12 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP2]], i64 4) +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = trunc i64 [[TMP3]] to i32 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i32 [[TMP4]], 12 // 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 @@ -206,23 +212,25 @@ void test3(struct annotated *p, size_t index) { // 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 @[[GLOB6:[0-9]+]], i64 [[TMP3]]) #[[ATTR2]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB6:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !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: [[DOTTR:%.*]] = trunc i64 [[TMP0]] to i32 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[DOTTR]], 2 +// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = shl i64 [[TMP0]], 2 +// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP4]], i64 16) +// 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 @test4( -// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] { +// 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:![0-9]+]] -// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTTR:%.*]] = trunc i64 [[TMP0]] to i32 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[DOTTR]], 2 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl i64 [[TMP0]], 2 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP1]], i64 16) +// 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]] @@ -261,7 +269,7 @@ void test4(struct anon_struct *p, int index) { // 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 @[[GLOB7:[0-9]+]], i64 [[TMP3]]) #[[ATTR2]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB7:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !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 @@ -311,29 +319,33 @@ void test5(struct anon_struct *p, int index) { // 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: [[DOTMASK:%.*]] = and i32 [[TMP1]], 255 -// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = icmp ugt i32 [[DOTMASK]], [[INDEX]] -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label [[CONT23:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF7]], !nosanitize !6 +// 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: [[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]]) #[[ATTR2]], !nosanitize !6 +// 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 @[[GLOB9:[0-9]+]], i64 [[TMP4]]) #[[ATTR3]], !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: [[TMP4:%.*]] = sext i32 [[INDEX]] to i64, !nosanitize !6 -// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[TMP4]] -// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = trunc i32 [[TMP1]] to i8 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP5]], 4 +// 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:%.*]] = zext i32 [[TMP1]] to i64 +// SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP6]], i64 12) +// SANITIZE-WITH-ATTR-NEXT: [[TMP8:%.*]] = trunc i64 [[TMP7]] to i8 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP8]], 4 // 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 @test6( -// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] { +// 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:%.*]] = trunc i32 [[TMP1]] to i8 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP2]], 4 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP2]], i64 12) +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = trunc i64 [[TMP3]] to i8 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP4]], 4 // 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]] @@ -373,7 +385,7 @@ void test6(struct union_of_fams *p, int index) { // 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 @[[GLOB10:[0-9]+]], i64 [[TMP5]]) #[[ATTR2]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB10:[0-9]+]], i64 [[TMP5]]) #[[ATTR3]], !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 @@ -425,23 +437,26 @@ void test7(struct union_of_fams *p, int index) { // 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 @[[GLOB11:[0-9]+]], i64 [[TMP5]]) #[[ATTR2]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB11:[0-9]+]], i64 [[TMP5]]) #[[ATTR3]], !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 [[TMP3]] -// SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = trunc i32 [[TMP1]] to i8 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP6]], 4 +// SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP2]], i64 12) +// SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = trunc i64 [[TMP6]] to i8 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP7]], 4 // 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 @test8( -// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] { +// 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:%.*]] = trunc i32 [[TMP1]] to i8 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP2]], 4 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP2]], i64 12) +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = trunc i64 [[TMP3]] to i8 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP4]], 4 // 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]] @@ -481,7 +496,7 @@ void test8(struct union_of_fams *p, int index) { // 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 @[[GLOB12:[0-9]+]], i64 [[TMP5]]) #[[ATTR2]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB12:[0-9]+]], i64 [[TMP5]]) #[[ATTR3]], !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 From 1e94fecd840742172bfdd4d19fb104c24b00d69c Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 1 Nov 2023 14:00:17 -0700 Subject: [PATCH 13/19] Small reordering of code and added more comments. --- clang/lib/CodeGen/CGBuiltin.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index a81b2c266d97f..3bfaea7849ce3 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -885,16 +885,14 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, CountedByFD->getDeclContext()->getOuterLexicalRecordContext(); ASTContext &Ctx = getContext(); - // Find the flexible array member. - const ValueDecl *FAM = FindFlexibleArrayMemberField(Ctx, OuterRD); - // Load the counted_by field. const Expr *CountedByExpr = BuildCountedByFieldExpr(E, CountedByFD); llvm::Value *CountedByInst = EmitAnyExprToTemp(CountedByExpr).getScalarVal(); // Get the size of the flexible array member's base type. - const auto *ArrayTy = Ctx.getAsArrayType(FAM->getType()); + const ValueDecl *FAM = FindFlexibleArrayMemberField(Ctx, OuterRD); + const ArrayType *ArrayTy = Ctx.getAsArrayType(FAM->getType()); CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType()); llvm::Constant *ElemSize = llvm::ConstantInt::get(CountedByInst->getType(), Size.getQuantity()); @@ -902,17 +900,20 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, llvm::Value *FAMSize = Builder.CreateMul(CountedByInst, ElemSize); llvm::Value *Res = Builder.CreateZExtOrTrunc(FAMSize, ResType); - // The whole struct is specificed in the __bdos. if (const auto *DRE = dyn_cast(E->IgnoreParenImpCasts())) { + // The whole struct is specificed in the __bdos. // Get the full size of the struct. const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD); llvm::Value *SizeofStruct = ConstantInt::get(ResType, Layout.getSize().getQuantity(), true); + // Get the offset of the FAM. CharUnits Offset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAM)); llvm::Value *FAMOffset = ConstantInt::get(ResType, Offset.getQuantity(), true); + // max(sizeof(struct s), + // offsetof(struct s, array) + p->count * sizeof(*p->array)) llvm::Value *OffsetAndFAMSize = Builder.CreateAdd(FAMOffset, Res); Res = Builder.CreateBinaryIntrinsic(llvm::Intrinsic::smax, OffsetAndFAMSize, SizeofStruct); From c9819d78bbc8091ce6c235c28cf306311b62b3c9 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 1 Nov 2023 16:44:25 -0700 Subject: [PATCH 14/19] Support a __bdos() on an index into the FAM. --- clang/lib/CodeGen/CGBuiltin.cpp | 32 ++++++- clang/lib/CodeGen/CGExpr.cpp | 5 +- clang/test/CodeGen/attr-counted-by.c | 125 +++++++++++++++++++-------- 3 files changed, 122 insertions(+), 40 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 3bfaea7849ce3..db54d629cf4f9 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" @@ -874,22 +875,47 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, // __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)) // - if (const ValueDecl *CountedByFD = FindCountedByField(E)) { + const Expr *Base = E->IgnoreParenImpCasts(); + const Expr *Idx = nullptr; + if (const auto *UO = dyn_cast(Base); + UO && UO->getOpcode() == UO_AddrOf) { + if (const auto *ASE = dyn_cast(UO->getSubExpr())) { + Base = ASE->getBase(); + Idx = ASE->getIdx()->IgnoreParenImpCasts(); + if (const auto *IL = dyn_cast(Idx); + IL && !IL->getValue().getZExtValue()) { + Idx = nullptr; + } + } + } + + if (const ValueDecl *CountedByFD = FindCountedByField(Base)) { const RecordDecl *OuterRD = CountedByFD->getDeclContext()->getOuterLexicalRecordContext(); ASTContext &Ctx = getContext(); // Load the counted_by field. - const Expr *CountedByExpr = BuildCountedByFieldExpr(E, CountedByFD); + const Expr *CountedByExpr = BuildCountedByFieldExpr(Base, CountedByFD); llvm::Value *CountedByInst = EmitAnyExprToTemp(CountedByExpr).getScalarVal(); + if (Idx) { + llvm::Value *IdxInst = EmitAnyExprToTemp(Idx).getScalarVal(); + IdxInst = Builder.CreateZExtOrTrunc(IdxInst, CountedByInst->getType()); + CountedByInst = Builder.CreateSub(CountedByInst, IdxInst); + } + // Get the size of the flexible array member's base type. const ValueDecl *FAM = FindFlexibleArrayMemberField(Ctx, OuterRD); const ArrayType *ArrayTy = Ctx.getAsArrayType(FAM->getType()); @@ -900,7 +926,7 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, llvm::Value *FAMSize = Builder.CreateMul(CountedByInst, ElemSize); llvm::Value *Res = Builder.CreateZExtOrTrunc(FAMSize, ResType); - if (const auto *DRE = dyn_cast(E->IgnoreParenImpCasts())) { + if (const auto *DRE = dyn_cast(Base)) { // The whole struct is specificed in the __bdos. // Get the full size of the struct. const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 4861179412102..80ba8e24e6f80 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1008,8 +1008,9 @@ CodeGenFunction::FindFlexibleArrayMemberField(ASTContext &Ctx, for (const Decl *D : RD->decls()) { if (const auto *VD = dyn_cast(D); - VD && Decl::isFlexibleArrayMemberLike(Ctx, VD, VD->getType(), - StrictFlexArraysLevel, true)) + VD && Decl::isFlexibleArrayMemberLike( + Ctx, VD, VD->getType(), StrictFlexArraysLevel, + /*IgnoreTemplateOrMacroSubstitution=*/true)) return VD; if (const auto *Record = dyn_cast(D)) diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c index 5c5a16f4ca32e..23d854ae991cc 100644 --- a/clang/test/CodeGen/attr-counted-by.c +++ b/clang/test/CodeGen/attr-counted-by.c @@ -205,6 +205,61 @@ void test3(struct annotated *p, size_t index) { // SANITIZE-WITH-ATTR-LABEL: define dso_local void @test4( // 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 [[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]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 +// SANITIZE-WITH-ATTR: cont13: +// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[TMP1]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = shl i32 [[TMP0]], 2 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i32 [[TMP5]], 244 +// SANITIZE-WITH-ATTR-NEXT: [[CONV3:%.*]] = and i32 [[CONV]], 252 +// SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV3]], 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-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]], 244 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV1:%.*]] = and i32 [[CONV]], 252 +// 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: ret void +// +// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test4( +// 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: [[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: ret void +// +// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test4( +// 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: [[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: ret void +// +void test4(struct annotated *p, int index) { + // This tests calculating the size from a pointer inside the FAM. + p->array[index] = (unsigned char)__builtin_dynamic_object_size(&p->array[3], 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: [[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 @@ -212,7 +267,7 @@ void test3(struct annotated *p, size_t index) { // 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 @[[GLOB6:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB7:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !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 @@ -223,7 +278,7 @@ void test3(struct annotated *p, size_t index) { // 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-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: [[COUNT:%.*]] = getelementptr inbounds [[STRUCT_ANON_STRUCT:%.*]], ptr [[P]], i64 0, i32 1 @@ -237,7 +292,7 @@ void test3(struct annotated *p, size_t index) { // 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 [[STRUCT_ANON_STRUCT:%.*]], ptr [[P]], i64 1 @@ -246,7 +301,7 @@ void test3(struct annotated *p, size_t index) { // 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 [[STRUCT_ANON_STRUCT:%.*]], ptr [[P]], i64 1 @@ -255,11 +310,11 @@ void test3(struct annotated *p, size_t index) { // NO-SANITIZE-WITHOUT-ATTR-NEXT: store i32 -1, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void // -void test4(struct 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 @test5( +// 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 @@ -269,7 +324,7 @@ void test4(struct anon_struct *p, int index) { // 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 @[[GLOB7:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB8:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !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 @@ -279,7 +334,7 @@ void test4(struct anon_struct *p, int index) { // 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 @test5( +// 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 #[[ATTR1]] { // NO-SANITIZE-WITH-ATTR-NEXT: entry: // NO-SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = getelementptr inbounds [[STRUCT_ANON_STRUCT:%.*]], ptr [[P]], i64 0, i32 1 @@ -292,7 +347,7 @@ void test4(struct anon_struct *p, int index) { // 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 @test5( +// 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 @@ -301,7 +356,7 @@ void test4(struct anon_struct *p, int index) { // 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 @test5( +// 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 @@ -310,11 +365,11 @@ void test4(struct anon_struct *p, int index) { // NO-SANITIZE-WITHOUT-ATTR-NEXT: store i32 -1, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void // -void test5(struct anon_struct *p, int index) { +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 @test6( +// 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 @@ -324,7 +379,7 @@ void test5(struct anon_struct *p, int 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 @[[GLOB9:[0-9]+]], i64 [[TMP4]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB10:[0-9]+]], i64 [[TMP4]]) #[[ATTR3]], !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 @@ -337,7 +392,7 @@ void test5(struct anon_struct *p, int index) { // 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 @test6( +// 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 @@ -352,7 +407,7 @@ void test5(struct anon_struct *p, int index) { // 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 @test6( +// 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 @@ -361,7 +416,7 @@ void test5(struct anon_struct *p, int index) { // 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 @test6( +// 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 @@ -370,11 +425,11 @@ void test5(struct anon_struct *p, int index) { // NO-SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6:![0-9]+]] // NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void // -void test6(struct union_of_fams *p, int index) { +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 @test7( +// 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 @@ -385,7 +440,7 @@ void test6(struct union_of_fams *p, int index) { // 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 @[[GLOB10:[0-9]+]], i64 [[TMP5]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB11:[0-9]+]], i64 [[TMP5]]) #[[ATTR3]], !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 @@ -393,7 +448,7 @@ void test6(struct union_of_fams *p, int index) { // 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 @test7( +// 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 @@ -404,7 +459,7 @@ void test6(struct union_of_fams *p, int index) { // 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 @test7( +// 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 @@ -413,7 +468,7 @@ void test6(struct union_of_fams *p, int index) { // 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 @test7( +// 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 @@ -422,11 +477,11 @@ void test6(struct union_of_fams *p, int index) { // NO-SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]] // NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void // -void test7(struct union_of_fams *p, int index) { +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 @test8( +// 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 @@ -437,7 +492,7 @@ void test7(struct union_of_fams *p, int index) { // 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 @[[GLOB11:[0-9]+]], i64 [[TMP5]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB12:[0-9]+]], i64 [[TMP5]]) #[[ATTR3]], !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 @@ -448,7 +503,7 @@ void test7(struct union_of_fams *p, int index) { // 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 @test8( +// 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 @@ -463,7 +518,7 @@ void test7(struct union_of_fams *p, int index) { // 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 @test8( +// 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 @@ -472,7 +527,7 @@ void test7(struct union_of_fams *p, int index) { // 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-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 @@ -481,11 +536,11 @@ void test7(struct union_of_fams *p, int index) { // 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) { +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 @test9( +// 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 @@ -496,7 +551,7 @@ void test8(struct union_of_fams *p, int index) { // 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 @[[GLOB12:[0-9]+]], i64 [[TMP5]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB13:[0-9]+]], i64 [[TMP5]]) #[[ATTR3]], !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 @@ -505,7 +560,7 @@ void test8(struct union_of_fams *p, int index) { // 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-LABEL: define dso_local void @test10( // 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 @@ -517,7 +572,7 @@ void test8(struct union_of_fams *p, int index) { // 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-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 @@ -526,7 +581,7 @@ void test8(struct union_of_fams *p, int index) { // 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-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 @@ -535,6 +590,6 @@ void test8(struct union_of_fams *p, int index) { // 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) { +void test10(struct union_of_fams *p, int index) { p->bytes[index] = (unsigned char)__builtin_dynamic_object_size(p->bytes, 1); } From 7abab68a06861702761494330eb3aae094b00f0a Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 8 Nov 2023 13:56:13 -0800 Subject: [PATCH 15/19] Ignore parens for '&(p->fam[10])' expressions and use signed extend instead of unsigned. --- clang/lib/CodeGen/CGBuiltin.cpp | 11 ++++--- clang/test/CodeGen/attr-counted-by.c | 47 +++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 080ee8bb9ec8c..5b04a6aab63ae 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -890,13 +890,14 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, const Expr *Idx = nullptr; if (const auto *UO = dyn_cast(Base); UO && UO->getOpcode() == UO_AddrOf) { - if (const auto *ASE = dyn_cast(UO->getSubExpr())) { + if (const auto *ASE = + dyn_cast(UO->getSubExpr()->IgnoreParens())) { Base = ASE->getBase(); Idx = ASE->getIdx()->IgnoreParenImpCasts(); + if (const auto *IL = dyn_cast(Idx); - IL && !IL->getValue().getZExtValue()) { + IL && !IL->getValue().getSExtValue()) Idx = nullptr; - } } } @@ -912,7 +913,7 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, if (Idx) { llvm::Value *IdxInst = EmitAnyExprToTemp(Idx).getScalarVal(); - IdxInst = Builder.CreateZExtOrTrunc(IdxInst, CountedByInst->getType()); + IdxInst = Builder.CreateSExtOrTrunc(IdxInst, CountedByInst->getType()); CountedByInst = Builder.CreateSub(CountedByInst, IdxInst); } @@ -924,7 +925,7 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, llvm::ConstantInt::get(CountedByInst->getType(), Size.getQuantity()); llvm::Value *FAMSize = Builder.CreateMul(CountedByInst, ElemSize); - llvm::Value *Res = Builder.CreateZExtOrTrunc(FAMSize, ResType); + llvm::Value *Res = Builder.CreateSExtOrTrunc(FAMSize, ResType); if (const auto *DRE = dyn_cast(Base)) { // The whole struct is specificed in the __bdos. diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c index 23d854ae991cc..cdfc929c97069 100644 --- a/clang/test/CodeGen/attr-counted-by.c +++ b/clang/test/CodeGen/attr-counted-by.c @@ -216,11 +216,27 @@ void test3(struct annotated *p, size_t index) { // SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB6:[0-9]+]], i64 [[TMP4]]) #[[ATTR3]], !nosanitize !6 // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 // SANITIZE-WITH-ATTR: cont13: -// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[TMP1]] // SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = shl i32 [[TMP0]], 2 // SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i32 [[TMP5]], 244 // SANITIZE-WITH-ATTR-NEXT: [[CONV3:%.*]] = and i32 [[CONV]], 252 +// 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: [[TMP6:%.*]] = load i32, ptr [[COUNT]], align 8, !tbaa [[TBAA2]] +// SANITIZE-WITH-ATTR-NEXT: [[ADD:%.*]] = add nsw i32 [[INDEX]], 1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = sext i32 [[ADD]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP8:%.*]] = zext i32 [[TMP6]] to i64, !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: [[TMP9:%.*]] = icmp ult i64 [[TMP7]], [[TMP8]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP9]], label [[CONT34:%.*]], label [[HANDLER_OUT_OF_BOUNDS29:%.*]], !prof [[PROF7]], !nosanitize !6 +// SANITIZE-WITH-ATTR: handler.out_of_bounds29: +// SANITIZE-WITH-ATTR-NEXT: [[TMP10:%.*]] = 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 [[TMP10]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 +// SANITIZE-WITH-ATTR: cont34: +// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX32:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[TMP7]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP11:%.*]] = shl i32 [[TMP6]], 2 +// SANITIZE-WITH-ATTR-NEXT: [[CONV19:%.*]] = add i32 [[TMP11]], 240 +// SANITIZE-WITH-ATTR-NEXT: [[CONV20:%.*]] = and i32 [[CONV19]], 252 +// SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV20]], ptr [[ARRAYIDX32]], align 4, !tbaa [[TBAA2]] // SANITIZE-WITH-ATTR-NEXT: ret void // // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test4( @@ -234,6 +250,14 @@ void test3(struct annotated *p, size_t index) { // 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: [[TMP2:%.*]] = load i32, ptr [[COUNT]], align 8, !tbaa [[TBAA2]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = shl i32 [[TMP2]], 2 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV3:%.*]] = add i32 [[TMP3]], 240 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV4:%.*]] = and i32 [[CONV3]], 252 +// 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: ret void // // SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test4( @@ -242,6 +266,10 @@ void test3(struct annotated *p, size_t index) { // 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: ret void // // NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test4( @@ -250,11 +278,16 @@ void test3(struct annotated *p, size_t index) { // 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: ret void // void test4(struct annotated *p, int index) { // 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); } // SANITIZE-WITH-ATTR-LABEL: define dso_local void @test5( @@ -267,7 +300,7 @@ void test4(struct annotated *p, int index) { // 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 @[[GLOB7:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB8:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !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 @@ -324,7 +357,7 @@ void test5(struct anon_struct *p, int index) { // 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 @[[GLOB8:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB9:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !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 @@ -379,7 +412,7 @@ void test6(struct anon_struct *p, int 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 @[[GLOB10:[0-9]+]], i64 [[TMP4]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB11:[0-9]+]], i64 [[TMP4]]) #[[ATTR3]], !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 @@ -440,7 +473,7 @@ void test7(struct union_of_fams *p, int index) { // 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 @[[GLOB11:[0-9]+]], i64 [[TMP5]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB12:[0-9]+]], i64 [[TMP5]]) #[[ATTR3]], !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 @@ -492,7 +525,7 @@ void test8(struct union_of_fams *p, int index) { // 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 @[[GLOB12:[0-9]+]], i64 [[TMP5]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB13:[0-9]+]], i64 [[TMP5]]) #[[ATTR3]], !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 @@ -551,7 +584,7 @@ void test9(struct union_of_fams *p, int index) { // 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]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB14:[0-9]+]], i64 [[TMP5]]) #[[ATTR3]], !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 From cbdfc3b74ad4c69efa820542535da256fcbbdecf Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 8 Nov 2023 14:10:03 -0800 Subject: [PATCH 16/19] Update testcase --- clang/test/CodeGen/attr-counted-by.c | 87 +++++++++++++--------------- 1 file changed, 40 insertions(+), 47 deletions(-) diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c index cdfc929c97069..4fa149d19a823 100644 --- a/clang/test/CodeGen/attr-counted-by.c +++ b/clang/test/CodeGen/attr-counted-by.c @@ -67,7 +67,7 @@ struct anon_struct { // 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]]) #[[ATTR3:[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]] @@ -111,7 +111,7 @@ 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]]) #[[ATTR3]], !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]] @@ -156,16 +156,14 @@ 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]]) #[[ATTR3]], !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: [[TMP4:%.*]] = zext i32 [[TMP3]] to i64 -// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP4]], i64 4) -// SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = trunc i64 [[TMP5]] to i32 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i32 [[TMP6]], 12 -// SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// 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: store i32 [[NARROW]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // SANITIZE-WITH-ATTR-NEXT: ret void // // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test3( @@ -174,12 +172,10 @@ void test2(struct annotated *p, size_t index) { // 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:%.*]] = zext i32 [[TMP1]] to i64 -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP2]], i64 4) -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = trunc i64 [[TMP3]] to i32 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i32 [[TMP4]], 12 +// 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: [[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: store i32 [[NARROW]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // NO-SANITIZE-WITH-ATTR-NEXT: ret void // // SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test3( @@ -213,7 +209,7 @@ void test3(struct annotated *p, size_t index) { // 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]]) #[[ATTR3]], !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 @@ -229,7 +225,7 @@ void test3(struct annotated *p, size_t index) { // SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP9]], label [[CONT34:%.*]], label [[HANDLER_OUT_OF_BOUNDS29:%.*]], !prof [[PROF7]], !nosanitize !6 // SANITIZE-WITH-ATTR: handler.out_of_bounds29: // SANITIZE-WITH-ATTR-NEXT: [[TMP10:%.*]] = 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 [[TMP10]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB7:[0-9]+]], i64 [[TMP10]]) #[[ATTR4]], !nosanitize !6 // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 // SANITIZE-WITH-ATTR: cont34: // SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX32:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[TMP7]] @@ -300,7 +296,7 @@ void test4(struct annotated *p, int index) { // 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 @[[GLOB8:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB8:[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 @@ -357,7 +353,7 @@ void test5(struct anon_struct *p, int index) { // 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 @[[GLOB9:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !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: cont12: // SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds [[STRUCT_ANON_STRUCT]], ptr [[P]], i64 1 @@ -412,16 +408,15 @@ void test6(struct anon_struct *p, int 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 @[[GLOB11:[0-9]+]], i64 [[TMP4]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB11:[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:%.*]] = zext i32 [[TMP1]] to i64 -// SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP6]], i64 12) -// SANITIZE-WITH-ATTR-NEXT: [[TMP8:%.*]] = trunc i64 [[TMP7]] to i8 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP8]], 4 +// SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP1]], i32 12) +// SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = trunc i32 [[TMP6]] to i8 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP7]], 4 // SANITIZE-WITH-ATTR-NEXT: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA10:![0-9]+]] // SANITIZE-WITH-ATTR-NEXT: ret void // @@ -430,10 +425,9 @@ void test6(struct anon_struct *p, int index) { // 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:%.*]] = zext i32 [[TMP1]] to i64 -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP2]], i64 12) -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = trunc i64 [[TMP3]] to i8 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP4]], 4 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP1]], i32 12) +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = trunc i32 [[TMP2]] to i8 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP3]], 4 // 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]] @@ -467,17 +461,17 @@ void test7(struct union_of_fams *p, int index) { // 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: [[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 [[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 @[[GLOB12:[0-9]+]], i64 [[TMP5]]) #[[ATTR3]], !nosanitize !6 +// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB12:[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: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[TMP2]] // SANITIZE-WITH-ATTR-NEXT: store i8 [[TMP1]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA10]] // SANITIZE-WITH-ATTR-NEXT: ret void // @@ -519,19 +513,19 @@ void test8(struct union_of_fams *p, int index) { // 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:%.*]] = zext i32 [[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: [[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 @[[GLOB13:[0-9]+]], i64 [[TMP5]]) #[[ATTR3]], !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: [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12 -// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[TMP3]] -// SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP2]], i64 12) -// SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = trunc i64 [[TMP6]] to i8 +// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[TMP2]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP1]], i32 12) +// SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = trunc i32 [[TMP6]] to i8 // SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP7]], 4 // SANITIZE-WITH-ATTR-NEXT: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA10]] // SANITIZE-WITH-ATTR-NEXT: ret void @@ -541,10 +535,9 @@ void test8(struct union_of_fams *p, int index) { // 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:%.*]] = zext i32 [[TMP1]] to i64 -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP2]], i64 12) -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = trunc i64 [[TMP3]] to i8 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP4]], 4 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP1]], i32 12) +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = trunc i32 [[TMP2]] to i8 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP3]], 4 // 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]] @@ -578,17 +571,17 @@ void test9(struct union_of_fams *p, int index) { // 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:%.*]] = zext i32 [[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: [[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]]) #[[ATTR3]], !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 [[TMP3]] +// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[TMP2]] // SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = trunc i32 [[TMP1]] to i8 // SANITIZE-WITH-ATTR-NEXT: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA10]] // SANITIZE-WITH-ATTR-NEXT: ret void From c15f340e96465aa3f3756ffef7b13b23ecb213b1 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 8 Nov 2023 15:38:55 -0800 Subject: [PATCH 17/19] Pass the signedness throughout the IR construction. --- clang/lib/CodeGen/CGBuiltin.cpp | 49 ++++++++++++++++++++-------- clang/test/CodeGen/attr-counted-by.c | 24 +++++++------- 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 5b04a6aab63ae..ad9f4af183a5c 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -902,6 +902,7 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, } if (const ValueDecl *CountedByFD = FindCountedByField(Base)) { + bool IsSigned = CountedByFD->getType()->isSignedIntegerType(); const RecordDecl *OuterRD = CountedByFD->getDeclContext()->getOuterLexicalRecordContext(); ASTContext &Ctx = getContext(); @@ -912,38 +913,58 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, EmitAnyExprToTemp(CountedByExpr).getScalarVal(); if (Idx) { + // There's an index into the array. Remove it from the count. llvm::Value *IdxInst = EmitAnyExprToTemp(Idx).getScalarVal(); - IdxInst = Builder.CreateSExtOrTrunc(IdxInst, CountedByInst->getType()); - CountedByInst = Builder.CreateSub(CountedByInst, IdxInst); + + if (Idx->getType()->isSignedIntegerType()) + IdxInst = + Builder.CreateSExtOrTrunc(IdxInst, CountedByInst->getType()); + else + IdxInst = + Builder.CreateZExtOrTrunc(IdxInst, CountedByInst->getType()); + + CountedByInst = + Builder.CreateSub(CountedByInst, IdxInst, "", !IsSigned, IsSigned); } // Get the size of the flexible array member's base type. const ValueDecl *FAM = FindFlexibleArrayMemberField(Ctx, OuterRD); + assert(FAM && "Can't find the flexible array member field"); + const ArrayType *ArrayTy = Ctx.getAsArrayType(FAM->getType()); CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType()); - llvm::Constant *ElemSize = - llvm::ConstantInt::get(CountedByInst->getType(), Size.getQuantity()); + llvm::Constant *ElemSize = llvm::ConstantInt::get( + CountedByInst->getType(), Size.getQuantity(), IsSigned); - llvm::Value *FAMSize = Builder.CreateMul(CountedByInst, ElemSize); - llvm::Value *Res = Builder.CreateSExtOrTrunc(FAMSize, ResType); + llvm::Value *FAMSize = + Builder.CreateMul(CountedByInst, ElemSize, "", !IsSigned, IsSigned); + llvm::Value *Res = IsSigned ? Builder.CreateSExtOrTrunc(FAMSize, ResType) + : Builder.CreateZExtOrTrunc(FAMSize, ResType); if (const auto *DRE = dyn_cast(Base)) { // The whole struct is specificed in the __bdos. - // Get the full size of the struct. const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD); - llvm::Value *SizeofStruct = - ConstantInt::get(ResType, Layout.getSize().getQuantity(), true); // Get the offset of the FAM. CharUnits Offset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAM)); - llvm::Value *FAMOffset = - ConstantInt::get(ResType, Offset.getQuantity(), true); + llvm::Constant *FAMOffset = + ConstantInt::get(ResType, Offset.getQuantity(), IsSigned); // max(sizeof(struct s), // offsetof(struct s, array) + p->count * sizeof(*p->array)) - llvm::Value *OffsetAndFAMSize = Builder.CreateAdd(FAMOffset, Res); - Res = Builder.CreateBinaryIntrinsic(llvm::Intrinsic::smax, - OffsetAndFAMSize, SizeofStruct); + llvm::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); + + if (IsSigned) + Res = Builder.CreateBinaryIntrinsic(llvm::Intrinsic::smax, + OffsetAndFAMSize, SizeofStruct); + else + Res = Builder.CreateBinaryIntrinsic(llvm::Intrinsic::umax, + OffsetAndFAMSize, SizeofStruct); } // PULL THE STRING!! diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c index 4fa149d19a823..a4f7f2bd12824 100644 --- a/clang/test/CodeGen/attr-counted-by.c +++ b/clang/test/CodeGen/attr-counted-by.c @@ -115,7 +115,7 @@ void test1(struct annotated *p, int index, int val) { // 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: [[TMP3:%.*]] = shl nsw i32 [[TMP0]], 2 // SANITIZE-WITH-ATTR-NEXT: store i32 [[TMP3]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] // SANITIZE-WITH-ATTR-NEXT: ret void // @@ -124,7 +124,7 @@ 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: [[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: ret void @@ -160,7 +160,7 @@ void test2(struct annotated *p, size_t index) { // 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: [[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: store i32 [[NARROW]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] @@ -171,7 +171,7 @@ void test2(struct annotated *p, size_t index) { // 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: [[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: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[INDEX]] @@ -301,8 +301,8 @@ void test4(struct annotated *p, int index) { // 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 i64 [[TMP0]], 2 -// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP4]], i64 16) +// 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: [[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 @@ -312,8 +312,8 @@ void test4(struct annotated *p, int index) { // 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:![0-9]+]] -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl i64 [[TMP0]], 2 -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP1]], i64 16) +// 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: [[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 @@ -461,9 +461,9 @@ void test7(struct union_of_fams *p, int index) { // 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:%.*]] = 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: [[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 @@ -471,7 +471,7 @@ void test7(struct union_of_fams *p, int index) { // 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 [[TMP2]] +// 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 // From e6f52990f088c32e6048c0257551ee974a42df41 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 8 Nov 2023 21:33:21 -0800 Subject: [PATCH 18/19] Start at the outer-most lexical RecordDecl instead of assuming the FAM was passed in here. --- clang/lib/CodeGen/CGExpr.cpp | 33 +++++++++++------------- clang/test/CodeGen/attr-counted-by.c | 38 +++++++++++++++------------- 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 2594ae430fb12..6f641d929e83a 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1016,42 +1016,39 @@ CodeGenFunction::FindFlexibleArrayMemberField(ASTContext &Ctx, } const ValueDecl *CodeGenFunction::FindCountedByField(const Expr *Base) { - const ValueDecl *VD = nullptr; + const RecordDecl *OuterRD = nullptr; Base = Base->IgnoreParenImpCasts(); - if (const auto *ME = dyn_cast(Base)) { - VD = dyn_cast(ME->getMemberDecl()); - } else if (const auto *DRE = dyn_cast(Base)) { - // Pointing to the full structure. - VD = dyn_cast(DRE->getDecl()); + // Get the outer-most lexical RecordDecl. + if (const auto *DRE = dyn_cast(Base)) { + QualType Ty = DRE->getDecl()->getType(); - QualType Ty = VD->getType(); if (Ty->isPointerType()) Ty = Ty->getPointeeType(); if (const auto *RD = Ty->getAsRecordDecl()) - VD = FindFlexibleArrayMemberField(getContext(), RD); - } else if (const auto *CE = dyn_cast(Base)) { - if (const auto *ME = dyn_cast(CE->getSubExpr())) - VD = dyn_cast(ME->getMemberDecl()); + OuterRD = RD->getOuterLexicalRecordContext(); + } else { + if (const auto *ME = dyn_cast(Base)) + if (const ValueDecl *VD = ME->getMemberDecl()) + OuterRD = VD->getDeclContext()->getOuterLexicalRecordContext(); } - LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = - getLangOpts().getStrictFlexArraysLevel(); + if (!OuterRD) + return nullptr; + + const ValueDecl *VD = FindFlexibleArrayMemberField(getContext(), OuterRD); const auto *FD = dyn_cast_if_present(VD); - if (!FD || !FD->getParent() || - !Decl::isFlexibleArrayMemberLike(getContext(), FD, FD->getType(), - StrictFlexArraysLevel, true)) + if (!FD) return nullptr; const auto *CBA = FD->getAttr(); if (!CBA) return nullptr; - const RecordDecl *RD = FD->getDeclContext()->getOuterLexicalRecordContext(); DeclarationName DName(CBA->getCountedByField()); - DeclContext::lookup_result Lookup = RD->lookup(DName); + DeclContext::lookup_result Lookup = OuterRD->lookup(DName); if (Lookup.empty()) return nullptr; diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c index a4f7f2bd12824..43c874032bcdc 100644 --- a/clang/test/CodeGen/attr-counted-by.c +++ b/clang/test/CodeGen/attr-counted-by.c @@ -402,22 +402,22 @@ void test6(struct anon_struct *p, int index) { // 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-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 8, !tbaa [[TBAA10:![0-9]+]] +// 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: [[TMP4:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize !6 -// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB11:[0-9]+]], i64 [[TMP4]]) #[[ATTR4]], !nosanitize !6 +// 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 @[[GLOB11:[0-9]+]], i64 [[TMP5]]) #[[ATTR4]], !nosanitize !6 // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 -// SANITIZE-WITH-ATTR: cont23: +// SANITIZE-WITH-ATTR: cont24: // 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: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[TMP2]] // SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP1]], i32 12) // SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = trunc i32 [[TMP6]] to i8 // SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP7]], 4 -// SANITIZE-WITH-ATTR-NEXT: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA10:![0-9]+]] +// 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 @test7( @@ -460,10 +460,10 @@ void test7(struct union_of_fams *p, int index) { // 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: [[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 @@ -471,19 +471,21 @@ void test7(struct union_of_fams *p, int index) { // 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: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[TMP2]] +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = trunc i32 [[TMP1]] 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 @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: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 8, !tbaa [[TBAA8]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = trunc i32 [[TMP1]] to i8 // 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: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA8]] // NO-SANITIZE-WITH-ATTR-NEXT: ret void // // SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test8( From ff321b076437446470319ff43b27bb3485d367b4 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 8 Nov 2023 23:31:22 -0800 Subject: [PATCH 19/19] If the count is negative, we've gone past the end of the FAM. Return 0. --- clang/lib/CodeGen/CGBuiltin.cpp | 102 +++++++---- clang/lib/CodeGen/CGExpr.cpp | 31 ++-- clang/test/CodeGen/attr-counted-by.c | 255 +++++++++++++++++++-------- 3 files changed, 269 insertions(+), 119 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index ad9f4af183a5c..da09456960ab0 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -859,6 +859,12 @@ 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) { // 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 @@ -909,75 +915,99 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, // Load the counted_by field. const Expr *CountedByExpr = BuildCountedByFieldExpr(Base, CountedByFD); - llvm::Value *CountedByInst = - EmitAnyExprToTemp(CountedByExpr).getScalarVal(); + Value *CountedByInst = EmitAnyExprToTemp(CountedByExpr).getScalarVal(); + llvm::Type *CountedByTy = CountedByInst->getType(); if (Idx) { // There's an index into the array. Remove it from the count. - llvm::Value *IdxInst = EmitAnyExprToTemp(Idx).getScalarVal(); - - if (Idx->getType()->isSignedIntegerType()) - IdxInst = - Builder.CreateSExtOrTrunc(IdxInst, CountedByInst->getType()); - else - IdxInst = - Builder.CreateZExtOrTrunc(IdxInst, CountedByInst->getType()); - + 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.CreateSub(CountedByInst, IdxInst, "", !IsSigned, IsSigned); + Builder.CreateAdd(CountedByInst, IdxInst, "", !IsSigned, IsSigned); } // Get the size of the flexible array member's base type. - const ValueDecl *FAM = FindFlexibleArrayMemberField(Ctx, OuterRD); - assert(FAM && "Can't find the flexible array member field"); + const ValueDecl *FAMDecl = nullptr; + if (const auto *ME = dyn_cast(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; + } - const ArrayType *ArrayTy = Ctx.getAsArrayType(FAM->getType()); + 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( - CountedByInst->getType(), Size.getQuantity(), IsSigned); + llvm::Constant *ElemSize = + llvm::ConstantInt::get(CountedByTy, Size.getQuantity(), IsSigned); - llvm::Value *FAMSize = + // Calculate how large the flexible array member is in bytes. + Value *FAMSize = Builder.CreateMul(CountedByInst, ElemSize, "", !IsSigned, IsSigned); - llvm::Value *Res = IsSigned ? Builder.CreateSExtOrTrunc(FAMSize, ResType) - : Builder.CreateZExtOrTrunc(FAMSize, ResType); + FAMSize = IsSigned ? Builder.CreateSExtOrTrunc(FAMSize, ResType) + : Builder.CreateZExtOrTrunc(FAMSize, ResType); + Value *Res = FAMSize; if (const auto *DRE = dyn_cast(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(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)) - llvm::Value *OffsetAndFAMSize = + 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); - if (IsSigned) - Res = Builder.CreateBinaryIntrinsic(llvm::Intrinsic::smax, - OffsetAndFAMSize, SizeofStruct); - else - Res = Builder.CreateBinaryIntrinsic(llvm::Intrinsic::umax, - OffsetAndFAMSize, SizeofStruct); + Res = IsSigned + ? Builder.CreateBinaryIntrinsic( + llvm::Intrinsic::smax, OffsetAndFAMSize, SizeofStruct) + : Builder.CreateBinaryIntrinsic( + llvm::Intrinsic::umax, OffsetAndFAMSize, SizeofStruct); + } else if (const auto *ME = dyn_cast(Base)) { + // Pointing to a place before the FAM. Add the difference 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())); + } } - // PULL THE STRING!! - return Res; + // 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 6f641d929e83a..a75f630e1a4c7 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -997,7 +997,7 @@ CodeGenFunction::BuildCountedByFieldExpr(const Expr *Base, const ValueDecl * CodeGenFunction::FindFlexibleArrayMemberField(ASTContext &Ctx, const RecordDecl *RD) { - LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = + const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = getLangOpts().getStrictFlexArraysLevel(); for (const Decl *D : RD->decls()) { @@ -1016,32 +1016,43 @@ CodeGenFunction::FindFlexibleArrayMemberField(ASTContext &Ctx, } const ValueDecl *CodeGenFunction::FindCountedByField(const Expr *Base) { + ASTContext &Ctx = getContext(); const RecordDecl *OuterRD = nullptr; + const FieldDecl *FD = nullptr; Base = Base->IgnoreParenImpCasts(); // Get the outer-most lexical RecordDecl. if (const auto *DRE = dyn_cast(Base)) { QualType Ty = DRE->getDecl()->getType(); - if (Ty->isPointerType()) Ty = Ty->getPointeeType(); if (const auto *RD = Ty->getAsRecordDecl()) OuterRD = RD->getOuterLexicalRecordContext(); - } else { - if (const auto *ME = dyn_cast(Base)) - if (const ValueDecl *VD = ME->getMemberDecl()) - OuterRD = VD->getDeclContext()->getOuterLexicalRecordContext(); + } else if (const auto *ME = dyn_cast(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(MD); + } } if (!OuterRD) return nullptr; - const ValueDecl *VD = FindFlexibleArrayMemberField(getContext(), OuterRD); - const auto *FD = dyn_cast_if_present(VD); - if (!FD) - return nullptr; + if (!FD) { + const ValueDecl *VD = FindFlexibleArrayMemberField(Ctx, OuterRD); + FD = dyn_cast_if_present(VD); + if (!FD) + return nullptr; + } const auto *CBA = FD->getAttr(); if (!CBA) diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c index 43c874032bcdc..3d3ce572ba62c 100644 --- a/clang/test/CodeGen/attr-counted-by.c +++ b/clang/test/CodeGen/attr-counted-by.c @@ -115,8 +115,10 @@ void test1(struct annotated *p, int index, int val) { // 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: [[DOTINV:%.*]] = icmp sgt i32 [[TMP0]], -1 // SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = shl nsw i32 [[TMP0]], 2 -// SANITIZE-WITH-ATTR-NEXT: store i32 [[TMP3]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// 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( @@ -125,8 +127,10 @@ void test1(struct annotated *p, int index, int val) { // 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 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( @@ -163,7 +167,9 @@ void test2(struct annotated *p, size_t index) { // 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: store i32 [[NARROW]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// 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( @@ -174,8 +180,10 @@ void test2(struct annotated *p, size_t index) { // 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 [[NARROW]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// 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 @test3( @@ -199,7 +207,7 @@ void test3(struct annotated *p, size_t index) { } // SANITIZE-WITH-ATTR-LABEL: define dso_local void @test4( -// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// 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]] @@ -213,51 +221,83 @@ void test3(struct annotated *p, size_t index) { // SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize !6 // SANITIZE-WITH-ATTR: cont13: // SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = shl i32 [[TMP0]], 2 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i32 [[TMP5]], 244 -// SANITIZE-WITH-ATTR-NEXT: [[CONV3:%.*]] = and i32 [[CONV]], 252 +// 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: [[TMP6:%.*]] = load i32, ptr [[COUNT]], align 8, !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: [[TMP7:%.*]] = sext i32 [[ADD]] to i64, !nosanitize !6 -// SANITIZE-WITH-ATTR-NEXT: [[TMP8:%.*]] = zext i32 [[TMP6]] to i64, !nosanitize !6 -// SANITIZE-WITH-ATTR-NEXT: [[TMP9:%.*]] = icmp ult i64 [[TMP7]], [[TMP8]], !nosanitize !6 -// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP9]], label [[CONT34:%.*]], label [[HANDLER_OUT_OF_BOUNDS29:%.*]], !prof [[PROF7]], !nosanitize !6 +// 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: [[TMP10:%.*]] = 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 [[TMP10]]) #[[ATTR4]], !nosanitize !6 +// 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: [[ARRAYIDX32:%.*]] = getelementptr inbounds [[STRUCT_ANNOTATED]], ptr [[P]], i64 0, i32 2, i64 [[TMP7]] -// SANITIZE-WITH-ATTR-NEXT: [[TMP11:%.*]] = shl i32 [[TMP6]], 2 -// SANITIZE-WITH-ATTR-NEXT: [[CONV19:%.*]] = add i32 [[TMP11]], 240 -// SANITIZE-WITH-ATTR-NEXT: [[CONV20:%.*]] = and i32 [[CONV19]], 252 +// 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:%.*]]) local_unnamed_addr #[[ATTR1]] { +// 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: [[CONV:%.*]] = add i32 [[TMP1]], 244 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV1:%.*]] = and i32 [[CONV]], 252 +// 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: [[TMP2:%.*]] = load i32, ptr [[COUNT]], align 8, !tbaa [[TBAA2]] -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = shl i32 [[TMP2]], 2 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV3:%.*]] = add i32 [[TMP3]], 240 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV4:%.*]] = and i32 [[CONV3]], 252 +// 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:%.*]]) local_unnamed_addr #[[ATTR0]] { +// 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]] @@ -266,10 +306,14 @@ void test3(struct annotated *p, size_t index) { // 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:%.*]]) local_unnamed_addr #[[ATTR1]] { +// 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]] @@ -278,12 +322,17 @@ void test3(struct annotated *p, size_t index) { // 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) { +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( @@ -296,14 +345,16 @@ void test4(struct annotated *p, int index) { // 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 @[[GLOB8:[0-9]+]], i64 [[TMP3]]) #[[ATTR4]], !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: 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: [[CONV:%.*]] = trunc i64 [[TMP5]] to i32 +// 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 // @@ -314,7 +365,9 @@ void test4(struct annotated *p, int index) { // 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: [[CONV:%.*]] = trunc i64 [[TMP2]] to i32 +// 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]] @@ -353,23 +406,25 @@ void test5(struct anon_struct *p, int index) { // 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 @[[GLOB9:[0-9]+]], i64 [[TMP3]]) #[[ATTR4]], !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: [[DOTTR:%.*]] = trunc i64 [[TMP0]] to i32 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[DOTTR]], 2 +// 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 #[[ATTR1]] { +// 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: [[DOTTR:%.*]] = trunc i64 [[TMP0]] to i32 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[DOTTR]], 2 +// 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]] @@ -402,22 +457,24 @@ void test6(struct anon_struct *p, int index) { // 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:![0-9]+]] -// 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-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: [[TMP5:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize !6 -// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB11:[0-9]+]], i64 [[TMP5]]) #[[ATTR4]], !nosanitize !6 +// 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: cont24: +// SANITIZE-WITH-ATTR: cont23: // 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 [[TMP2]] -// SANITIZE-WITH-ATTR-NEXT: [[TMP6:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP1]], i32 12) -// SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = trunc i32 [[TMP6]] to i8 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP7]], 4 -// SANITIZE-WITH-ATTR-NEXT: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA10]] +// 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( @@ -426,8 +483,10 @@ void test6(struct anon_struct *p, int index) { // 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:%.*]] = trunc i32 [[TMP2]] to i8 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP3]], 4 +// 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]] @@ -460,32 +519,30 @@ void test7(struct union_of_fams *p, int index) { // 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: [[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 @[[GLOB12:[0-9]+]], i64 [[TMP5]]) #[[ATTR4]], !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 [[TMP2]] -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = trunc i32 [[TMP1]] to i8 -// SANITIZE-WITH-ATTR-NEXT: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA10]] +// 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 i32, ptr [[TMP0]], align 8, !tbaa [[TBAA8]] -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = trunc i32 [[TMP1]] to i8 +// 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 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA8]] +// 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( @@ -521,14 +578,16 @@ void test8(struct union_of_fams *p, int index) { // 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: 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:%.*]] = tail call i32 @llvm.smax.i32(i32 [[TMP1]], i32 12) -// SANITIZE-WITH-ATTR-NEXT: [[TMP7:%.*]] = trunc i32 [[TMP6]] to i8 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP7]], 4 +// 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 // @@ -538,8 +597,10 @@ void test8(struct union_of_fams *p, int index) { // 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:%.*]] = trunc i32 [[TMP2]] to i8 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = add i8 [[TMP3]], 4 +// 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]] @@ -579,21 +640,23 @@ void test9(struct union_of_fams *p, int index) { // 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: 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: [[CONV:%.*]] = trunc i32 [[TMP1]] to i8 +// 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 #[[ATTR1]] { +// 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: [[CONV:%.*]] = trunc i32 [[TMP1]] to i8 +// 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]] @@ -621,3 +684,49 @@ void test9(struct union_of_fams *p, int index) { 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); +}