https://github.com/bwendling updated https://github.com/llvm/llvm-project/pull/70606
>From 19dd7db8ab5f98a618c717944c96b34e604fbc30 Mon Sep 17 00:00:00 2001 From: Bill Wendling <mo...@google.com> Date: Sun, 29 Oct 2023 14:58:04 -0700 Subject: [PATCH 01/11] [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 dce5ee5888c458e..acee2c1af1ab368 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<MemberExpr>(Base); - llvm::Value *ObjectSize = nullptr; - - if (!ME) { - const auto *DRE = dyn_cast<DeclRefExpr>(Base); - ValueDecl *VD = nullptr; - - ObjectSize = ConstantInt::get( - ResType, - getContext().getTypeSize(DRE->getType()->getPointeeType()) / 8, - true); - - if (auto *RD = DRE->getType()->getPointeeType()->getAsRecordDecl()) - VD = RD->getLastField(); - - Expr *ICE = ImplicitCastExpr::Create( - getContext(), DRE->getType(), CK_LValueToRValue, - const_cast<Expr *>(cast<Expr>(DRE)), nullptr, VK_PRValue, - FPOptionsOverride()); - ME = MemberExpr::CreateImplicit(getContext(), ICE, true, VD, - VD->getType(), VK_LValue, OK_Ordinary); - } - - // 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<Expr *>(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<Expr *>(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<DeclRefExpr>(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 54a1d300a9ac738..2b39194e18ed861 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<MemberExpr>(CE->getSubExpr()); + if (const ValueDecl *VD = CGF.FindCountedByField(Base)) { IndexedType = Base->getType(); - return CGF - .EmitAnyExprToTemp(MemberExpr::CreateImplicit( - CGF.getContext(), const_cast<Expr *>(ME->getBase()), - ME->isArrow(), FD, FD->getType(), VK_LValue, OK_Ordinary)) - .getScalarVal(); + Expr *E = CGF.BuildCountedByFieldExpr(const_cast<Expr *>(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<DeclRefExpr>(Base)) + if (auto *ME = dyn_cast<MemberExpr>(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<IndirectFieldDecl>(CountedByVD)) { + // The counted_by field is inside an anonymous struct / union. The + // IndirectFieldDecl has the correct order of FieldDecls to build this + // easily. (Yay!) + for (NamedDecl *ND : IFD->chain()) { + ValueDecl *VD = cast<ValueDecl>(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<ValueDecl *>(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<ValueDecl>(D); + VD && Decl::isFlexibleArrayMemberLike(Ctx, VD, VD->getType(), + StrictFlexArraysLevel, true)) + return VD; + + if (const auto *Record = dyn_cast<RecordDecl>(D)) + if (const ValueDecl *VD = FindFlexibleArrayMemberField(Ctx, Record)) + return VD; + } + + return nullptr; +} + +const ValueDecl *CodeGenFunction::FindCountedByField(const Expr *Base) { 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<CastExpr>(Base)) { if (const auto *ME = dyn_cast<MemberExpr>(CE->getSubExpr())) VD = dyn_cast<ValueDecl>(ME->getMemberDecl()); } + LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = + getLangOpts().getStrictFlexArraysLevel(); const auto *FD = dyn_cast_if_present<FieldDecl>(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<ValueDecl>(Lookup.front()); } void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base, diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index e82115e2d706cf1..64f192037ec8ce5 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 <mo...@google.com> Date: Sun, 29 Oct 2023 15:22:29 -0700 Subject: [PATCH 02/11] 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 acee2c1af1ab368..26c73d07c7038e5 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<Expr *>(E), - CountedByFD); + Expr *CountedByExpr = + BuildCountedByFieldExpr(const_cast<Expr *>(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 2b39194e18ed861..b39cd8b45fe8f6a 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<ValueDecl>(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<ValueDecl *>(CountedByVD), CountedByVD->getType(), - VK_LValue, OK_Ordinary); + getContext(), CountedByExpr, CountedByExpr->getType()->isPointerType(), + const_cast<ValueDecl *>(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 <mo...@google.com> Date: Mon, 30 Oct 2023 13:30:31 -0700 Subject: [PATCH 03/11] 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 a7eb0da6dd282a7..1440ec819f6b1ee 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 <mo...@google.com> Date: Mon, 30 Oct 2023 13:58:12 -0700 Subject: [PATCH 04/11] 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 26c73d07c7038e5..c4c31019c031f4e 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<Expr *>(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<DeclRefExpr>(E->IgnoreImpCasts())) { + if (const auto *DRE = dyn_cast<DeclRefExpr>(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 <mo...@google.com> Date: Mon, 30 Oct 2023 14:58:57 -0700 Subject: [PATCH 05/11] 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 b39cd8b45fe8f6a..a9bf2d5a8bf389d 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<DeclRefExpr>(Base)) - if (auto *ME = dyn_cast<MemberExpr>(Base->IgnoreImpCasts())) { - Base = ME->getBase()->IgnoreImpCasts(); - Base = Base->IgnoreParenNoopCasts(getContext()); - } + if (auto *ME = dyn_cast<MemberExpr>(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<IndirectFieldDecl>(CountedByVD)) { // The counted_by field is inside an anonymous struct / union. The // IndirectFieldDecl has the correct order of FieldDecls to build this // easily. (Yay!) for (NamedDecl *ND : IFD->chain()) { - ValueDecl *VD = cast<ValueDecl>(ND); - CountedByExpr = - MemberExpr::CreateImplicit(getContext(), CountedByExpr, - CountedByExpr->getType()->isPointerType(), - VD, VD->getType(), VK_LValue, OK_Ordinary); + auto *VD = cast<ValueDecl>(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<ValueDecl *>(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<ValueDecl>(D); + if (const auto *VD = dyn_cast<ValueDecl>(D); VD && Decl::isFlexibleArrayMemberLike(Ctx, VD, VD->getType(), StrictFlexArraysLevel, true)) return VD; >From e70b48752f0228c5412503b1bef6d6946b686b62 Mon Sep 17 00:00:00 2001 From: Bill Wendling <mo...@google.com> Date: Mon, 30 Oct 2023 15:29:58 -0700 Subject: [PATCH 06/11] 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 c4c31019c031f4e..ebd270be8b42828 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<Expr *>(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 a9bf2d5a8bf389d..4861179412102c1 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<Expr *>(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<Expr *>(Base)->IgnoreParenImpCasts(); // Work our way up the expression until we reach the DeclRefExpr. - while (!isa<DeclRefExpr>(Base)) - if (auto *ME = dyn_cast<MemberExpr>(Base)) - Base = ME->getBase()->IgnoreParenImpCasts(); + while (!isa<DeclRefExpr>(CountedByExpr)) + if (const auto *ME = dyn_cast<MemberExpr>(CountedByExpr)) + CountedByExpr = ME->getBase()->IgnoreParenImpCasts(); // Add back an implicit cast to create the required pr-value. - 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<IndirectFieldDecl>(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<ValueDecl>(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<Expr *>(CountedByExpr), + CountedByExpr->getType()->isPointerType(), const_cast<ValueDecl *>(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 64f192037ec8ce5..af0faf10a62a581 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 <mo...@google.com> Date: Tue, 31 Oct 2023 13:15:21 -0700 Subject: [PATCH 07/11] 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 ebd270be8b42828..5d6e9f5efe9529b 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 <mo...@google.com> Date: Tue, 31 Oct 2023 14:54:20 -0700 Subject: [PATCH 08/11] 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 5d6e9f5efe9529b..f966d4563b4d182 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 <mo...@google.com> Date: Tue, 31 Oct 2023 14:54:45 -0700 Subject: [PATCH 09/11] 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 f966d4563b4d182..11d152d61259004 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 <mo...@google.com> Date: Tue, 31 Oct 2023 16:54:54 -0700 Subject: [PATCH 10/11] 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 11d152d61259004..177da15f5e998bd 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<DeclRefExpr>(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 <mo...@google.com> Date: Tue, 31 Oct 2023 17:26:37 -0700 Subject: [PATCH 11/11] 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 1440ec819f6b1ee..595224303773b80 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]] _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits