[clang-tools-extra] [llvm] [clang] [CodeGen] Revamp counted_by calculations (PR #70606)
Bill Wendling via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 9 01:53:46 PST 2023
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 <morbo at google.com>
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 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 <morbo at google.com>
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 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 <morbo at google.com>
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 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 <morbo at google.com>
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 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 <morbo at google.com>
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 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 <morbo at google.com>
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 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 <morbo at google.com>
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 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 <morbo at google.com>
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 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 <morbo at google.com>
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 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 <morbo at google.com>
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 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 <morbo at google.com>
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 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]]
>From 7a20a343500cacab26c5b0ae62f04fd6d6e59cd9 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
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 177da15f5e998bd..a81b2c266d97ff3 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<DeclRefExpr>(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 595224303773b80..5c5a16f4ca32e3b 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 <morbo at google.com>
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 a81b2c266d97ff3..3bfaea7849ce39d 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<DeclRefExpr>(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 <morbo at google.com>
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 3bfaea7849ce39d..db54d629cf4f902 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<UnaryOperator>(Base);
+ UO && UO->getOpcode() == UO_AddrOf) {
+ if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->getSubExpr())) {
+ Base = ASE->getBase();
+ Idx = ASE->getIdx()->IgnoreParenImpCasts();
+ if (const auto *IL = dyn_cast<IntegerLiteral>(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<DeclRefExpr>(E->IgnoreParenImpCasts())) {
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(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 4861179412102c1..80ba8e24e6f803a 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<ValueDecl>(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<RecordDecl>(D))
diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c
index 5c5a16f4ca32e3b..23d854ae991ccff 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 <morbo at google.com>
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 080ee8bb9ec8c6e..5b04a6aab63ae1c 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<UnaryOperator>(Base);
UO && UO->getOpcode() == UO_AddrOf) {
- if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->getSubExpr())) {
+ if (const auto *ASE =
+ dyn_cast<ArraySubscriptExpr>(UO->getSubExpr()->IgnoreParens())) {
Base = ASE->getBase();
Idx = ASE->getIdx()->IgnoreParenImpCasts();
+
if (const auto *IL = dyn_cast<IntegerLiteral>(Idx);
- IL && !IL->getValue().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<DeclRefExpr>(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 23d854ae991ccff..cdfc929c97069ae 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 <morbo at google.com>
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 cdfc929c97069ae..4fa149d19a823db 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 <morbo at google.com>
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 5b04a6aab63ae1c..ad9f4af183a5ccb 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<DeclRefExpr>(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 4fa149d19a823db..a4f7f2bd12824cc 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 <morbo at google.com>
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 2594ae430fb1279..6f641d929e83a54 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<MemberExpr>(Base)) {
- VD = dyn_cast<ValueDecl>(ME->getMemberDecl());
- } else if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
- // Pointing to the full structure.
- VD = dyn_cast<ValueDecl>(DRE->getDecl());
+ // Get the outer-most lexical RecordDecl.
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(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<CastExpr>(Base)) {
- if (const auto *ME = dyn_cast<MemberExpr>(CE->getSubExpr()))
- VD = dyn_cast<ValueDecl>(ME->getMemberDecl());
+ OuterRD = RD->getOuterLexicalRecordContext();
+ } else {
+ if (const auto *ME = dyn_cast<MemberExpr>(Base))
+ if (const ValueDecl *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<FieldDecl>(VD);
- if (!FD || !FD->getParent() ||
- !Decl::isFlexibleArrayMemberLike(getContext(), FD, FD->getType(),
- StrictFlexArraysLevel, true))
+ if (!FD)
return nullptr;
const auto *CBA = FD->getAttr<CountedByAttr>();
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 a4f7f2bd12824cc..43c874032bcdc79 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 <morbo at google.com>
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 ad9f4af183a5ccb..da09456960ab00e 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<MemberExpr>(Base)) {
+ const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
+ getLangOpts().getStrictFlexArraysLevel();
+ if (const ValueDecl *MD = ME->getMemberDecl();
+ MD && Decl::isFlexibleArrayMemberLike(
+ Ctx, MD, MD->getType(), StrictFlexArraysLevel,
+ /*IgnoreTemplateOrMacroSubstitution=*/true))
+ // Base is referencing the FAM itself.
+ FAMDecl = MD;
+ }
- 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<DeclRefExpr>(Base)) {
// The whole struct is specificed in the __bdos.
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD);
// Get the offset of the FAM.
- CharUnits Offset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(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<MemberExpr>(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 6f641d929e83a54..a75f630e1a4c767 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<DeclRefExpr>(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<MemberExpr>(Base))
- if (const ValueDecl *VD = ME->getMemberDecl())
- OuterRD = VD->getDeclContext()->getOuterLexicalRecordContext();
+ } else if (const auto *ME = dyn_cast<MemberExpr>(Base)) {
+ if (const ValueDecl *MD = ME->getMemberDecl()) {
+ OuterRD = MD->getDeclContext()->getOuterLexicalRecordContext();
+
+ const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
+ getLangOpts().getStrictFlexArraysLevel();
+ if (Decl::isFlexibleArrayMemberLike(
+ Ctx, MD, MD->getType(), StrictFlexArraysLevel,
+ /*IgnoreTemplateOrMacroSubstitution=*/true))
+ // Base is referencing the FAM itself.
+ FD = dyn_cast<FieldDecl>(MD);
+ }
}
if (!OuterRD)
return nullptr;
- const ValueDecl *VD = FindFlexibleArrayMemberField(getContext(), OuterRD);
- const auto *FD = dyn_cast_if_present<FieldDecl>(VD);
- if (!FD)
- return nullptr;
+ if (!FD) {
+ const ValueDecl *VD = FindFlexibleArrayMemberField(Ctx, OuterRD);
+ FD = dyn_cast_if_present<FieldDecl>(VD);
+ if (!FD)
+ return nullptr;
+ }
const auto *CBA = FD->getAttr<CountedByAttr>();
if (!CBA)
diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c
index 43c874032bcdc79..3d3ce572ba62c00 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);
+}
More information about the cfe-commits
mailing list