[clang] [Clang] Add __builtin_counted_by_ref builtin (PR #114495)
Bill Wendling via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 1 15:44:22 PDT 2024
https://github.com/bwendling updated https://github.com/llvm/llvm-project/pull/114495
>From fe49528f47dee6d2167d07da1ac8d4cb80cf5fe0 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Tue, 6 Aug 2024 17:49:01 -0700
Subject: [PATCH 01/59] [Clang] Add __builtin_counted_by_ref builtin
The __builtin_counted_by_ref builtin is used on a flexible array
pointer and returns a pointer to the "counted_by" attribute's COUNT
argument, which is a field in the same non-anonymous struct as the
flexible array member. This is useful for automatically setting the
count field without needing the programmer's intervention. Otherwise
it's possible to get this anti-pattern:
ptr = alloc(<ty>, ..., COUNT);
ptr->FAM[9] = 42; /* <<< Sanitizer will complain */
ptr->count = COUNT;
To prevent this anti-pattern, the user can create an allocator that
automatically performs the assignment:
#define alloc(TY, FAM, COUNT) ({ \
TY __p = alloc(get_size(TY, COUNT)); \
if (__builtin_counted_by_ref(__p->FAM)) \
*__builtin_counted_by_ref(__p->FAM) = COUNT; \
__p; \
})
The builtin's behavior is heavily dependent upon the "counted_by"
attribute existing. It's main utility is during allocation to avoid
the above anti-pattern. If the flexible array member doesn't have that
attribute, the builtin becomes a no-op. Therefore, if the flexible
array member has a "count" field not referenced by "counted_by", it
must be set explicitly after the allocation as this builtin will
return a "nullptr" and the assignment will most likely be elided.
---
clang/include/clang/Basic/Builtins.td | 6 ++++
clang/lib/CodeGen/CGBuiltin.cpp | 22 ++++++++++++
clang/lib/CodeGen/CGExpr.cpp | 29 +++++++++-------
clang/lib/CodeGen/CodeGenFunction.h | 8 +++++
clang/lib/Sema/SemaExpr.cpp | 49 +++++++++++++++++++++++++--
5 files changed, 100 insertions(+), 14 deletions(-)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 9bd67e0cefebc3..81e7e581ecb243 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4914,3 +4914,9 @@ def ArithmeticFence : LangBuiltin<"ALL_LANGUAGES"> {
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
+
+def GetCountedBy : Builtin {
+ let Spellings = ["__builtin_get_counted_by"];
+ let Attributes = [NoThrow];
+ let Prototype = "size_t*(void*)";
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 038057d2164ced..8b1cc9f23a7e90 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3691,6 +3691,28 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(emitBuiltinObjectSize(E->getArg(0), Type, ResType,
/*EmittedE=*/nullptr, IsDynamic));
}
+ case Builtin::BI__builtin_get_counted_by: {
+ llvm::Value *Result = nullptr;
+
+ if (const MemberExpr *ME =
+ dyn_cast<MemberExpr>(E->getArg(0)->IgnoreImpCasts())) {
+ bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
+ getContext(), getLangOpts().getStrictFlexArraysLevel(),
+ /*IgnoreTemplateOrMacroSubstitution=*/false);
+
+ // TODO: Probably have to handle horrible casting crap here.
+
+ // FIXME: Emit a diagnostic?
+ if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
+ ME->getMemberDecl()->getType()->isCountAttributedType()) {
+ const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
+ if (const FieldDecl *CountFD = FindCountedByField(FAMDecl))
+ Result = GetCountedByFieldExprGEP(ME, FAMDecl, CountFD);
+ }
+ }
+
+ return RValue::get(Result);
+ }
case Builtin::BI__builtin_prefetch: {
Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0));
// FIXME: Technically these constants should of type 'int', yes?
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index e90e8da3e9f1ea..3364a00c6e9ff7 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1145,15 +1145,7 @@ static bool getGEPIndicesToField(CodeGenFunction &CGF, const RecordDecl *RD,
return false;
}
-/// This method is typically called in contexts where we can't generate
-/// side-effects, like in __builtin_dynamic_object_size. When finding
-/// expressions, only choose those that have either already been emitted or can
-/// be loaded without side-effects.
-///
-/// - \p FAMDecl: the \p Decl for the flexible array member. It may not be
-/// within the top-level struct.
-/// - \p CountDecl: must be within the same non-anonymous struct as \p FAMDecl.
-llvm::Value *CodeGenFunction::EmitLoadOfCountedByField(
+llvm::Value *CodeGenFunction::GetCountedByFieldExprGEP(
const Expr *Base, const FieldDecl *FAMDecl, const FieldDecl *CountDecl) {
const RecordDecl *RD = CountDecl->getParent()->getOuterLexicalRecordContext();
@@ -1182,12 +1174,25 @@ llvm::Value *CodeGenFunction::EmitLoadOfCountedByField(
return nullptr;
Indices.push_back(Builder.getInt32(0));
- Res = Builder.CreateInBoundsGEP(
+ return Builder.CreateInBoundsGEP(
ConvertType(QualType(RD->getTypeForDecl(), 0)), Res,
RecIndicesTy(llvm::reverse(Indices)), "..counted_by.gep");
+}
- return Builder.CreateAlignedLoad(ConvertType(CountDecl->getType()), Res,
- getIntAlign(), "..counted_by.load");
+/// This method is typically called in contexts where we can't generate
+/// side-effects, like in __builtin_dynamic_object_size. When finding
+/// expressions, only choose those that have either already been emitted or can
+/// be loaded without side-effects.
+///
+/// - \p FAMDecl: the \p Decl for the flexible array member. It may not be
+/// within the top-level struct.
+/// - \p CountDecl: must be within the same non-anonymous struct as \p FAMDecl.
+llvm::Value *CodeGenFunction::EmitLoadOfCountedByField(
+ const Expr *Base, const FieldDecl *FAMDecl, const FieldDecl *CountDecl) {
+ if (llvm::Value *GEP = GetCountedByFieldExprGEP(Base, FAMDecl, CountDecl))
+ return Builder.CreateAlignedLoad(ConvertType(CountDecl->getType()), GEP,
+ getIntAlign(), "..counted_by.load");
+ return nullptr;
}
void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 3ff4458fb32024..a370a2fe5f5775 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3305,6 +3305,14 @@ class CodeGenFunction : public CodeGenTypeCache {
const FieldDecl *FAMDecl,
uint64_t &Offset);
+ /// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns
+ /// \p nullptr if either the attribute or the field doesn't exist.
+ const FieldDecl *FindCountedByField(const FieldDecl *FD);
+
+ llvm::Value *GetCountedByFieldExprGEP(const Expr *Base,
+ const FieldDecl *FAMDecl,
+ const FieldDecl *CountDecl);
+
/// Build an expression accessing the "counted_by" field.
llvm::Value *EmitLoadOfCountedByField(const Expr *Base,
const FieldDecl *FAMDecl,
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 7f3cff1054aeed..4b83978a0d380b 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6462,9 +6462,26 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
currentEvaluationContext().ReferenceToConsteval.erase(DRE);
}
}
+
return Call;
}
+const FieldDecl *FindCountedByField(const FieldDecl *FD) {
+ if (!FD)
+ return nullptr;
+
+ const auto *CAT = FD->getType()->getAs<CountAttributedType>();
+ if (!CAT)
+ return nullptr;
+
+ const auto *CountDRE = cast<DeclRefExpr>(CAT->getCountExpr());
+ const auto *CountDecl = CountDRE->getDecl();
+ if (const auto *IFD = dyn_cast<IndirectFieldDecl>(CountDecl))
+ CountDecl = IFD->getAnonField();
+
+ return dyn_cast<FieldDecl>(CountDecl);
+}
+
ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
MultiExprArg ArgExprs, SourceLocation RParenLoc,
Expr *ExecConfig, bool IsExecConfig,
@@ -6662,8 +6679,36 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy,
VK_PRValue, RParenLoc, CurFPFeatureOverrides());
}
- return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc,
- ExecConfig, IsExecConfig);
+
+ Result = BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc,
+ ExecConfig, IsExecConfig);
+
+ if (FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
+ FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_get_counted_by) {
+ if (const MemberExpr *ME =
+ dyn_cast<MemberExpr>(ArgExprs[0]->IgnoreImpCasts())) {
+ bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
+ Context, getLangOpts().getStrictFlexArraysLevel(),
+ /*IgnoreTemplateOrMacroSubstitution=*/false);
+
+ // TODO: Probably have to handle horrible casting crap here.
+
+ // FIXME: Emit a diagnostic?
+ if (!ME->HasSideEffects(Context) && IsFlexibleArrayMember &&
+ ME->getMemberDecl()->getType()->isCountAttributedType()) {
+ const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
+ if (const FieldDecl *CountFD = FindCountedByField(FAMDecl)) {
+ QualType PtrTy = Context.getPointerType(CountFD->getType());
+ Result = CStyleCastExpr::Create(
+ Context, PtrTy, VK_LValue, CK_BitCast, Result.get(), nullptr,
+ FPOptionsOverride(), Context.CreateTypeSourceInfo(PtrTy),
+ LParenLoc, RParenLoc);
+ }
+ }
+ }
+ }
+
+ return Result;
}
Expr *Sema::BuildBuiltinCallExpr(SourceLocation Loc, Builtin::ID Id,
>From e3583c785f7237667744f752f39846521caaf305 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 7 Aug 2024 10:32:28 -0700
Subject: [PATCH 02/59] If the 'counted_by' attribute doesn't exist, then
return nullptr.
---
clang/lib/CodeGen/CGBuiltin.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 8b1cc9f23a7e90..a6d7516e35fcdb 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3708,6 +3708,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
if (const FieldDecl *CountFD = FindCountedByField(FAMDecl))
Result = GetCountedByFieldExprGEP(ME, FAMDecl, CountFD);
+ } else {
+ E->getType()->dump();
+ ConvertType(E->getType())->dump();
+ Result = llvm::ConstantPointerNull::get(cast<llvm::PointerType>(ConvertType(E->getType())));
}
}
>From 053bfcd519abb766ef8ea05252751d07e480bd04 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 7 Aug 2024 10:36:01 -0700
Subject: [PATCH 03/59] Remove debugging code.
---
clang/lib/CodeGen/CGBuiltin.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index a6d7516e35fcdb..f457ac99ee2957 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3709,8 +3709,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
if (const FieldDecl *CountFD = FindCountedByField(FAMDecl))
Result = GetCountedByFieldExprGEP(ME, FAMDecl, CountFD);
} else {
- E->getType()->dump();
- ConvertType(E->getType())->dump();
Result = llvm::ConstantPointerNull::get(cast<llvm::PointerType>(ConvertType(E->getType())));
}
}
>From 4ce6525c31f077182fc4d205a811c55f090a5748 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 7 Aug 2024 10:38:42 -0700
Subject: [PATCH 04/59] Make returning a nullptr the default.
---
clang/lib/CodeGen/CGBuiltin.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index f457ac99ee2957..6321976c551e5e 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3692,7 +3692,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
/*EmittedE=*/nullptr, IsDynamic));
}
case Builtin::BI__builtin_get_counted_by: {
- llvm::Value *Result = nullptr;
+ llvm::Value *Result =
+ llvm::ConstantPointerNull::get(cast<llvm::PointerType>(ConvertType(E->getType())));
if (const MemberExpr *ME =
dyn_cast<MemberExpr>(E->getArg(0)->IgnoreImpCasts())) {
@@ -3708,8 +3709,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
if (const FieldDecl *CountFD = FindCountedByField(FAMDecl))
Result = GetCountedByFieldExprGEP(ME, FAMDecl, CountFD);
- } else {
- Result = llvm::ConstantPointerNull::get(cast<llvm::PointerType>(ConvertType(E->getType())));
}
}
>From 8017e733cc74c39a2c50fbc9dafb0966ebb59fca Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 7 Aug 2024 10:39:05 -0700
Subject: [PATCH 05/59] clang-format
---
clang/lib/CodeGen/CGBuiltin.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 6321976c551e5e..41dc9d83f62e26 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3692,8 +3692,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
/*EmittedE=*/nullptr, IsDynamic));
}
case Builtin::BI__builtin_get_counted_by: {
- llvm::Value *Result =
- llvm::ConstantPointerNull::get(cast<llvm::PointerType>(ConvertType(E->getType())));
+ llvm::Value *Result = llvm::ConstantPointerNull::get(
+ cast<llvm::PointerType>(ConvertType(E->getType())));
if (const MemberExpr *ME =
dyn_cast<MemberExpr>(E->getArg(0)->IgnoreImpCasts())) {
>From 8808431e646252f11002358a5fc6ff6f1fc29b12 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 7 Aug 2024 13:54:22 -0700
Subject: [PATCH 06/59] Use a visitor to retrieve the MemberExpr. It's
intentionally harsh and ignores pretty much everythings that may 'hide' the
underlying MemberExpr.
---
clang/lib/CodeGen/CGBuiltin.cpp | 47 +++++++++++++++++++++++++++----
clang/lib/Sema/SemaExpr.cpp | 50 +++++++++++++++++++++++++++++----
2 files changed, 87 insertions(+), 10 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 41dc9d83f62e26..929a00a844bbdb 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -30,6 +30,7 @@
#include "clang/AST/OSLog.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/Type.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
@@ -2638,6 +2639,45 @@ static RValue EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
return RValue::get(CGF->Builder.CreateCall(UBF, Args));
}
+namespace {
+
+/// MemberExprVisitor - Find the MemberExpr through all of the casts, array
+/// subscripts, and unary ops. This intentionally avoids all of them because
+/// we're interested only in the MemberExpr to check if it's a flexible array
+/// member.
+class MemberExprVisitor
+ : public ConstStmtVisitor<MemberExprVisitor, const Expr *> {
+public:
+ //===--------------------------------------------------------------------===//
+ // Visitor Methods
+ //===--------------------------------------------------------------------===//
+
+ const Expr *Visit(const Expr *E) {
+ return ConstStmtVisitor<MemberExprVisitor, const Expr *>::Visit(E);
+ }
+ const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+ const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
+
+ const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+ return Visit(E->getBase());
+ }
+ const Expr *VisitCastExpr(const CastExpr *E) {
+ return Visit(E->getSubExpr());
+ }
+ const Expr *VisitParenExpr(const ParenExpr *E) {
+ return Visit(E->getSubExpr());
+ }
+ const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
+ return Visit(E->getSubExpr());
+ }
+ const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) {
+ return Visit(E->getSubExpr());
+ }
+};
+
+} // anonymous namespace
+
RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
const CallExpr *E,
ReturnValueSlot ReturnValue) {
@@ -3695,15 +3735,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
llvm::Value *Result = llvm::ConstantPointerNull::get(
cast<llvm::PointerType>(ConvertType(E->getType())));
- if (const MemberExpr *ME =
- dyn_cast<MemberExpr>(E->getArg(0)->IgnoreImpCasts())) {
+ if (const Expr *Ptr = MemberExprVisitor().Visit(E->getArg(0))) {
+ const MemberExpr *ME = cast<MemberExpr>(Ptr);
bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
getContext(), getLangOpts().getStrictFlexArraysLevel(),
/*IgnoreTemplateOrMacroSubstitution=*/false);
- // TODO: Probably have to handle horrible casting crap here.
-
- // FIXME: Emit a diagnostic?
if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
ME->getMemberDecl()->getType()->isCountAttributedType()) {
const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 4b83978a0d380b..1ec80fa5849a4a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -30,6 +30,7 @@
#include "clang/AST/OperationKinds.h"
#include "clang/AST/ParentMapContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
@@ -6482,6 +6483,45 @@ const FieldDecl *FindCountedByField(const FieldDecl *FD) {
return dyn_cast<FieldDecl>(CountDecl);
}
+namespace {
+
+/// MemberExprVisitor - Find the MemberExpr through all of the casts, array
+/// subscripts, and unary ops. This intentionally avoids all of them because
+/// we're interested only in the MemberExpr to check if it's a flexible array
+/// member.
+class MemberExprVisitor
+ : public ConstStmtVisitor<MemberExprVisitor, const Expr *> {
+public:
+ //===--------------------------------------------------------------------===//
+ // Visitor Methods
+ //===--------------------------------------------------------------------===//
+
+ const Expr *Visit(const Expr *E) {
+ return ConstStmtVisitor<MemberExprVisitor, const Expr *>::Visit(E);
+ }
+ const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+ const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
+
+ const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+ return Visit(E->getBase());
+ }
+ const Expr *VisitCastExpr(const CastExpr *E) {
+ return Visit(E->getSubExpr());
+ }
+ const Expr *VisitParenExpr(const ParenExpr *E) {
+ return Visit(E->getSubExpr());
+ }
+ const Expr *VisitUnaryAddrOf(const UnaryOperator *E) {
+ return Visit(E->getSubExpr());
+ }
+ const Expr *VisitUnaryDeref(const UnaryOperator *E) {
+ return Visit(E->getSubExpr());
+ }
+};
+
+} // anonymous namespace
+
ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
MultiExprArg ArgExprs, SourceLocation RParenLoc,
Expr *ExecConfig, bool IsExecConfig,
@@ -6685,19 +6725,19 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
if (FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_get_counted_by) {
- if (const MemberExpr *ME =
- dyn_cast<MemberExpr>(ArgExprs[0]->IgnoreImpCasts())) {
+ if (const Expr *Ptr = MemberExprVisitor().Visit(ArgExprs[0])) {
+ const MemberExpr *ME = cast<MemberExpr>(Ptr);
bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
Context, getLangOpts().getStrictFlexArraysLevel(),
/*IgnoreTemplateOrMacroSubstitution=*/false);
- // TODO: Probably have to handle horrible casting crap here.
-
- // FIXME: Emit a diagnostic?
if (!ME->HasSideEffects(Context) && IsFlexibleArrayMember &&
ME->getMemberDecl()->getType()->isCountAttributedType()) {
const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
if (const FieldDecl *CountFD = FindCountedByField(FAMDecl)) {
+ // The builtin returns a 'size_t *', however 'size_t' might not be
+ // the type of the count field. Thus we create an explicit c-style
+ // cast to ensure the proper types going forward.
QualType PtrTy = Context.getPointerType(CountFD->getType());
Result = CStyleCastExpr::Create(
Context, PtrTy, VK_LValue, CK_BitCast, Result.get(), nullptr,
>From 122d2b858f6b3b6519bd9ed0298caa284a85e917 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 7 Aug 2024 15:11:45 -0700
Subject: [PATCH 07/59] Add testcases.
---
clang/lib/CodeGen/CGBuiltin.cpp | 4 +-
clang/lib/Sema/SemaExpr.cpp | 4 +-
clang/test/CodeGen/builtin-get-counted-by.c | 83 +++++++++++++++++++++
clang/test/Sema/builtin-get-counted-by.c | 22 ++++++
4 files changed, 109 insertions(+), 4 deletions(-)
create mode 100644 clang/test/CodeGen/builtin-get-counted-by.c
create mode 100644 clang/test/Sema/builtin-get-counted-by.c
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 929a00a844bbdb..6089f6a3d66b63 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3738,8 +3738,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
if (const Expr *Ptr = MemberExprVisitor().Visit(E->getArg(0))) {
const MemberExpr *ME = cast<MemberExpr>(Ptr);
bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
- getContext(), getLangOpts().getStrictFlexArraysLevel(),
- /*IgnoreTemplateOrMacroSubstitution=*/false);
+ getContext(), getLangOpts().getStrictFlexArraysLevel(),
+ /*IgnoreTemplateOrMacroSubstitution=*/false);
if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
ME->getMemberDecl()->getType()->isCountAttributedType()) {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 1ec80fa5849a4a..bb82791f05e4f5 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6728,8 +6728,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
if (const Expr *Ptr = MemberExprVisitor().Visit(ArgExprs[0])) {
const MemberExpr *ME = cast<MemberExpr>(Ptr);
bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
- Context, getLangOpts().getStrictFlexArraysLevel(),
- /*IgnoreTemplateOrMacroSubstitution=*/false);
+ Context, getLangOpts().getStrictFlexArraysLevel(),
+ /*IgnoreTemplateOrMacroSubstitution=*/false);
if (!ME->HasSideEffects(Context) && IsFlexibleArrayMember &&
ME->getMemberDecl()->getType()->isCountAttributedType()) {
diff --git a/clang/test/CodeGen/builtin-get-counted-by.c b/clang/test/CodeGen/builtin-get-counted-by.c
new file mode 100644
index 00000000000000..8209db6a77111e
--- /dev/null
+++ b/clang/test/CodeGen/builtin-get-counted-by.c
@@ -0,0 +1,83 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=X86_64
+// RUN: %clang_cc1 -triple i386-unknown-unknown -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=I386
+
+struct s {
+ char x;
+ short count;
+ int array[] __attribute__((counted_by(count)));
+};
+
+// X86_64-LABEL: define dso_local noalias noundef ptr @test1(
+// X86_64-SAME: i32 noundef [[SIZE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// X86_64-NEXT: [[ENTRY:.*:]]
+// X86_64-NEXT: [[CONV:%.*]] = sext i32 [[SIZE]] to i64
+// X86_64-NEXT: [[MUL:%.*]] = shl nsw i64 [[CONV]], 2
+// X86_64-NEXT: [[ADD:%.*]] = add nsw i64 [[MUL]], 4
+// X86_64-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3:[0-9]+]]
+// X86_64-NEXT: [[CONV1:%.*]] = trunc i32 [[SIZE]] to i16
+// X86_64-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 2
+// X86_64-NEXT: store i16 [[CONV1]], ptr [[DOT_COUNTED_BY_GEP]], align 2, !tbaa [[TBAA2:![0-9]+]]
+// X86_64-NEXT: ret ptr [[CALL]]
+//
+// I386-LABEL: define dso_local noalias noundef ptr @test1(
+// I386-SAME: i32 noundef [[SIZE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// I386-NEXT: [[ENTRY:.*:]]
+// I386-NEXT: [[MUL:%.*]] = shl i32 [[SIZE]], 2
+// I386-NEXT: [[ADD:%.*]] = add i32 [[MUL]], 4
+// I386-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3:[0-9]+]]
+// I386-NEXT: [[CONV:%.*]] = trunc i32 [[SIZE]] to i16
+// I386-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i32 2
+// I386-NEXT: store i16 [[CONV]], ptr [[DOT_COUNTED_BY_GEP]], align 2, !tbaa [[TBAA3:![0-9]+]]
+// I386-NEXT: ret ptr [[CALL]]
+//
+struct s *test1(int size) {
+ struct s *p = __builtin_malloc(sizeof(struct s) + sizeof(int) * size);
+
+ *__builtin_get_counted_by(p->array) = size;
+ *__builtin_get_counted_by(&p->array[0]) = size;
+ return p;
+}
+
+struct z {
+ char x;
+ short count;
+ int array[];
+};
+
+// X86_64-LABEL: define dso_local noalias noundef ptr @test2(
+// X86_64-SAME: i32 noundef [[SIZE:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
+// X86_64-NEXT: [[ENTRY:.*:]]
+// X86_64-NEXT: [[CONV:%.*]] = sext i32 [[SIZE]] to i64
+// X86_64-NEXT: [[MUL:%.*]] = shl nsw i64 [[CONV]], 2
+// X86_64-NEXT: [[ADD:%.*]] = add nsw i64 [[MUL]], 4
+// X86_64-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3]]
+// X86_64-NEXT: ret ptr [[CALL]]
+//
+// I386-LABEL: define dso_local noalias noundef ptr @test2(
+// I386-SAME: i32 noundef [[SIZE:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
+// I386-NEXT: [[ENTRY:.*:]]
+// I386-NEXT: [[MUL:%.*]] = shl i32 [[SIZE]], 2
+// I386-NEXT: [[ADD:%.*]] = add i32 [[MUL]], 4
+// I386-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3]]
+// I386-NEXT: ret ptr [[CALL]]
+//
+struct z *test2(int size) {
+ struct z *p = __builtin_malloc(sizeof(struct z) + sizeof(int) * size);
+
+ if (__builtin_get_counted_by(&p->array[0]))
+ *__builtin_get_counted_by(&p->array[0]) = size;
+
+ return p;
+}
+//.
+// X86_64: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
+// X86_64: [[META3]] = !{!"short", [[META4:![0-9]+]], i64 0}
+// X86_64: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}
+// X86_64: [[META5]] = !{!"Simple C/C++ TBAA"}
+//.
+// I386: [[TBAA3]] = !{[[META4:![0-9]+]], [[META4]], i64 0}
+// I386: [[META4]] = !{!"short", [[META5:![0-9]+]], i64 0}
+// I386: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0}
+// I386: [[META6]] = !{!"Simple C/C++ TBAA"}
+//.
diff --git a/clang/test/Sema/builtin-get-counted-by.c b/clang/test/Sema/builtin-get-counted-by.c
new file mode 100644
index 00000000000000..18cef35b0509a1
--- /dev/null
+++ b/clang/test/Sema/builtin-get-counted-by.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct fam_struct {
+ char x;
+ short count;
+ int array[] __attribute__((counted_by(count)));
+} *p;
+
+struct non_fam_struct {
+ char x;
+ short count;
+ int array[];
+} *q;
+
+void foo(int size) {
+ *__builtin_get_counted_by(p->array) = size;
+
+ if (__builtin_get_counted_by(q->array))
+ *__builtin_get_counted_by(q->array) = size;
+
+ *__builtin_get_counted_by(p->count) = size; // expected-error{{incompatible integer to pointer conversion passing 'short' to parameter of type 'void *'}}
+}
>From 2b58283f9e16c81bf82905f5bc2168766fba5f9e Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 8 Aug 2024 16:51:24 -0700
Subject: [PATCH 08/59] Combine the code to grab the MemberExpr, if it exists.
---
clang/include/clang/AST/Expr.h | 10 +++++--
clang/lib/AST/Expr.cpp | 43 ++++++++++++++++++++++++++++++
clang/lib/CodeGen/CGBuiltin.cpp | 45 ++------------------------------
clang/lib/Sema/SemaExpr.cpp | 46 ++-------------------------------
4 files changed, 55 insertions(+), 89 deletions(-)
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 466c65a9685ad3..236214ac42ba64 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -537,8 +537,8 @@ class Expr : public ValueStmt {
/// semantically correspond to a bool.
bool isKnownToHaveBooleanValue(bool Semantic = true) const;
- /// Check whether this array fits the idiom of a flexible array member,
- /// depending on the value of -fstrict-flex-array.
+ /// isFlexibleArrayMemberLike - Check whether this array fits the idiom of a
+ /// flexible array member, depending on the value of -fstrict-flex-array.
/// When IgnoreTemplateOrMacroSubstitution is set, it doesn't consider sizes
/// resulting from the substitution of a macro or a template as special sizes.
bool isFlexibleArrayMemberLike(
@@ -546,6 +546,12 @@ class Expr : public ValueStmt {
LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel,
bool IgnoreTemplateOrMacroSubstitution = false) const;
+ /// getMemberExpr - Find the first MemberExpr of the Expr. This method
+ /// intentionally looks through all casts, array subscripts, and unary
+ /// operators to find an underlying MemberExpr. If one doesn't exist, it
+ /// returns a nullptr.
+ const MemberExpr *getMemberExpr() const;
+
/// isIntegerConstantExpr - Return the value if this expression is a valid
/// integer constant expression. If not a valid i-c-e, return std::nullopt
/// and fill in Loc (if specified) with the location of the invalid
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index bf2c1b92fa6b49..c87f0f1d518e38 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -223,6 +223,49 @@ bool Expr::isFlexibleArrayMemberLike(
IgnoreTemplateOrMacroSubstitution);
}
+namespace {
+
+/// MemberExprVisitor - Find the MemberExpr through all of the casts, array
+/// subscripts, and unary ops. This intentionally avoids all of them because
+/// we're interested only in the MemberExpr to check if it's a flexible array
+/// member.
+class MemberExprVisitor
+ : public ConstStmtVisitor<MemberExprVisitor, const Expr *> {
+public:
+ //===--------------------------------------------------------------------===//
+ // Visitor Methods
+ //===--------------------------------------------------------------------===//
+
+ const Expr *Visit(const Expr *E) {
+ return ConstStmtVisitor<MemberExprVisitor, const Expr *>::Visit(E);
+ }
+ const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+ const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
+
+ const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+ return Visit(E->getBase());
+ }
+ const Expr *VisitCastExpr(const CastExpr *E) {
+ return Visit(E->getSubExpr());
+ }
+ const Expr *VisitParenExpr(const ParenExpr *E) {
+ return Visit(E->getSubExpr());
+ }
+ const Expr *VisitUnaryAddrOf(const UnaryOperator *E) {
+ return Visit(E->getSubExpr());
+ }
+ const Expr *VisitUnaryDeref(const UnaryOperator *E) {
+ return Visit(E->getSubExpr());
+ }
+};
+
+} // anonymous namespace
+
+const MemberExpr *Expr::getMemberExpr() const {
+ return dyn_cast_if_present<MemberExpr>(MemberExprVisitor().Visit(this));
+}
+
const ValueDecl *
Expr::getAsBuiltinConstantDeclRef(const ASTContext &Context) const {
Expr::EvalResult Eval;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 6089f6a3d66b63..c2c7f24fa75af9 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2639,45 +2639,6 @@ static RValue EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
return RValue::get(CGF->Builder.CreateCall(UBF, Args));
}
-namespace {
-
-/// MemberExprVisitor - Find the MemberExpr through all of the casts, array
-/// subscripts, and unary ops. This intentionally avoids all of them because
-/// we're interested only in the MemberExpr to check if it's a flexible array
-/// member.
-class MemberExprVisitor
- : public ConstStmtVisitor<MemberExprVisitor, const Expr *> {
-public:
- //===--------------------------------------------------------------------===//
- // Visitor Methods
- //===--------------------------------------------------------------------===//
-
- const Expr *Visit(const Expr *E) {
- return ConstStmtVisitor<MemberExprVisitor, const Expr *>::Visit(E);
- }
- const Expr *VisitStmt(const Stmt *S) { return nullptr; }
-
- const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
-
- const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
- return Visit(E->getBase());
- }
- const Expr *VisitCastExpr(const CastExpr *E) {
- return Visit(E->getSubExpr());
- }
- const Expr *VisitParenExpr(const ParenExpr *E) {
- return Visit(E->getSubExpr());
- }
- const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
- return Visit(E->getSubExpr());
- }
- const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) {
- return Visit(E->getSubExpr());
- }
-};
-
-} // anonymous namespace
-
RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
const CallExpr *E,
ReturnValueSlot ReturnValue) {
@@ -3735,11 +3696,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
llvm::Value *Result = llvm::ConstantPointerNull::get(
cast<llvm::PointerType>(ConvertType(E->getType())));
- if (const Expr *Ptr = MemberExprVisitor().Visit(E->getArg(0))) {
- const MemberExpr *ME = cast<MemberExpr>(Ptr);
+ if (const MemberExpr *ME = E->getArg(0)->getMemberExpr()) {
bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
- getContext(), getLangOpts().getStrictFlexArraysLevel(),
- /*IgnoreTemplateOrMacroSubstitution=*/false);
+ getContext(), getLangOpts().getStrictFlexArraysLevel());
if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
ME->getMemberDecl()->getType()->isCountAttributedType()) {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index bb82791f05e4f5..8acad00485d469 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -30,7 +30,6 @@
#include "clang/AST/OperationKinds.h"
#include "clang/AST/ParentMapContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
@@ -6483,45 +6482,6 @@ const FieldDecl *FindCountedByField(const FieldDecl *FD) {
return dyn_cast<FieldDecl>(CountDecl);
}
-namespace {
-
-/// MemberExprVisitor - Find the MemberExpr through all of the casts, array
-/// subscripts, and unary ops. This intentionally avoids all of them because
-/// we're interested only in the MemberExpr to check if it's a flexible array
-/// member.
-class MemberExprVisitor
- : public ConstStmtVisitor<MemberExprVisitor, const Expr *> {
-public:
- //===--------------------------------------------------------------------===//
- // Visitor Methods
- //===--------------------------------------------------------------------===//
-
- const Expr *Visit(const Expr *E) {
- return ConstStmtVisitor<MemberExprVisitor, const Expr *>::Visit(E);
- }
- const Expr *VisitStmt(const Stmt *S) { return nullptr; }
-
- const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
-
- const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
- return Visit(E->getBase());
- }
- const Expr *VisitCastExpr(const CastExpr *E) {
- return Visit(E->getSubExpr());
- }
- const Expr *VisitParenExpr(const ParenExpr *E) {
- return Visit(E->getSubExpr());
- }
- const Expr *VisitUnaryAddrOf(const UnaryOperator *E) {
- return Visit(E->getSubExpr());
- }
- const Expr *VisitUnaryDeref(const UnaryOperator *E) {
- return Visit(E->getSubExpr());
- }
-};
-
-} // anonymous namespace
-
ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
MultiExprArg ArgExprs, SourceLocation RParenLoc,
Expr *ExecConfig, bool IsExecConfig,
@@ -6725,11 +6685,9 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
if (FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_get_counted_by) {
- if (const Expr *Ptr = MemberExprVisitor().Visit(ArgExprs[0])) {
- const MemberExpr *ME = cast<MemberExpr>(Ptr);
+ if (const MemberExpr *ME = ArgExprs[0]->getMemberExpr()) {
bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
- Context, getLangOpts().getStrictFlexArraysLevel(),
- /*IgnoreTemplateOrMacroSubstitution=*/false);
+ Context, getLangOpts().getStrictFlexArraysLevel());
if (!ME->HasSideEffects(Context) && IsFlexibleArrayMember &&
ME->getMemberDecl()->getType()->isCountAttributedType()) {
>From 76f01fe2e4721bb608a7383d061e551c00fe8423 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 9 Aug 2024 16:38:50 -0700
Subject: [PATCH 09/59] Move FindCountedByField into a central place.
---
clang/include/clang/AST/Decl.h | 2 +-
clang/lib/AST/Decl.cpp | 2 +-
clang/lib/CodeGen/CGBuiltin.cpp | 4 ++--
clang/lib/CodeGen/CGExpr.cpp | 2 +-
clang/lib/CodeGen/CodeGenFunction.h | 4 ----
clang/lib/Sema/SemaExpr.cpp | 19 +------------------
6 files changed, 6 insertions(+), 27 deletions(-)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 7ff35d73df5997..310427b919d28b 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3212,7 +3212,7 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
/// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns
/// \p nullptr if either the attribute or the field doesn't exist.
- const FieldDecl *findCountedByField() const;
+ const FieldDecl *FindCountedByField() const;
private:
void setLazyInClassInitializer(LazyDeclStmtPtr NewInit);
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 86913763ef9ff5..31e1a7111a4219 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -4699,7 +4699,7 @@ void FieldDecl::printName(raw_ostream &OS, const PrintingPolicy &Policy) const {
DeclaratorDecl::printName(OS, Policy);
}
-const FieldDecl *FieldDecl::findCountedByField() const {
+const FieldDecl *FieldDecl::FindCountedByField() const {
const auto *CAT = getType()->getAs<CountAttributedType>();
if (!CAT)
return nullptr;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index c2c7f24fa75af9..097a75f154e38c 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -1083,7 +1083,7 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
// attribute.
return nullptr;
- const FieldDecl *CountedByFD = FAMDecl->findCountedByField();
+ const FieldDecl *CountedByFD = FAMDecl->FindCountedByField();
if (!CountedByFD)
// Can't find the field referenced by the "counted_by" attribute.
return nullptr;
@@ -3703,7 +3703,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
ME->getMemberDecl()->getType()->isCountAttributedType()) {
const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
- if (const FieldDecl *CountFD = FindCountedByField(FAMDecl))
+ if (const FieldDecl *CountFD = FAMDecl->FindCountedByField())
Result = GetCountedByFieldExprGEP(ME, FAMDecl, CountFD);
}
}
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 3364a00c6e9ff7..b6cc36f29e5dcb 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4371,7 +4371,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
ME->isFlexibleArrayMemberLike(getContext(), StrictFlexArraysLevel) &&
ME->getMemberDecl()->getType()->isCountAttributedType()) {
const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
- if (const FieldDecl *CountFD = FAMDecl->findCountedByField()) {
+ if (const FieldDecl *CountFD = FAMDecl->FindCountedByField()) {
if (std::optional<int64_t> Diff =
getOffsetDifferenceInBits(*this, CountFD, FAMDecl)) {
CharUnits OffsetDiff = CGM.getContext().toCharUnitsFromBits(*Diff);
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index a370a2fe5f5775..90dc399f1341f3 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3305,10 +3305,6 @@ class CodeGenFunction : public CodeGenTypeCache {
const FieldDecl *FAMDecl,
uint64_t &Offset);
- /// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns
- /// \p nullptr if either the attribute or the field doesn't exist.
- const FieldDecl *FindCountedByField(const FieldDecl *FD);
-
llvm::Value *GetCountedByFieldExprGEP(const Expr *Base,
const FieldDecl *FAMDecl,
const FieldDecl *CountDecl);
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 8acad00485d469..c905a22da14ccd 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6462,26 +6462,9 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
currentEvaluationContext().ReferenceToConsteval.erase(DRE);
}
}
-
return Call;
}
-const FieldDecl *FindCountedByField(const FieldDecl *FD) {
- if (!FD)
- return nullptr;
-
- const auto *CAT = FD->getType()->getAs<CountAttributedType>();
- if (!CAT)
- return nullptr;
-
- const auto *CountDRE = cast<DeclRefExpr>(CAT->getCountExpr());
- const auto *CountDecl = CountDRE->getDecl();
- if (const auto *IFD = dyn_cast<IndirectFieldDecl>(CountDecl))
- CountDecl = IFD->getAnonField();
-
- return dyn_cast<FieldDecl>(CountDecl);
-}
-
ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
MultiExprArg ArgExprs, SourceLocation RParenLoc,
Expr *ExecConfig, bool IsExecConfig,
@@ -6692,7 +6675,7 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
if (!ME->HasSideEffects(Context) && IsFlexibleArrayMember &&
ME->getMemberDecl()->getType()->isCountAttributedType()) {
const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
- if (const FieldDecl *CountFD = FindCountedByField(FAMDecl)) {
+ if (const FieldDecl *CountFD = FAMDecl->FindCountedByField()) {
// The builtin returns a 'size_t *', however 'size_t' might not be
// the type of the count field. Thus we create an explicit c-style
// cast to ensure the proper types going forward.
>From c95e38c9e8d3b6870aca5e365753d16a91c8be08 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 14 Aug 2024 12:11:27 -0700
Subject: [PATCH 10/59] Use CustomTypeChecking for the builtin. It allows us
explicitly to set the return type based on the 'count' field's type.
---
clang/include/clang/Basic/Builtins.td | 4 +-
.../clang/Basic/DiagnosticSemaKinds.td | 5 +++
clang/include/clang/Sema/Sema.h | 2 +
clang/lib/AST/Expr.cpp | 5 ---
clang/lib/Sema/SemaChecking.cpp | 42 +++++++++++++++++++
clang/lib/Sema/SemaExpr.cpp | 29 +------------
6 files changed, 53 insertions(+), 34 deletions(-)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 81e7e581ecb243..5f9aded810d982 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4917,6 +4917,6 @@ def ArithmeticFence : LangBuiltin<"ALL_LANGUAGES"> {
def GetCountedBy : Builtin {
let Spellings = ["__builtin_get_counted_by"];
- let Attributes = [NoThrow];
- let Prototype = "size_t*(void*)";
+ let Attributes = [NoThrow, CustomTypeChecking];
+ let Prototype = "int(...)";
}
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 34ff49d7238a7f..04b1ab864f97ad 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6652,6 +6652,11 @@ def warn_counted_by_attr_elt_type_unknown_size :
Warning<err_counted_by_attr_pointee_unknown_size.Summary>,
InGroup<BoundsSafetyCountedByEltTyUnknownSize>;
+def err_builtin_get_counted_by_has_side_effects : Error<
+ "__builtin_get_counted_by cannot have side-effects">;
+def err_builtin_get_counted_by_must_be_pointer : Error<
+ "__builtin_get_counted_by argument must be a pointer">;
+
let CategoryName = "ARC Semantic Issue" in {
// ARC-mode diagnostics.
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 93d98e1cbb9c81..7dc2a39dc3a4db 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2510,6 +2510,8 @@ class Sema final : public SemaBase {
bool BuiltinNonDeterministicValue(CallExpr *TheCall);
+ bool BuiltinGetCountedBy(CallExpr *TheCall);
+
// Matrix builtin handling.
ExprResult BuiltinMatrixTranspose(CallExpr *TheCall, ExprResult CallResult);
ExprResult BuiltinMatrixColumnMajorLoad(CallExpr *TheCall,
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index c87f0f1d518e38..159a69272ebba3 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -236,11 +236,6 @@ class MemberExprVisitor
// Visitor Methods
//===--------------------------------------------------------------------===//
- const Expr *Visit(const Expr *E) {
- return ConstStmtVisitor<MemberExprVisitor, const Expr *>::Visit(E);
- }
- const Expr *VisitStmt(const Stmt *S) { return nullptr; }
-
const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index dae271c1ff5001..9b7f6cd45f380c 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2971,6 +2971,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
}
break;
}
+ case Builtin::BI__builtin_get_counted_by:
+ if (BuiltinGetCountedBy(TheCall))
+ return ExprError();
+ break;
}
if (getLangOpts().HLSL && HLSL().CheckBuiltinFunctionCall(BuiltinID, TheCall))
@@ -5573,6 +5577,44 @@ bool Sema::BuiltinSetjmp(CallExpr *TheCall) {
return false;
}
+bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
+ if (checkArgCount(TheCall, 1))
+ return true;
+
+ ExprResult ArgRes = UsualUnaryConversions(TheCall->getArg(0));
+ if (ArgRes.isInvalid())
+ return true;
+
+ const Expr *Arg = ArgRes.get();
+ if (!isa<PointerType>(Arg->getType()))
+ return Diag(Arg->getBeginLoc(),
+ diag::err_builtin_get_counted_by_must_be_pointer)
+ << Arg->getSourceRange();
+
+ if (Arg->HasSideEffects(Context))
+ return Diag(Arg->getBeginLoc(),
+ diag::err_builtin_get_counted_by_has_side_effects)
+ << Arg->getSourceRange();
+
+ // Use 'void *' as the default return type. If the argument doesn't have the
+ // 'counted_by' attribute, it'll return a "nullptr."
+ TheCall->setType(Context.VoidPtrTy);
+
+ if (const MemberExpr *ME = Arg->getMemberExpr();
+ ME &&
+ ME->isFlexibleArrayMemberLike(Context,
+ getLangOpts().getStrictFlexArraysLevel()) &&
+ ME->getMemberDecl()->getType()->isCountAttributedType()) {
+ if (const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ if (const FieldDecl *CountFD = FAMDecl->FindCountedByField())
+ // The proper return type should be a pointer to the type of the
+ // counted_by's 'count' field.
+ TheCall->setType(Context.getPointerType(CountFD->getType()));
+ }
+
+ return false;
+}
+
namespace {
class UncoveredArgHandler {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index c905a22da14ccd..ba7baf1476a380 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6663,33 +6663,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
VK_PRValue, RParenLoc, CurFPFeatureOverrides());
}
- Result = BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc,
- ExecConfig, IsExecConfig);
-
- if (FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
- FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_get_counted_by) {
- if (const MemberExpr *ME = ArgExprs[0]->getMemberExpr()) {
- bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
- Context, getLangOpts().getStrictFlexArraysLevel());
-
- if (!ME->HasSideEffects(Context) && IsFlexibleArrayMember &&
- ME->getMemberDecl()->getType()->isCountAttributedType()) {
- const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
- if (const FieldDecl *CountFD = FAMDecl->FindCountedByField()) {
- // The builtin returns a 'size_t *', however 'size_t' might not be
- // the type of the count field. Thus we create an explicit c-style
- // cast to ensure the proper types going forward.
- QualType PtrTy = Context.getPointerType(CountFD->getType());
- Result = CStyleCastExpr::Create(
- Context, PtrTy, VK_LValue, CK_BitCast, Result.get(), nullptr,
- FPOptionsOverride(), Context.CreateTypeSourceInfo(PtrTy),
- LParenLoc, RParenLoc);
- }
- }
- }
- }
-
- return Result;
+ return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc,
+ ExecConfig, IsExecConfig);
}
Expr *Sema::BuildBuiltinCallExpr(SourceLocation Loc, Builtin::ID Id,
>From 925fbd2a2cfc2c495a827ecebc7919c06e297d18 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 15 Aug 2024 05:27:19 +0000
Subject: [PATCH 11/59] [Clang][NFC] Move FindCountedByField into FieldDecl
(#104235)
FindCountedByField can be used in more places than CodeGen. Move it into
FieldDecl to avoid layering issues.
---
clang/include/clang/AST/Decl.h | 2 +-
clang/lib/AST/Decl.cpp | 2 +-
clang/lib/CodeGen/CGBuiltin.cpp | 2 +-
clang/lib/CodeGen/CGExpr.cpp | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 310427b919d28b..7ff35d73df5997 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3212,7 +3212,7 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
/// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns
/// \p nullptr if either the attribute or the field doesn't exist.
- const FieldDecl *FindCountedByField() const;
+ const FieldDecl *findCountedByField() const;
private:
void setLazyInClassInitializer(LazyDeclStmtPtr NewInit);
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 31e1a7111a4219..86913763ef9ff5 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -4699,7 +4699,7 @@ void FieldDecl::printName(raw_ostream &OS, const PrintingPolicy &Policy) const {
DeclaratorDecl::printName(OS, Policy);
}
-const FieldDecl *FieldDecl::FindCountedByField() const {
+const FieldDecl *FieldDecl::findCountedByField() const {
const auto *CAT = getType()->getAs<CountAttributedType>();
if (!CAT)
return nullptr;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 097a75f154e38c..9d4ca330cf3cda 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -1083,7 +1083,7 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
// attribute.
return nullptr;
- const FieldDecl *CountedByFD = FAMDecl->FindCountedByField();
+ const FieldDecl *CountedByFD = FAMDecl->findCountedByField();
if (!CountedByFD)
// Can't find the field referenced by the "counted_by" attribute.
return nullptr;
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index b6cc36f29e5dcb..3364a00c6e9ff7 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4371,7 +4371,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
ME->isFlexibleArrayMemberLike(getContext(), StrictFlexArraysLevel) &&
ME->getMemberDecl()->getType()->isCountAttributedType()) {
const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
- if (const FieldDecl *CountFD = FAMDecl->FindCountedByField()) {
+ if (const FieldDecl *CountFD = FAMDecl->findCountedByField()) {
if (std::optional<int64_t> Diff =
getOffsetDifferenceInBits(*this, CountFD, FAMDecl)) {
CharUnits OffsetDiff = CGM.getContext().toCharUnitsFromBits(*Diff);
>From ec62a2b3264f56949a683d2a78f15467bb1dc159 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 14 Aug 2024 22:34:51 -0700
Subject: [PATCH 12/59] Fix a build failure.
---
clang/lib/CodeGen/CGBuiltin.cpp | 2 +-
clang/lib/Sema/SemaChecking.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 9d4ca330cf3cda..4552313f8c348a 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3703,7 +3703,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
ME->getMemberDecl()->getType()->isCountAttributedType()) {
const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
- if (const FieldDecl *CountFD = FAMDecl->FindCountedByField())
+ if (const FieldDecl *CountFD = FAMDecl->findCountedByField())
Result = GetCountedByFieldExprGEP(ME, FAMDecl, CountFD);
}
}
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 9b7f6cd45f380c..6529f5a7a38434 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5606,7 +5606,7 @@ bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
getLangOpts().getStrictFlexArraysLevel()) &&
ME->getMemberDecl()->getType()->isCountAttributedType()) {
if (const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl()))
- if (const FieldDecl *CountFD = FAMDecl->FindCountedByField())
+ if (const FieldDecl *CountFD = FAMDecl->findCountedByField())
// The proper return type should be a pointer to the type of the
// counted_by's 'count' field.
TheCall->setType(Context.getPointerType(CountFD->getType()));
>From d3ca48c77fdafa6ff4f37f53529abf48b4f57cbb Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 15 Aug 2024 02:31:29 -0700
Subject: [PATCH 13/59] Remove empty line.
---
clang/lib/Sema/SemaExpr.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index ba7baf1476a380..7f3cff1054aeed 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6662,7 +6662,6 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy,
VK_PRValue, RParenLoc, CurFPFeatureOverrides());
}
-
return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc,
ExecConfig, IsExecConfig);
}
>From 85b4474a52f730e7a2d905595d87f7c95147e7b6 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 15 Aug 2024 02:33:15 -0700
Subject: [PATCH 14/59] Remove merge errors.
>From 91a7d1b19bdb7b9d202894d6472a56efb9e63037 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 15 Aug 2024 03:22:54 -0700
Subject: [PATCH 15/59] Use 'size_t *' for the default return type and improve
the testcase.
---
clang/lib/Sema/SemaChecking.cpp | 6 +++---
clang/test/Sema/builtin-get-counted-by.c | 19 ++++++++++++-------
2 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 6529f5a7a38434..262fbc740b4a14 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5596,9 +5596,9 @@ bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
diag::err_builtin_get_counted_by_has_side_effects)
<< Arg->getSourceRange();
- // Use 'void *' as the default return type. If the argument doesn't have the
- // 'counted_by' attribute, it'll return a "nullptr."
- TheCall->setType(Context.VoidPtrTy);
+ // Use 'size_t *' as the default return type. If the argument doesn't have
+ // the 'counted_by' attribute, it'll return a "nullptr."
+ TheCall->setType(Context.getPointerType(Context.getSizeType()));
if (const MemberExpr *ME = Arg->getMemberExpr();
ME &&
diff --git a/clang/test/Sema/builtin-get-counted-by.c b/clang/test/Sema/builtin-get-counted-by.c
index 18cef35b0509a1..27ae4a440243a5 100644
--- a/clang/test/Sema/builtin-get-counted-by.c
+++ b/clang/test/Sema/builtin-get-counted-by.c
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
struct fam_struct {
- char x;
- short count;
+ int x;
+ char count;
int array[] __attribute__((counted_by(count)));
} *p;
@@ -12,11 +12,16 @@ struct non_fam_struct {
int array[];
} *q;
-void foo(int size) {
- *__builtin_get_counted_by(p->array) = size;
+void test1(int size) {
+ int i = 0;
- if (__builtin_get_counted_by(q->array))
- *__builtin_get_counted_by(q->array) = size;
+ *__builtin_get_counted_by(p->array) = size; // ok
+ *__builtin_get_counted_by(&p->array[i]) = size; // ok
+ if (__builtin_get_counted_by(q->array)) // ok
+ *__builtin_get_counted_by(q->array) = size; // ok
- *__builtin_get_counted_by(p->count) = size; // expected-error{{incompatible integer to pointer conversion passing 'short' to parameter of type 'void *'}}
+ __builtin_get_counted_by(&p->array[i++]); // expected-error {{__builtin_get_counted_by cannot have side-effects}}
+ __builtin_get_counted_by(p->x); // expected-error {{__builtin_get_counted_by argument must be a pointer}}
+ __builtin_get_counted_by(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+ __builtin_get_counted_by(p->array, p->x, p->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
}
>From 2d95e441b4cd4d7a1a5deb14676b1c1ca3b44431 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 15 Aug 2024 13:17:29 -0700
Subject: [PATCH 16/59] Don't use a Visitor to retrieve the MemberExpr. Instead
accept only non-pathological expressions.
---
clang/include/clang/AST/Expr.h | 6 ---
.../clang/Basic/DiagnosticSemaKinds.td | 5 ++-
clang/lib/AST/Expr.cpp | 38 -------------------
clang/lib/CodeGen/CGBuiltin.cpp | 12 +++++-
clang/lib/Sema/SemaChecking.cpp | 17 +++++++--
clang/test/Sema/builtin-get-counted-by.c | 3 +-
6 files changed, 29 insertions(+), 52 deletions(-)
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 236214ac42ba64..b00f9dab02a29e 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -546,12 +546,6 @@ class Expr : public ValueStmt {
LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel,
bool IgnoreTemplateOrMacroSubstitution = false) const;
- /// getMemberExpr - Find the first MemberExpr of the Expr. This method
- /// intentionally looks through all casts, array subscripts, and unary
- /// operators to find an underlying MemberExpr. If one doesn't exist, it
- /// returns a nullptr.
- const MemberExpr *getMemberExpr() const;
-
/// isIntegerConstantExpr - Return the value if this expression is a valid
/// integer constant expression. If not a valid i-c-e, return std::nullopt
/// and fill in Loc (if specified) with the location of the invalid
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 04b1ab864f97ad..39c7fe6512cbb0 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6654,8 +6654,9 @@ def warn_counted_by_attr_elt_type_unknown_size :
def err_builtin_get_counted_by_has_side_effects : Error<
"__builtin_get_counted_by cannot have side-effects">;
-def err_builtin_get_counted_by_must_be_pointer : Error<
- "__builtin_get_counted_by argument must be a pointer">;
+def err_builtin_get_counted_by_must_be_flex_array_member : Error<
+ "__builtin_get_counted_by argument must be a pointer "
+ "to a flexible array member">;
let CategoryName = "ARC Semantic Issue" in {
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 159a69272ebba3..bf2c1b92fa6b49 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -223,44 +223,6 @@ bool Expr::isFlexibleArrayMemberLike(
IgnoreTemplateOrMacroSubstitution);
}
-namespace {
-
-/// MemberExprVisitor - Find the MemberExpr through all of the casts, array
-/// subscripts, and unary ops. This intentionally avoids all of them because
-/// we're interested only in the MemberExpr to check if it's a flexible array
-/// member.
-class MemberExprVisitor
- : public ConstStmtVisitor<MemberExprVisitor, const Expr *> {
-public:
- //===--------------------------------------------------------------------===//
- // Visitor Methods
- //===--------------------------------------------------------------------===//
-
- const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
-
- const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
- return Visit(E->getBase());
- }
- const Expr *VisitCastExpr(const CastExpr *E) {
- return Visit(E->getSubExpr());
- }
- const Expr *VisitParenExpr(const ParenExpr *E) {
- return Visit(E->getSubExpr());
- }
- const Expr *VisitUnaryAddrOf(const UnaryOperator *E) {
- return Visit(E->getSubExpr());
- }
- const Expr *VisitUnaryDeref(const UnaryOperator *E) {
- return Visit(E->getSubExpr());
- }
-};
-
-} // anonymous namespace
-
-const MemberExpr *Expr::getMemberExpr() const {
- return dyn_cast_if_present<MemberExpr>(MemberExprVisitor().Visit(this));
-}
-
const ValueDecl *
Expr::getAsBuiltinConstantDeclRef(const ASTContext &Context) const {
Expr::EvalResult Eval;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 4552313f8c348a..d9c37296a404e3 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3696,7 +3696,17 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
llvm::Value *Result = llvm::ConstantPointerNull::get(
cast<llvm::PointerType>(ConvertType(E->getType())));
- if (const MemberExpr *ME = E->getArg(0)->getMemberExpr()) {
+ const Expr *Arg = E->getArg(0)->IgnoreParenImpCasts();
+
+ if (auto *UO = dyn_cast<UnaryOperator>(Arg);
+ UO && UO->getOpcode() == UO_AddrOf) {
+ Arg = UO->getSubExpr()->IgnoreParenImpCasts();
+
+ if (auto *ASE = dyn_cast<ArraySubscriptExpr>(Arg))
+ Arg = ASE->getBase()->IgnoreParenImpCasts();
+ }
+
+ if (const MemberExpr *ME = dyn_cast_if_present<MemberExpr>(Arg)) {
bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
getContext(), getLangOpts().getStrictFlexArraysLevel());
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 262fbc740b4a14..7a1cdd3c4bb7c4 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5585,10 +5585,10 @@ bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
if (ArgRes.isInvalid())
return true;
- const Expr *Arg = ArgRes.get();
- if (!isa<PointerType>(Arg->getType()))
+ const Expr *Arg = ArgRes.get()->IgnoreParenImpCasts();
+ if (!isa<PointerType>(Arg->getType()) && !Arg->getType()->isArrayType())
return Diag(Arg->getBeginLoc(),
- diag::err_builtin_get_counted_by_must_be_pointer)
+ diag::err_builtin_get_counted_by_must_be_flex_array_member)
<< Arg->getSourceRange();
if (Arg->HasSideEffects(Context))
@@ -5596,11 +5596,20 @@ bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
diag::err_builtin_get_counted_by_has_side_effects)
<< Arg->getSourceRange();
+ // See if we have something like '&ptr->fam[0]`.
+ if (auto *UO = dyn_cast<UnaryOperator>(Arg);
+ UO && UO->getOpcode() == UO_AddrOf) {
+ Arg = UO->getSubExpr()->IgnoreParenImpCasts();
+
+ if (auto *ASE = dyn_cast<ArraySubscriptExpr>(Arg))
+ Arg = ASE->getBase()->IgnoreParenImpCasts();
+ }
+
// Use 'size_t *' as the default return type. If the argument doesn't have
// the 'counted_by' attribute, it'll return a "nullptr."
TheCall->setType(Context.getPointerType(Context.getSizeType()));
- if (const MemberExpr *ME = Arg->getMemberExpr();
+ if (const MemberExpr *ME = dyn_cast_if_present<MemberExpr>(Arg);
ME &&
ME->isFlexibleArrayMemberLike(Context,
getLangOpts().getStrictFlexArraysLevel()) &&
diff --git a/clang/test/Sema/builtin-get-counted-by.c b/clang/test/Sema/builtin-get-counted-by.c
index 27ae4a440243a5..707d477a974238 100644
--- a/clang/test/Sema/builtin-get-counted-by.c
+++ b/clang/test/Sema/builtin-get-counted-by.c
@@ -17,11 +17,12 @@ void test1(int size) {
*__builtin_get_counted_by(p->array) = size; // ok
*__builtin_get_counted_by(&p->array[i]) = size; // ok
+
if (__builtin_get_counted_by(q->array)) // ok
*__builtin_get_counted_by(q->array) = size; // ok
+ __builtin_get_counted_by(p->x); // expected-error {{__builtin_get_counted_by argument must be a pointer to a flexible array member}}
__builtin_get_counted_by(&p->array[i++]); // expected-error {{__builtin_get_counted_by cannot have side-effects}}
- __builtin_get_counted_by(p->x); // expected-error {{__builtin_get_counted_by argument must be a pointer}}
__builtin_get_counted_by(); // expected-error {{too few arguments to function call, expected 1, have 0}}
__builtin_get_counted_by(p->array, p->x, p->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
}
>From 9628b0fa083a7c0efc445c50fe339c525f6295ff Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 15 Aug 2024 13:58:46 -0700
Subject: [PATCH 17/59] Improve error messages. Make the side-effects error a
warning.
---
.../clang/Basic/DiagnosticSemaKinds.td | 7 ++---
clang/lib/Sema/SemaChecking.cpp | 28 ++++++++++---------
clang/test/Sema/builtin-get-counted-by.c | 10 +++----
3 files changed, 23 insertions(+), 22 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 39c7fe6512cbb0..aa610188c06424 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6652,11 +6652,10 @@ def warn_counted_by_attr_elt_type_unknown_size :
Warning<err_counted_by_attr_pointee_unknown_size.Summary>,
InGroup<BoundsSafetyCountedByEltTyUnknownSize>;
-def err_builtin_get_counted_by_has_side_effects : Error<
- "__builtin_get_counted_by cannot have side-effects">;
def err_builtin_get_counted_by_must_be_flex_array_member : Error<
- "__builtin_get_counted_by argument must be a pointer "
- "to a flexible array member">;
+ "'__builtin_get_counted_by' argument must reference a flexible array member">;
+def warn_builtin_get_counted_by_has_side_effects : Warning<
+ "'__builtin_get_counted_by' argument has side-effects that will be discarded">;
let CategoryName = "ARC Semantic Issue" in {
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 7a1cdd3c4bb7c4..8a8e6de9a6866b 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5592,9 +5592,8 @@ bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
<< Arg->getSourceRange();
if (Arg->HasSideEffects(Context))
- return Diag(Arg->getBeginLoc(),
- diag::err_builtin_get_counted_by_has_side_effects)
- << Arg->getSourceRange();
+ Diag(Arg->getBeginLoc(), diag::warn_builtin_get_counted_by_has_side_effects)
+ << Arg->getSourceRange();
// See if we have something like '&ptr->fam[0]`.
if (auto *UO = dyn_cast<UnaryOperator>(Arg);
@@ -5609,16 +5608,19 @@ bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
// the 'counted_by' attribute, it'll return a "nullptr."
TheCall->setType(Context.getPointerType(Context.getSizeType()));
- if (const MemberExpr *ME = dyn_cast_if_present<MemberExpr>(Arg);
- ME &&
- ME->isFlexibleArrayMemberLike(Context,
- getLangOpts().getStrictFlexArraysLevel()) &&
- ME->getMemberDecl()->getType()->isCountAttributedType()) {
- if (const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl()))
- if (const FieldDecl *CountFD = FAMDecl->findCountedByField())
- // The proper return type should be a pointer to the type of the
- // counted_by's 'count' field.
- TheCall->setType(Context.getPointerType(CountFD->getType()));
+ if (const MemberExpr *ME = dyn_cast_if_present<MemberExpr>(Arg)) {
+ if (!ME->isFlexibleArrayMemberLike(
+ Context, getLangOpts().getStrictFlexArraysLevel()))
+ return Diag(Arg->getBeginLoc(),
+ diag::err_builtin_get_counted_by_must_be_flex_array_member)
+ << Arg->getSourceRange();
+
+ if (ME->getMemberDecl()->getType()->isCountAttributedType())
+ if (const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ if (const FieldDecl *CountFD = FAMDecl->findCountedByField())
+ // The proper return type should be a pointer to the type of the
+ // counted_by's 'count' field.
+ TheCall->setType(Context.getPointerType(CountFD->getType()));
}
return false;
diff --git a/clang/test/Sema/builtin-get-counted-by.c b/clang/test/Sema/builtin-get-counted-by.c
index 707d477a974238..6dcb1a0ab73754 100644
--- a/clang/test/Sema/builtin-get-counted-by.c
+++ b/clang/test/Sema/builtin-get-counted-by.c
@@ -8,8 +8,8 @@ struct fam_struct {
struct non_fam_struct {
char x;
+ int array[42];
short count;
- int array[];
} *q;
void test1(int size) {
@@ -18,11 +18,11 @@ void test1(int size) {
*__builtin_get_counted_by(p->array) = size; // ok
*__builtin_get_counted_by(&p->array[i]) = size; // ok
- if (__builtin_get_counted_by(q->array)) // ok
- *__builtin_get_counted_by(q->array) = size; // ok
+ *__builtin_get_counted_by(q->array) = size // expected-error {{'__builtin_get_counted_by' argument must reference a flexible array member}}
+ *__builtin_get_counted_by(&q->array[0]) = size; // expected-error {{'__builtin_get_counted_by' argument must reference a flexible array member}}
+ __builtin_get_counted_by(p->x); // expected-error {{'__builtin_get_counted_by' argument must reference a flexible array member}}
+ __builtin_get_counted_by(&p->array[i++]); // expected-warning {{'__builtin_get_counted_by' argument has side-effects that will be discarded}}
- __builtin_get_counted_by(p->x); // expected-error {{__builtin_get_counted_by argument must be a pointer to a flexible array member}}
- __builtin_get_counted_by(&p->array[i++]); // expected-error {{__builtin_get_counted_by cannot have side-effects}}
__builtin_get_counted_by(); // expected-error {{too few arguments to function call, expected 1, have 0}}
__builtin_get_counted_by(p->array, p->x, p->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
}
>From c278c1f1f5db5304a75a72327a3575bfb6c3b83d Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 15 Aug 2024 14:25:09 -0700
Subject: [PATCH 18/59] Add _Generic checks.
---
clang/lib/CodeGen/CGExpr.cpp | 6 ++--
clang/test/Sema/builtin-get-counted-by.c | 41 +++++++++++++++++++++++-
2 files changed, 43 insertions(+), 4 deletions(-)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 3364a00c6e9ff7..024a7a47e1398d 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1174,9 +1174,9 @@ llvm::Value *CodeGenFunction::GetCountedByFieldExprGEP(
return nullptr;
Indices.push_back(Builder.getInt32(0));
- return Builder.CreateInBoundsGEP(
- ConvertType(QualType(RD->getTypeForDecl(), 0)), Res,
- RecIndicesTy(llvm::reverse(Indices)), "..counted_by.gep");
+ return Builder.CreateGEP(ConvertType(QualType(RD->getTypeForDecl(), 0)), Res,
+ RecIndicesTy(llvm::reverse(Indices)),
+ "..counted_by.gep");
}
/// This method is typically called in contexts where we can't generate
diff --git a/clang/test/Sema/builtin-get-counted-by.c b/clang/test/Sema/builtin-get-counted-by.c
index 6dcb1a0ab73754..898a4702950ec0 100644
--- a/clang/test/Sema/builtin-get-counted-by.c
+++ b/clang/test/Sema/builtin-get-counted-by.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c99 -fsyntax-only -verify %s
struct fam_struct {
int x;
@@ -26,3 +26,42 @@ void test1(int size) {
__builtin_get_counted_by(); // expected-error {{too few arguments to function call, expected 1, have 0}}
__builtin_get_counted_by(p->array, p->x, p->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
}
+
+struct char_count {
+ char count;
+ int array[] __attribute__((counted_by(count)));
+} *cp;
+
+struct short_count {
+ short count;
+ int array[] __attribute__((counted_by(count)));
+} *sp;
+
+struct int_count {
+ int count;
+ int array[] __attribute__((counted_by(count)));
+} *ip;
+
+struct unsigned_count {
+ unsigned count;
+ int array[] __attribute__((counted_by(count)));
+} *up;
+
+struct long_count {
+ long count;
+ int array[] __attribute__((counted_by(count)));
+} *lp;
+
+struct unsigned_long_count {
+ unsigned long count;
+ int array[] __attribute__((counted_by(count)));
+} *ulp;
+
+void test2(void) {
+ _Static_assert(_Generic(__builtin_get_counted_by(cp->array), char * : 1, default : 0) == 1, "wrong return type");
+ _Static_assert(_Generic(__builtin_get_counted_by(sp->array), short * : 1, default : 0) == 1, "wrong return type");
+ _Static_assert(_Generic(__builtin_get_counted_by(ip->array), int * : 1, default : 0) == 1, "wrong return type");
+ _Static_assert(_Generic(__builtin_get_counted_by(up->array), unsigned int * : 1, default : 0) == 1, "wrong return type");
+ _Static_assert(_Generic(__builtin_get_counted_by(lp->array), long * : 1, default : 0) == 1, "wrong return type");
+ _Static_assert(_Generic(__builtin_get_counted_by(ulp->array), unsigned long * : 1, default : 0) == 1, "wrong return type");
+}
>From 0f42e5d82ed93987d638681218094a95861fa678 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 21 Aug 2024 15:41:06 -0700
Subject: [PATCH 19/59] Remove unrelated change
---
clang/include/clang/AST/Expr.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index b00f9dab02a29e..466c65a9685ad3 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -537,8 +537,8 @@ class Expr : public ValueStmt {
/// semantically correspond to a bool.
bool isKnownToHaveBooleanValue(bool Semantic = true) const;
- /// isFlexibleArrayMemberLike - Check whether this array fits the idiom of a
- /// flexible array member, depending on the value of -fstrict-flex-array.
+ /// Check whether this array fits the idiom of a flexible array member,
+ /// depending on the value of -fstrict-flex-array.
/// When IgnoreTemplateOrMacroSubstitution is set, it doesn't consider sizes
/// resulting from the substitution of a macro or a template as special sizes.
bool isFlexibleArrayMemberLike(
>From 751a55d2a80535ec616a355b18aac0c066712989 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 21 Aug 2024 15:58:24 -0700
Subject: [PATCH 20/59] Use MemberExpr::Create instead of
MemberExpr::CreateImplicit.
---
clang/lib/CodeGen/CGBuiltin.cpp | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index d9c37296a404e3..ef6a4ba1b74e4b 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3712,9 +3712,21 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
ME->getMemberDecl()->getType()->isCountAttributedType()) {
- const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
- if (const FieldDecl *CountFD = FAMDecl->findCountedByField())
- Result = GetCountedByFieldExprGEP(ME, FAMDecl, CountFD);
+ FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
+ if (FieldDecl *CountFD = FAMDecl->findCountedByField()) {
+ QualType CountTy = CountFD->getType();
+
+ MemberExpr *NewME = MemberExpr::Create(
+ Ctx, ME->getBase(), ME->isArrow(), ME->getOperatorLoc(),
+ ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), CountFD,
+ ME->getFoundDecl(),
+ DeclarationNameInfo(CountFD->getDeclName(),
+ CountFD->getLocation()),
+ nullptr, CountTy, VK_PRValue, OK_Ordinary, ME->isNonOdrUse());
+ Result = EmitScalarExpr(UnaryOperator::Create(
+ Ctx, NewME, UO_AddrOf, Ctx.getPointerType(CountTy), VK_LValue,
+ OK_Ordinary, SourceLocation(), false, FPOptionsOverride()));
+ }
}
}
>From 53272cf19b999807279d0a2f60da69f54e32d1a6 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 21 Aug 2024 16:00:42 -0700
Subject: [PATCH 21/59] Regenerate
---
clang/test/CodeGen/builtin-get-counted-by.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/test/CodeGen/builtin-get-counted-by.c b/clang/test/CodeGen/builtin-get-counted-by.c
index 8209db6a77111e..6f2796850947d4 100644
--- a/clang/test/CodeGen/builtin-get-counted-by.c
+++ b/clang/test/CodeGen/builtin-get-counted-by.c
@@ -16,8 +16,8 @@ struct s {
// X86_64-NEXT: [[ADD:%.*]] = add nsw i64 [[MUL]], 4
// X86_64-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3:[0-9]+]]
// X86_64-NEXT: [[CONV1:%.*]] = trunc i32 [[SIZE]] to i16
-// X86_64-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 2
-// X86_64-NEXT: store i16 [[CONV1]], ptr [[DOT_COUNTED_BY_GEP]], align 2, !tbaa [[TBAA2:![0-9]+]]
+// X86_64-NEXT: [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 2
+// X86_64-NEXT: store i16 [[CONV1]], ptr [[COUNT]], align 2, !tbaa [[TBAA2:![0-9]+]]
// X86_64-NEXT: ret ptr [[CALL]]
//
// I386-LABEL: define dso_local noalias noundef ptr @test1(
@@ -27,8 +27,8 @@ struct s {
// I386-NEXT: [[ADD:%.*]] = add i32 [[MUL]], 4
// I386-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3:[0-9]+]]
// I386-NEXT: [[CONV:%.*]] = trunc i32 [[SIZE]] to i16
-// I386-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i32 2
-// I386-NEXT: store i16 [[CONV]], ptr [[DOT_COUNTED_BY_GEP]], align 2, !tbaa [[TBAA3:![0-9]+]]
+// I386-NEXT: [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i32 2
+// I386-NEXT: store i16 [[CONV]], ptr [[COUNT]], align 2, !tbaa [[TBAA3:![0-9]+]]
// I386-NEXT: ret ptr [[CALL]]
//
struct s *test1(int size) {
>From ecda8e07940c2bb505bcf20d6b3c88b698934679 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 21 Aug 2024 16:19:26 -0700
Subject: [PATCH 22/59] Add -W flag for warning.
---
clang/include/clang/Basic/DiagnosticGroups.td | 4 ++++
clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 ++-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 72eada50a56cc9..e27a94a623fea2 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1482,6 +1482,10 @@ def NoDeref : DiagGroup<"noderef">;
def BoundsSafetyCountedByEltTyUnknownSize :
DiagGroup<"bounds-safety-counted-by-elt-type-unknown-size">;
+// counted_by warnings
+def CountedByAttribute
+ : DiagGroup<"get-counted-by-side-effects">;
+
// A group for cross translation unit static analysis related warnings.
def CrossTU : DiagGroup<"ctu">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index aa610188c06424..270bcdc56f996f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6655,7 +6655,8 @@ def warn_counted_by_attr_elt_type_unknown_size :
def err_builtin_get_counted_by_must_be_flex_array_member : Error<
"'__builtin_get_counted_by' argument must reference a flexible array member">;
def warn_builtin_get_counted_by_has_side_effects : Warning<
- "'__builtin_get_counted_by' argument has side-effects that will be discarded">;
+ "'__builtin_get_counted_by' argument has side-effects that will be discarded">,
+ InGroup<CountedByAttribute>;
let CategoryName = "ARC Semantic Issue" in {
>From 612000fb14784eff955c05527460bf883d6aa789 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 22 Aug 2024 16:32:45 -0700
Subject: [PATCH 23/59] Handle any anonymous structs surrounding the flexible
array member and / or count field.
---
clang/lib/CodeGen/CGBuiltin.cpp | 50 +++++++++++++++++++++++++++------
1 file changed, 42 insertions(+), 8 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index ef6a4ba1b74e4b..de602a178fc4da 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3715,16 +3715,50 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
if (FieldDecl *CountFD = FAMDecl->findCountedByField()) {
QualType CountTy = CountFD->getType();
+ SmallVector<NamedDecl *, 2> PathToFD;
+
+ // Reverse through any anonymous structs / unions surrounding the
+ // flexible array member. We'll build any necessary MemberExpr's to
+ // anonymous structs / unions when building a reference to the
+ // 'count' field.
+ RecordDecl *RD = FAMDecl->getParent();
+ DeclContext *DC = RD;
+ for (; DC->isRecord(); DC = DC->getLexicalParent()) {
+ if (!RD->isAnonymousStructOrUnion())
+ break;
+ RD = cast<RecordDecl>(DC);
+ if (auto *Base = dyn_cast<MemberExpr>(ME->getBase()))
+ ME = Base;
+ }
+
+ // See if the count's FieldDecl is within anonymous structs.
+ for (Decl *D : RD->decls()) {
+ if (auto *IFD = dyn_cast<IndirectFieldDecl>(D);
+ IFD && IFD->getAnonField() == CountFD) {
+ PathToFD.insert(PathToFD.begin(), IFD->chain_begin(),
+ IFD->chain_end());
+ break;
+ }
+ }
+
+ if (PathToFD.empty())
+ PathToFD.push_back(CountFD);
+
+ // Build a MemberExpr to the 'count' field. This accounts for any
+ // anonymous structs / unions that may contain the field.
+ bool isArrow = ME->isArrow();
+ Expr *New = ME->getBase();
+ for (NamedDecl *ND : PathToFD) {
+ ValueDecl *VD = cast<ValueDecl>(ND);
+ New = MemberExpr::CreateImplicit(Ctx, New, isArrow, VD,
+ VD->getType(), VK_PRValue,
+ OK_Ordinary);
+ isArrow = false;
+ }
- MemberExpr *NewME = MemberExpr::Create(
- Ctx, ME->getBase(), ME->isArrow(), ME->getOperatorLoc(),
- ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), CountFD,
- ME->getFoundDecl(),
- DeclarationNameInfo(CountFD->getDeclName(),
- CountFD->getLocation()),
- nullptr, CountTy, VK_PRValue, OK_Ordinary, ME->isNonOdrUse());
+ // The result is a pointer to the 'count' field.
Result = EmitScalarExpr(UnaryOperator::Create(
- Ctx, NewME, UO_AddrOf, Ctx.getPointerType(CountTy), VK_LValue,
+ Ctx, New, UO_AddrOf, Ctx.getPointerType(CountTy), VK_LValue,
OK_Ordinary, SourceLocation(), false, FPOptionsOverride()));
}
}
>From b555af9e771317da2cc4e7298855cd3fa324f9ab Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 22 Aug 2024 16:42:58 -0700
Subject: [PATCH 24/59] Add anonymous struct testcase.
---
clang/lib/CodeGen/CGBuiltin.cpp | 5 +-
clang/test/CodeGen/builtin-get-counted-by.c | 71 ++++++++++++++++++---
2 files changed, 65 insertions(+), 11 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index de602a178fc4da..034e7d55003e3b 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3750,9 +3750,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Expr *New = ME->getBase();
for (NamedDecl *ND : PathToFD) {
ValueDecl *VD = cast<ValueDecl>(ND);
- New = MemberExpr::CreateImplicit(Ctx, New, isArrow, VD,
- VD->getType(), VK_PRValue,
- OK_Ordinary);
+ New = MemberExpr::CreateImplicit(
+ Ctx, New, isArrow, VD, VD->getType(), VK_PRValue, OK_Ordinary);
isArrow = false;
}
diff --git a/clang/test/CodeGen/builtin-get-counted-by.c b/clang/test/CodeGen/builtin-get-counted-by.c
index 6f2796850947d4..96d48eb0dce6aa 100644
--- a/clang/test/CodeGen/builtin-get-counted-by.c
+++ b/clang/test/CodeGen/builtin-get-counted-by.c
@@ -2,7 +2,7 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=X86_64
// RUN: %clang_cc1 -triple i386-unknown-unknown -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=I386
-struct s {
+struct a {
char x;
short count;
int array[] __attribute__((counted_by(count)));
@@ -31,21 +31,74 @@ struct s {
// I386-NEXT: store i16 [[CONV]], ptr [[COUNT]], align 2, !tbaa [[TBAA3:![0-9]+]]
// I386-NEXT: ret ptr [[CALL]]
//
-struct s *test1(int size) {
- struct s *p = __builtin_malloc(sizeof(struct s) + sizeof(int) * size);
+struct a *test1(int size) {
+ struct a *p = __builtin_malloc(sizeof(struct a) + sizeof(int) * size);
*__builtin_get_counted_by(p->array) = size;
*__builtin_get_counted_by(&p->array[0]) = size;
return p;
}
-struct z {
+struct b {
+ int _filler;
+ struct {
+ int __filler;
+ struct {
+ int ___filler;
+ struct {
+ char count;
+ };
+ };
+ };
+ struct {
+ int filler_;
+ struct {
+ int filler__;
+ struct {
+ long array[] __attribute__((counted_by(count)));
+ };
+ };
+ };
+};
+
+// X86_64-LABEL: define dso_local noalias noundef ptr @test2(
+// X86_64-SAME: i32 noundef [[SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// X86_64-NEXT: [[ENTRY:.*:]]
+// X86_64-NEXT: [[CONV:%.*]] = sext i32 [[SIZE]] to i64
+// X86_64-NEXT: [[MUL:%.*]] = shl nsw i64 [[CONV]], 2
+// X86_64-NEXT: [[ADD:%.*]] = add nsw i64 [[MUL]], 4
+// X86_64-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3]]
+// X86_64-NEXT: [[CONV1:%.*]] = trunc i32 [[SIZE]] to i8
+// X86_64-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 12
+// X86_64-NEXT: store i8 [[CONV1]], ptr [[TMP0]], align 1, !tbaa [[TBAA6:![0-9]+]]
+// X86_64-NEXT: ret ptr [[CALL]]
+//
+// I386-LABEL: define dso_local noalias noundef ptr @test2(
+// I386-SAME: i32 noundef [[SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// I386-NEXT: [[ENTRY:.*:]]
+// I386-NEXT: [[MUL:%.*]] = shl i32 [[SIZE]], 2
+// I386-NEXT: [[ADD:%.*]] = add i32 [[MUL]], 4
+// I386-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3]]
+// I386-NEXT: [[CONV:%.*]] = trunc i32 [[SIZE]] to i8
+// I386-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i32 12
+// I386-NEXT: store i8 [[CONV]], ptr [[TMP0]], align 1, !tbaa [[TBAA7:![0-9]+]]
+// I386-NEXT: ret ptr [[CALL]]
+//
+struct b *test2(int size) {
+ struct b *p = __builtin_malloc(sizeof(struct a) + sizeof(int) * size);
+
+ *__builtin_get_counted_by(p->array) = size;
+ *__builtin_get_counted_by(&p->array[0]) = size;
+ return p;
+}
+
+struct c {
char x;
short count;
int array[];
};
-// X86_64-LABEL: define dso_local noalias noundef ptr @test2(
+// X86_64-LABEL: define dso_local noalias noundef ptr @test3(
// X86_64-SAME: i32 noundef [[SIZE:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
// X86_64-NEXT: [[ENTRY:.*:]]
// X86_64-NEXT: [[CONV:%.*]] = sext i32 [[SIZE]] to i64
@@ -54,7 +107,7 @@ struct z {
// X86_64-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3]]
// X86_64-NEXT: ret ptr [[CALL]]
//
-// I386-LABEL: define dso_local noalias noundef ptr @test2(
+// I386-LABEL: define dso_local noalias noundef ptr @test3(
// I386-SAME: i32 noundef [[SIZE:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
// I386-NEXT: [[ENTRY:.*:]]
// I386-NEXT: [[MUL:%.*]] = shl i32 [[SIZE]], 2
@@ -62,8 +115,8 @@ struct z {
// I386-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3]]
// I386-NEXT: ret ptr [[CALL]]
//
-struct z *test2(int size) {
- struct z *p = __builtin_malloc(sizeof(struct z) + sizeof(int) * size);
+struct c *test3(int size) {
+ struct c *p = __builtin_malloc(sizeof(struct c) + sizeof(int) * size);
if (__builtin_get_counted_by(&p->array[0]))
*__builtin_get_counted_by(&p->array[0]) = size;
@@ -75,9 +128,11 @@ struct z *test2(int size) {
// X86_64: [[META3]] = !{!"short", [[META4:![0-9]+]], i64 0}
// X86_64: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}
// X86_64: [[META5]] = !{!"Simple C/C++ TBAA"}
+// X86_64: [[TBAA6]] = !{[[META4]], [[META4]], i64 0}
//.
// I386: [[TBAA3]] = !{[[META4:![0-9]+]], [[META4]], i64 0}
// I386: [[META4]] = !{!"short", [[META5:![0-9]+]], i64 0}
// I386: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0}
// I386: [[META6]] = !{!"Simple C/C++ TBAA"}
+// I386: [[TBAA7]] = !{[[META5]], [[META5]], i64 0}
//.
>From 48707ae3cab49d2c382c19e5ed1f6d37f4c88ac6 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 22 Aug 2024 17:09:12 -0700
Subject: [PATCH 25/59] Report a fatal error if we can't find the 'count'
field.
---
clang/lib/CodeGen/CGBuiltin.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 034e7d55003e3b..d2c878ba5c622a 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3759,6 +3759,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Result = EmitScalarExpr(UnaryOperator::Create(
Ctx, New, UO_AddrOf, Ctx.getPointerType(CountTy), VK_LValue,
OK_Ordinary, SourceLocation(), false, FPOptionsOverride()));
+ } else {
+ llvm::report_fatal_error("Cannot find the counted_by 'count' field");
}
}
}
>From 5c778cadad865cdaf0362cd36057f0047f8c8d00 Mon Sep 17 00:00:00 2001
From: Bill Wendling <isanbard at gmail.com>
Date: Thu, 22 Aug 2024 19:14:13 -0700
Subject: [PATCH 26/59] Use 'cast' instead of 'dyn_cast' and default to 'void
*' for the return type.
---
clang/lib/CodeGen/CGBuiltin.cpp | 2 +-
clang/lib/Sema/SemaChecking.cpp | 9 ++++++---
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index d2c878ba5c622a..be679d08451961 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3712,7 +3712,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
ME->getMemberDecl()->getType()->isCountAttributedType()) {
- FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
+ FieldDecl *FAMDecl = cast<FieldDecl>(ME->getMemberDecl());
if (FieldDecl *CountFD = FAMDecl->findCountedByField()) {
QualType CountTy = CountFD->getType();
SmallVector<NamedDecl *, 2> PathToFD;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 8a8e6de9a6866b..3dfbea960cd0fc 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5578,6 +5578,9 @@ bool Sema::BuiltinSetjmp(CallExpr *TheCall) {
}
bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
+ // For simplicity, we support only a limited expressions for the argument.
+ // Specifically 'ptr->array' and '&ptr->array[0]'. This allows us to reject
+ // arguments with complex casting, which really shouldn't be a huge problem.
if (checkArgCount(TheCall, 1))
return true;
@@ -5604,9 +5607,9 @@ bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
Arg = ASE->getBase()->IgnoreParenImpCasts();
}
- // Use 'size_t *' as the default return type. If the argument doesn't have
- // the 'counted_by' attribute, it'll return a "nullptr."
- TheCall->setType(Context.getPointerType(Context.getSizeType()));
+ // Use 'void *' as the default return type. If the argument doesn't have the
+ // 'counted_by' attribute, it'll return a 'nullptr'.
+ TheCall->setType(Context.getPointerType(Context.VoidTy));
if (const MemberExpr *ME = dyn_cast_if_present<MemberExpr>(Arg)) {
if (!ME->isFlexibleArrayMemberLike(
>From a1a6ead1335934cb4e84237c8fd8df2a95e3185f Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 23 Aug 2024 15:05:10 -0700
Subject: [PATCH 27/59] A 'void *' can result in an error message about
assigning to a 'void'. Go back to 'size_t *' as the default return type.
---
clang/lib/Sema/SemaChecking.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 3dfbea960cd0fc..bbc1f207b8c7b1 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5607,9 +5607,9 @@ bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
Arg = ASE->getBase()->IgnoreParenImpCasts();
}
- // Use 'void *' as the default return type. If the argument doesn't have the
- // 'counted_by' attribute, it'll return a 'nullptr'.
- TheCall->setType(Context.getPointerType(Context.VoidTy));
+ // Use 'size_t *' as the default return type. If the argument doesn't have
+ // the 'counted_by' attribute, it'll return a 'nullptr'.
+ TheCall->setType(Context.getPointerType(Context.getSizeType()));
if (const MemberExpr *ME = dyn_cast_if_present<MemberExpr>(Arg)) {
if (!ME->isFlexibleArrayMemberLike(
>From 6b388b5ce07ef6f5ab7ff29ab0e087894e52194e Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Mon, 26 Aug 2024 16:06:23 -0700
Subject: [PATCH 28/59] Add some documentation.
---
clang/docs/LanguageExtensions.rst | 60 +++++++++++++++++++++++++++++++
clang/docs/ReleaseNotes.rst | 20 +++++++++++
2 files changed, 80 insertions(+)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 10232ff41da15a..eb6a5edcf7c871 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3774,6 +3774,66 @@ type-generic alternative to the ``__builtin_clz{,l,ll}`` (respectively
``__builtin_ctz{,l,ll}``) builtins, with support for other integer types, such
as ``unsigned __int128`` and C23 ``unsigned _BitInt(N)``.
+``__builtin_get_counted_by``
+----------------------------
+
+``__builtin_get_counted_by`` returns a pointer to the count field from the
+``counted_by`` attribute.
+
+the argument must be a pointer to a flexible array member. If the argument
+isn't a flexible array member or doesn't have the ``counted_by`` attribute, it
+returns ``(size_t *)0``.
+
+**Syntax**:
+
+.. code-block:: c
+
+ T *__builtin_get_counted_by(void *array)
+
+**Examples**:
+
+.. code-block:: c
+
+ #define alloc(P, FAM, COUNT) ({ \
+ typeof(P) __p = NULL; \
+ __p = malloc(MAX(sizeof(*__p), \
+ sizeof(*__p) + sizeof(*__p->FAM) * COUNT)); \
+ if (__builtin_get_counted_by(__p->FAM)) \
+ *__builtin_get_counted_by(__p->FAM) = COUNT; \
+ __p; \
+ })
+
+**Description**:
+
+the ``__builtin_get_counted_by`` builtin allows the programmer to prevent a
+common error associated with the ``counted_by`` attribute. When using the
+``counted_by`` attribute, the ``count`` field **must** be set before the
+flexible array member can be accessed. Otherwise, the sanitizers may view such
+accesses as false positives. For instance, it's not uncommon for programmers to
+initialize the flexible array before setting the ``count`` field:
+
+.. code-block:: c
+
+ struct s {
+ int dummy;
+ short count;
+ long array[];
+ };
+
+ struct s *ptr = malloc(sizeof(struct s) + sizeof(long) * COUNT);
+
+ for (int i = 0; i < COUNT; ++i)
+ ptr->array[i] = i;
+
+ ptr->count = COUNT;
+
+Enforcing the rule that ``ptr->count = COUNT;`` must occur after every
+allocation of a struct with a flexible array member that has the ``counted_by``
+attribute is prone to failure in large code bases.
+
+This builtin works best with allocators that are implemented via macros (like
+in Linux) where the assignment happens automatically.
+
Multiprecision Arithmetic Builtins
----------------------------------
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4e542ee91a8b36..2af78f1c2261da 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -289,6 +289,26 @@ Non-comprehensive list of changes in this release
as well as declarations.
- ``__builtin_abs`` function can now be used in constant expressions.
+- The new builtin ``__builtin_get_counted_by`` was added. In contexts where the
+ programmer needs access to the ``counted_by`` attribute's field, but it's not
+ available --- e.g. in macros. For instace, it can be used to automatically
+ set the counter during allocation in the Linux kernel:
+
+ .. code-block:: c
+
+ /* A simplified version of Linux allocation macros */
+ #define alloc(PTR, FAM, COUNT) ({ \
+ typeof(P) __p; \
+ size_t __size = sizeof(*P) + sizeof(*P->FAM) * COUNT; \
+ __p = malloc(__size); \
+ if (__builtin_get_counted_by(__p->FAM)) \
+ *__builtin_get_counted_by(__p->FAM) = COUNT; \
+ __p; \
+ })
+
+ The flexible array member (FAM) can now be accessed immediately without causing
+ issues with the sanitizer because the counter is automatically set.
+
New Compiler Flags
------------------
>From 791443b1dabe3857d55a6305e531ca0c1395a7bd Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Tue, 10 Sep 2024 14:58:35 -0700
Subject: [PATCH 29/59] Rename to __builtin_counted_by_ref.
---
clang/docs/LanguageExtensions.rst | 12 ++++----
clang/docs/ReleaseNotes.rst | 6 ++--
clang/include/clang/Basic/Builtins.td | 2 +-
.../clang/Basic/DiagnosticSemaKinds.td | 4 +--
clang/lib/CodeGen/CGBuiltin.cpp | 2 +-
clang/lib/Sema/SemaChecking.cpp | 2 +-
clang/test/CodeGen/builtin-get-counted-by.c | 12 ++++----
clang/test/Sema/builtin-get-counted-by.c | 28 +++++++++----------
8 files changed, 34 insertions(+), 34 deletions(-)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index eb6a5edcf7c871..e584ea51e515c8 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3774,10 +3774,10 @@ type-generic alternative to the ``__builtin_clz{,l,ll}`` (respectively
``__builtin_ctz{,l,ll}``) builtins, with support for other integer types, such
as ``unsigned __int128`` and C23 ``unsigned _BitInt(N)``.
-``__builtin_get_counted_by``
+``__builtin_counted_by_ref``
----------------------------
-``__builtin_get_counted_by`` returns a pointer to the count field from the
+``__builtin_counted_by_ref`` returns a pointer to the count field from the
``counted_by`` attribute.
the argument must be a pointer to a flexible array member. If the argument
@@ -3788,7 +3788,7 @@ returns ``(size_t *)0``.
.. code-block:: c
- T *__builtin_get_counted_by(void *array)
+ T *__builtin_counted_by_ref(void *array)
**Examples**:
@@ -3798,14 +3798,14 @@ returns ``(size_t *)0``.
typeof(P) __p = NULL; \
__p = malloc(MAX(sizeof(*__p), \
sizeof(*__p) + sizeof(*__p->FAM) * COUNT)); \
- if (__builtin_get_counted_by(__p->FAM)) \
- *__builtin_get_counted_by(__p->FAM) = COUNT; \
+ if (__builtin_counted_by_ref(__p->FAM)) \
+ *__builtin_counted_by_ref(__p->FAM) = COUNT; \
__p; \
})
**Description**:
-the ``__builtin_get_counted_by`` builtin allows the programmer to prevent a
+the ``__builtin_counted_by_ref`` builtin allows the programmer to prevent a
common error associated with the ``counted_by`` attribute. When using the
``counted_by`` attribute, the ``count`` field **must** be set before the
flexible array member can be accessed. Otherwise, the sanitizers may view such
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2af78f1c2261da..d63697cd37a86f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -289,7 +289,7 @@ Non-comprehensive list of changes in this release
as well as declarations.
- ``__builtin_abs`` function can now be used in constant expressions.
-- The new builtin ``__builtin_get_counted_by`` was added. In contexts where the
+- The new builtin ``__builtin_counted_by_ref`` was added. In contexts where the
programmer needs access to the ``counted_by`` attribute's field, but it's not
available --- e.g. in macros. For instace, it can be used to automatically
set the counter during allocation in the Linux kernel:
@@ -301,8 +301,8 @@ Non-comprehensive list of changes in this release
typeof(P) __p; \
size_t __size = sizeof(*P) + sizeof(*P->FAM) * COUNT; \
__p = malloc(__size); \
- if (__builtin_get_counted_by(__p->FAM)) \
- *__builtin_get_counted_by(__p->FAM) = COUNT; \
+ if (__builtin_counted_by_ref(__p->FAM)) \
+ *__builtin_counted_by_ref(__p->FAM) = COUNT; \
__p; \
})
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 5f9aded810d982..57959fb0f30454 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4916,7 +4916,7 @@ def ArithmeticFence : LangBuiltin<"ALL_LANGUAGES"> {
}
def GetCountedBy : Builtin {
- let Spellings = ["__builtin_get_counted_by"];
+ let Spellings = ["__builtin_counted_by_ref"];
let Attributes = [NoThrow, CustomTypeChecking];
let Prototype = "int(...)";
}
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 270bcdc56f996f..cfcbc8bc588435 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6653,9 +6653,9 @@ def warn_counted_by_attr_elt_type_unknown_size :
InGroup<BoundsSafetyCountedByEltTyUnknownSize>;
def err_builtin_get_counted_by_must_be_flex_array_member : Error<
- "'__builtin_get_counted_by' argument must reference a flexible array member">;
+ "'__builtin_counted_by_ref' argument must reference a flexible array member">;
def warn_builtin_get_counted_by_has_side_effects : Warning<
- "'__builtin_get_counted_by' argument has side-effects that will be discarded">,
+ "'__builtin_counted_by_ref' argument has side-effects that will be discarded">,
InGroup<CountedByAttribute>;
let CategoryName = "ARC Semantic Issue" in {
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index be679d08451961..b6b30beede8c29 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3692,7 +3692,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(emitBuiltinObjectSize(E->getArg(0), Type, ResType,
/*EmittedE=*/nullptr, IsDynamic));
}
- case Builtin::BI__builtin_get_counted_by: {
+ case Builtin::BI__builtin_counted_by_ref: {
llvm::Value *Result = llvm::ConstantPointerNull::get(
cast<llvm::PointerType>(ConvertType(E->getType())));
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index bbc1f207b8c7b1..8b61ed3523f552 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2971,7 +2971,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
}
break;
}
- case Builtin::BI__builtin_get_counted_by:
+ case Builtin::BI__builtin_counted_by_ref:
if (BuiltinGetCountedBy(TheCall))
return ExprError();
break;
diff --git a/clang/test/CodeGen/builtin-get-counted-by.c b/clang/test/CodeGen/builtin-get-counted-by.c
index 96d48eb0dce6aa..3d4c042e5731ea 100644
--- a/clang/test/CodeGen/builtin-get-counted-by.c
+++ b/clang/test/CodeGen/builtin-get-counted-by.c
@@ -34,8 +34,8 @@ struct a {
struct a *test1(int size) {
struct a *p = __builtin_malloc(sizeof(struct a) + sizeof(int) * size);
- *__builtin_get_counted_by(p->array) = size;
- *__builtin_get_counted_by(&p->array[0]) = size;
+ *__builtin_counted_by_ref(p->array) = size;
+ *__builtin_counted_by_ref(&p->array[0]) = size;
return p;
}
@@ -87,8 +87,8 @@ struct b {
struct b *test2(int size) {
struct b *p = __builtin_malloc(sizeof(struct a) + sizeof(int) * size);
- *__builtin_get_counted_by(p->array) = size;
- *__builtin_get_counted_by(&p->array[0]) = size;
+ *__builtin_counted_by_ref(p->array) = size;
+ *__builtin_counted_by_ref(&p->array[0]) = size;
return p;
}
@@ -118,8 +118,8 @@ struct c {
struct c *test3(int size) {
struct c *p = __builtin_malloc(sizeof(struct c) + sizeof(int) * size);
- if (__builtin_get_counted_by(&p->array[0]))
- *__builtin_get_counted_by(&p->array[0]) = size;
+ if (__builtin_counted_by_ref(&p->array[0]))
+ *__builtin_counted_by_ref(&p->array[0]) = size;
return p;
}
diff --git a/clang/test/Sema/builtin-get-counted-by.c b/clang/test/Sema/builtin-get-counted-by.c
index 898a4702950ec0..09547120f330e7 100644
--- a/clang/test/Sema/builtin-get-counted-by.c
+++ b/clang/test/Sema/builtin-get-counted-by.c
@@ -15,16 +15,16 @@ struct non_fam_struct {
void test1(int size) {
int i = 0;
- *__builtin_get_counted_by(p->array) = size; // ok
- *__builtin_get_counted_by(&p->array[i]) = size; // ok
+ *__builtin_counted_by_ref(p->array) = size; // ok
+ *__builtin_counted_by_ref(&p->array[i]) = size; // ok
- *__builtin_get_counted_by(q->array) = size // expected-error {{'__builtin_get_counted_by' argument must reference a flexible array member}}
- *__builtin_get_counted_by(&q->array[0]) = size; // expected-error {{'__builtin_get_counted_by' argument must reference a flexible array member}}
- __builtin_get_counted_by(p->x); // expected-error {{'__builtin_get_counted_by' argument must reference a flexible array member}}
- __builtin_get_counted_by(&p->array[i++]); // expected-warning {{'__builtin_get_counted_by' argument has side-effects that will be discarded}}
+ *__builtin_counted_by_ref(q->array) = size // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+ *__builtin_counted_by_ref(&q->array[0]) = size; // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+ __builtin_counted_by_ref(p->x); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+ __builtin_counted_by_ref(&p->array[i++]); // expected-warning {{'__builtin_counted_by_ref' argument has side-effects that will be discarded}}
- __builtin_get_counted_by(); // expected-error {{too few arguments to function call, expected 1, have 0}}
- __builtin_get_counted_by(p->array, p->x, p->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
+ __builtin_counted_by_ref(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+ __builtin_counted_by_ref(p->array, p->x, p->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
}
struct char_count {
@@ -58,10 +58,10 @@ struct unsigned_long_count {
} *ulp;
void test2(void) {
- _Static_assert(_Generic(__builtin_get_counted_by(cp->array), char * : 1, default : 0) == 1, "wrong return type");
- _Static_assert(_Generic(__builtin_get_counted_by(sp->array), short * : 1, default : 0) == 1, "wrong return type");
- _Static_assert(_Generic(__builtin_get_counted_by(ip->array), int * : 1, default : 0) == 1, "wrong return type");
- _Static_assert(_Generic(__builtin_get_counted_by(up->array), unsigned int * : 1, default : 0) == 1, "wrong return type");
- _Static_assert(_Generic(__builtin_get_counted_by(lp->array), long * : 1, default : 0) == 1, "wrong return type");
- _Static_assert(_Generic(__builtin_get_counted_by(ulp->array), unsigned long * : 1, default : 0) == 1, "wrong return type");
+ _Static_assert(_Generic(__builtin_counted_by_ref(cp->array), char * : 1, default : 0) == 1, "wrong return type");
+ _Static_assert(_Generic(__builtin_counted_by_ref(sp->array), short * : 1, default : 0) == 1, "wrong return type");
+ _Static_assert(_Generic(__builtin_counted_by_ref(ip->array), int * : 1, default : 0) == 1, "wrong return type");
+ _Static_assert(_Generic(__builtin_counted_by_ref(up->array), unsigned int * : 1, default : 0) == 1, "wrong return type");
+ _Static_assert(_Generic(__builtin_counted_by_ref(lp->array), long * : 1, default : 0) == 1, "wrong return type");
+ _Static_assert(_Generic(__builtin_counted_by_ref(ulp->array), unsigned long * : 1, default : 0) == 1, "wrong return type");
}
>From 768e7b1573f66555c2cf84457030162493afedc8 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Tue, 10 Sep 2024 15:09:57 -0700
Subject: [PATCH 30/59] Rename method to reflect new builtin name.
---
clang/include/clang/Basic/Builtins.td | 2 +-
clang/include/clang/Sema/Sema.h | 2 +-
clang/lib/Sema/SemaChecking.cpp | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 57959fb0f30454..3ae6f190dc56f0 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4915,7 +4915,7 @@ def ArithmeticFence : LangBuiltin<"ALL_LANGUAGES"> {
let Prototype = "void(...)";
}
-def GetCountedBy : Builtin {
+def CountedByRef : Builtin {
let Spellings = ["__builtin_counted_by_ref"];
let Attributes = [NoThrow, CustomTypeChecking];
let Prototype = "int(...)";
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 7dc2a39dc3a4db..742e0565e50887 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2510,7 +2510,7 @@ class Sema final : public SemaBase {
bool BuiltinNonDeterministicValue(CallExpr *TheCall);
- bool BuiltinGetCountedBy(CallExpr *TheCall);
+ bool BuiltinCountedByRef(CallExpr *TheCall);
// Matrix builtin handling.
ExprResult BuiltinMatrixTranspose(CallExpr *TheCall, ExprResult CallResult);
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 8b61ed3523f552..3757f75ff5a556 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2972,7 +2972,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
break;
}
case Builtin::BI__builtin_counted_by_ref:
- if (BuiltinGetCountedBy(TheCall))
+ if (BuiltinCountedByRef(TheCall))
return ExprError();
break;
}
@@ -5577,7 +5577,7 @@ bool Sema::BuiltinSetjmp(CallExpr *TheCall) {
return false;
}
-bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
+bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
// For simplicity, we support only a limited expressions for the argument.
// Specifically 'ptr->array' and '&ptr->array[0]'. This allows us to reject
// arguments with complex casting, which really shouldn't be a huge problem.
>From 4111cc0c10fbf45d6346b793848a0ec2eb8ae0c7 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 11 Sep 2024 14:18:00 -0700
Subject: [PATCH 31/59] Emit an error if the 'count' reference is assigned to a
variable, used as a function arg, or in a return.
---
clang/docs/LanguageExtensions.rst | 17 ++++++++++-------
.../include/clang/Basic/DiagnosticSemaKinds.td | 9 +++++++--
clang/lib/Sema/SemaChecking.cpp | 6 +++---
clang/lib/Sema/SemaExpr.cpp | 9 +++++++++
...et-counted-by.c => builtin-counted-by-ref.c} | 0
...et-counted-by.c => builtin-counted-by-ref.c} | 10 +++++++++-
6 files changed, 38 insertions(+), 13 deletions(-)
rename clang/test/CodeGen/{builtin-get-counted-by.c => builtin-counted-by-ref.c} (100%)
rename clang/test/Sema/{builtin-get-counted-by.c => builtin-counted-by-ref.c} (76%)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index e584ea51e515c8..c9915a16480c98 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3780,9 +3780,9 @@ as ``unsigned __int128`` and C23 ``unsigned _BitInt(N)``.
``__builtin_counted_by_ref`` returns a pointer to the count field from the
``counted_by`` attribute.
-the argument must be a pointer to a flexible array member. If the argument
-isn't a flexible array member or doesn't have the ``counted_by`` attribute, it
-returns ``(size_t *)0``.
+The argument must be a pointer to a flexible array member. If the argument
+isn't a flexible array member or doesn't have the ``counted_by`` attribute, the
+builtin returns ``(size_t *)0``.
**Syntax**:
@@ -3805,7 +3805,7 @@ returns ``(size_t *)0``.
**Description**:
-the ``__builtin_counted_by_ref`` builtin allows the programmer to prevent a
+The ``__builtin_counted_by_ref`` builtin allows the programmer to prevent a
common error associated with the ``counted_by`` attribute. When using the
``counted_by`` attribute, the ``count`` field **must** be set before the
flexible array member can be accessed. Otherwise, the sanitizers may view such
@@ -3829,10 +3829,13 @@ initialize the flexible array before setting the ``count`` field:
Enforcing the rule that ``ptr->count = COUNT;`` must occur after every
allocation of a struct with a flexible array member that has the ``counted_by``
-attribute is prone to failure in large code bases.
+attribute is prone to failure in large code bases. This builtin mitigates this
+for allocators (like in Linux) that are implemented via macros where the
+assignment happens automatically.
-This builtin works best with allocators that are implemented via macros (like
-in Linux) where the assignment happens automatically.
+**Note: The value returned by ``__builtin_counted_by_ref`` cannot be assigned
+to a variable or passed into a function. Doing so violates bounds safety
+conventions.**
Multiprecision Arithmetic Builtins
----------------------------------
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index cfcbc8bc588435..f732c11a4f461e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6652,9 +6652,14 @@ def warn_counted_by_attr_elt_type_unknown_size :
Warning<err_counted_by_attr_pointee_unknown_size.Summary>,
InGroup<BoundsSafetyCountedByEltTyUnknownSize>;
-def err_builtin_get_counted_by_must_be_flex_array_member : Error<
+// __builtin_counted_by_ref diagnostics:
+def err_builtin_counted_by_ref_must_be_flex_array_member : Error<
"'__builtin_counted_by_ref' argument must reference a flexible array member">;
-def warn_builtin_get_counted_by_has_side_effects : Warning<
+def err_builtin_counted_by_ref_cannot_leak_reference : Error<
+ "value returned by '__builtin_counted_by_ref' cannot be assigned to a "
+ "variable or used as a function argument">;
+
+def warn_builtin_counted_by_ref_has_side_effects : Warning<
"'__builtin_counted_by_ref' argument has side-effects that will be discarded">,
InGroup<CountedByAttribute>;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 3757f75ff5a556..273d4a1ee37816 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5591,11 +5591,11 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
const Expr *Arg = ArgRes.get()->IgnoreParenImpCasts();
if (!isa<PointerType>(Arg->getType()) && !Arg->getType()->isArrayType())
return Diag(Arg->getBeginLoc(),
- diag::err_builtin_get_counted_by_must_be_flex_array_member)
+ diag::err_builtin_counted_by_ref_must_be_flex_array_member)
<< Arg->getSourceRange();
if (Arg->HasSideEffects(Context))
- Diag(Arg->getBeginLoc(), diag::warn_builtin_get_counted_by_has_side_effects)
+ Diag(Arg->getBeginLoc(), diag::warn_builtin_counted_by_ref_has_side_effects)
<< Arg->getSourceRange();
// See if we have something like '&ptr->fam[0]`.
@@ -5615,7 +5615,7 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
if (!ME->isFlexibleArrayMemberLike(
Context, getLangOpts().getStrictFlexArraysLevel()))
return Diag(Arg->getBeginLoc(),
- diag::err_builtin_get_counted_by_must_be_flex_array_member)
+ diag::err_builtin_counted_by_ref_must_be_flex_array_member)
<< Arg->getSourceRange();
if (ME->getMemberDecl()->getType()->isCountAttributedType())
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 7f3cff1054aeed..e4688bb0f74abc 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -9187,6 +9187,15 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
LHSType = Context.getCanonicalType(LHSType).getUnqualifiedType();
RHSType = Context.getCanonicalType(RHSType).getUnqualifiedType();
+ // __builtin_counted_by_ref cannot be assigned to a variable, used in
+ // function call, or in a return.
+ if (auto *CE = dyn_cast<CallExpr>(RHS.get())) {
+ if (FunctionDecl *FDecl = CE->getDirectCallee();
+ FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_counted_by_ref)
+ Diag(RHS.get()->getExprLoc(),
+ diag::err_builtin_counted_by_ref_cannot_leak_reference);
+ }
+
// Common case: no conversion required.
if (LHSType == RHSType) {
Kind = CK_NoOp;
diff --git a/clang/test/CodeGen/builtin-get-counted-by.c b/clang/test/CodeGen/builtin-counted-by-ref.c
similarity index 100%
rename from clang/test/CodeGen/builtin-get-counted-by.c
rename to clang/test/CodeGen/builtin-counted-by-ref.c
diff --git a/clang/test/Sema/builtin-get-counted-by.c b/clang/test/Sema/builtin-counted-by-ref.c
similarity index 76%
rename from clang/test/Sema/builtin-get-counted-by.c
rename to clang/test/Sema/builtin-counted-by-ref.c
index 09547120f330e7..c9f6cc32cab395 100644
--- a/clang/test/Sema/builtin-get-counted-by.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -12,8 +12,14 @@ struct non_fam_struct {
short count;
} *q;
-void test1(int size) {
+void g(char *);
+
+void *test1(int size) {
int i = 0;
+ char *ref = __builtin_counted_by_ref(p->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+
+ ref = __builtin_counted_by_ref(p->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+ g(__builtin_counted_by_ref(p->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
*__builtin_counted_by_ref(p->array) = size; // ok
*__builtin_counted_by_ref(&p->array[i]) = size; // ok
@@ -25,6 +31,8 @@ void test1(int size) {
__builtin_counted_by_ref(); // expected-error {{too few arguments to function call, expected 1, have 0}}
__builtin_counted_by_ref(p->array, p->x, p->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
+
+ return __builtin_counted_by_ref(p->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
}
struct char_count {
>From d897d09e5889800dc480f554ca76f8885d75c336 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 11 Sep 2024 15:34:30 -0700
Subject: [PATCH 32/59] Ignore paren casts.
---
clang/lib/Sema/SemaExpr.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index e4688bb0f74abc..f5d67e8b0bdceb 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -9189,7 +9189,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// __builtin_counted_by_ref cannot be assigned to a variable, used in
// function call, or in a return.
- if (auto *CE = dyn_cast<CallExpr>(RHS.get())) {
+ if (auto *CE = dyn_cast<CallExpr>(RHS.get()->IgnoreParenCasts())) {
if (FunctionDecl *FDecl = CE->getDirectCallee();
FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_counted_by_ref)
Diag(RHS.get()->getExprLoc(),
>From 4f1c3133d4543444f12c4e3cab62a1345c7e3449 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 11 Sep 2024 16:11:14 -0700
Subject: [PATCH 33/59] Don't allow __builtin_counted_by_ref in complex
expressions.
---
clang/lib/Sema/SemaExpr.cpp | 26 ++++++++++++++++++------
clang/test/Sema/builtin-counted-by-ref.c | 1 +
2 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index f5d67e8b0bdceb..866271df8b8f82 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -9189,12 +9189,26 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// __builtin_counted_by_ref cannot be assigned to a variable, used in
// function call, or in a return.
- if (auto *CE = dyn_cast<CallExpr>(RHS.get()->IgnoreParenCasts())) {
- if (FunctionDecl *FDecl = CE->getDirectCallee();
- FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_counted_by_ref)
- Diag(RHS.get()->getExprLoc(),
- diag::err_builtin_counted_by_ref_cannot_leak_reference);
- }
+ auto FindBuiltinCountedByRefExpr = [](Expr *E) {
+ struct BuiltinCountedByRefVisitor
+ : public RecursiveASTVisitor<BuiltinCountedByRefVisitor> {
+ CallExpr *TheCall = nullptr;
+ bool VisitCallExpr(CallExpr *E) {
+ if (FunctionDecl *FD = E->getDirectCallee())
+ if (FD->getBuiltinID() == Builtin::BI__builtin_counted_by_ref) {
+ TheCall = E;
+ return true;
+ }
+ return false;
+ }
+ } V;
+ V.TraverseStmt(E);
+ return V.TheCall;
+ };
+
+ if (auto *CE = FindBuiltinCountedByRefExpr(RHS.get()))
+ Diag(RHS.get()->getExprLoc(),
+ diag::err_builtin_counted_by_ref_cannot_leak_reference);
// Common case: no conversion required.
if (LHSType == RHSType) {
diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index c9f6cc32cab395..3f358bf9523120 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -19,6 +19,7 @@ void *test1(int size) {
char *ref = __builtin_counted_by_ref(p->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
ref = __builtin_counted_by_ref(p->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+ ref = (char *)(int *)(42 + &*__builtin_counted_by_ref(p->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
g(__builtin_counted_by_ref(p->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
*__builtin_counted_by_ref(p->array) = size; // ok
>From 7002f50b19dedf201c6deda3593e2252f744c256 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 11 Sep 2024 16:16:25 -0700
Subject: [PATCH 34/59] Add test case for pointers.
---
clang/test/Sema/builtin-counted-by-ref.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index 3f358bf9523120..d41a886addef45 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -8,6 +8,7 @@ struct fam_struct {
struct non_fam_struct {
char x;
+ long *pointer;
int array[42];
short count;
} *q;
@@ -27,6 +28,8 @@ void *test1(int size) {
*__builtin_counted_by_ref(q->array) = size // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
*__builtin_counted_by_ref(&q->array[0]) = size; // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+ *__builtin_counted_by_ref(q->pointer) = size; // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+ *__builtin_counted_by_ref(&q->pointer[0]) = size; // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
__builtin_counted_by_ref(p->x); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
__builtin_counted_by_ref(&p->array[i++]); // expected-warning {{'__builtin_counted_by_ref' argument has side-effects that will be discarded}}
>From 7ef517b6d27b7d78d04c049a932b0229bbf1ef0e Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 12 Sep 2024 13:29:01 -0700
Subject: [PATCH 35/59] Add SourceRange to the diagnostic.
---
clang/lib/Sema/SemaExpr.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 866271df8b8f82..a59c00b7678521 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -9207,8 +9207,9 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
};
if (auto *CE = FindBuiltinCountedByRefExpr(RHS.get()))
- Diag(RHS.get()->getExprLoc(),
- diag::err_builtin_counted_by_ref_cannot_leak_reference);
+ Diag(CE->getExprLoc(),
+ diag::err_builtin_counted_by_ref_cannot_leak_reference)
+ << CE->getSourceRange();
// Common case: no conversion required.
if (LHSType == RHSType) {
>From 19e00f1f2f75060c9c9049ea7bb63ec0fca3622d Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 12 Sep 2024 18:08:25 -0700
Subject: [PATCH 36/59] Check that __builtin_counted_by_ref isn't used on the
LHS by a complex equation.
---
.../clang/Basic/DiagnosticSemaKinds.td | 3 ++
clang/lib/Sema/SemaExpr.cpp | 37 ++++++++++++++++++-
clang/test/Sema/builtin-counted-by-ref.c | 3 ++
3 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f732c11a4f461e..cb8660ada25664 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6658,6 +6658,9 @@ def err_builtin_counted_by_ref_must_be_flex_array_member : Error<
def err_builtin_counted_by_ref_cannot_leak_reference : Error<
"value returned by '__builtin_counted_by_ref' cannot be assigned to a "
"variable or used as a function argument">;
+def err_builtin_counted_by_ref_invalid_lhs_use : Error<
+ "value returned by '__builtin_counted_by_ref' cannot be used in "
+ "%select{array subscript|binary}0 expression">;
def warn_builtin_counted_by_ref_has_side_effects : Warning<
"'__builtin_counted_by_ref' argument has side-effects that will be discarded">,
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index a59c00b7678521..36f9a4f87e9d07 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -9205,7 +9205,6 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
V.TraverseStmt(E);
return V.TheCall;
};
-
if (auto *CE = FindBuiltinCountedByRefExpr(RHS.get()))
Diag(CE->getExprLoc(),
diag::err_builtin_counted_by_ref_cannot_leak_reference)
@@ -13759,6 +13758,42 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
ConvTy = CheckAssignmentConstraints(Loc, LHSType, RHSType);
}
+ // __builtin_counted_by_ref can't be used in a binary expression or array
+ // subscript on the LHS.
+ int DiagOption = -1;
+ auto FindBuiltinCountedByRefExpr = [&](Expr *E) {
+ struct BuiltinCountedByRefVisitor
+ : public RecursiveASTVisitor<BuiltinCountedByRefVisitor> {
+ CallExpr *TheCall = nullptr;
+ bool InvalidUse = false;
+ int Option = -1;
+
+ bool VisitCallExpr(CallExpr *E) {
+ if (FunctionDecl *FD = E->getDirectCallee();
+ FD && FD->getBuiltinID() == Builtin::BI__builtin_counted_by_ref)
+ TheCall = E;
+ return false;
+ }
+
+ bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
+ InvalidUse = true;
+ Option = 0; // report 'array expression' in diagnostic.
+ return VisitStmt(E->getBase()) || VisitStmt(E->getIdx());
+ }
+ bool VisitBinaryOperator(BinaryOperator *E) {
+ InvalidUse = true;
+ Option = 1; // report 'binary expression' in diagnostic.
+ return VisitStmt(E->getLHS()) || VisitStmt(E->getRHS());
+ }
+ } V;
+ V.TraverseStmt(E);
+ DiagOption = V.Option;
+ return V.InvalidUse ? V.TheCall : nullptr;
+ };
+ if (auto *CE = FindBuiltinCountedByRefExpr(LHSExpr))
+ Diag(CE->getExprLoc(), diag::err_builtin_counted_by_ref_invalid_lhs_use)
+ << DiagOption << CE->getSourceRange();
+
if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType, RHS.get(),
AssignmentAction::Assigning))
return QualType();
diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index d41a886addef45..10938ed4c59bb1 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -23,6 +23,9 @@ void *test1(int size) {
ref = (char *)(int *)(42 + &*__builtin_counted_by_ref(p->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
g(__builtin_counted_by_ref(p->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+ *(__builtin_counted_by_ref(p->array) + 4) = 37; // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in binary expression}}
+ __builtin_counted_by_ref(p->array)[3] = 37; // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in array subscript expression}}
+
*__builtin_counted_by_ref(p->array) = size; // ok
*__builtin_counted_by_ref(&p->array[i]) = size; // ok
>From 8f6ef2847cbb36709db3cc14c63d19bb89c0570f Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 13 Sep 2024 20:16:19 +0000
Subject: [PATCH 37/59] Update clang/include/clang/Basic/DiagnosticSemaKinds.td
make the grammar better.
Co-authored-by: Aaron Ballman <aaron at aaronballman.com>
---
clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index cb8660ada25664..637cf13ad53f4d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6660,7 +6660,7 @@ def err_builtin_counted_by_ref_cannot_leak_reference : Error<
"variable or used as a function argument">;
def err_builtin_counted_by_ref_invalid_lhs_use : Error<
"value returned by '__builtin_counted_by_ref' cannot be used in "
- "%select{array subscript|binary}0 expression">;
+ "%select{an array subscript|a binary}0 expression">;
def warn_builtin_counted_by_ref_has_side_effects : Warning<
"'__builtin_counted_by_ref' argument has side-effects that will be discarded">,
>From cd65acca21b260cdfd08d58f5ce4b384783d4114 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 19 Sep 2024 14:47:21 -0700
Subject: [PATCH 38/59] Add a flag indicating that the 'MemberExpr' was once a
call to '__builtin_counted_by_ref' so that we can issue proper diagnostics.
---
clang/include/clang/AST/Decl.h | 13 +++-
clang/lib/Sema/SemaBoundsSafety.cpp | 2 +
clang/lib/Sema/SemaChecking.cpp | 70 +++++++++++++++++++--
clang/lib/Sema/SemaExpr.cpp | 42 ++++++-------
clang/test/CodeGen/builtin-counted-by-ref.c | 4 +-
clang/test/Sema/builtin-counted-by-ref.c | 62 +++++++++---------
6 files changed, 131 insertions(+), 62 deletions(-)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 7ff35d73df5997..96ac7799fb05c0 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3059,9 +3059,11 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
unsigned BitField : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned Mutable : 1;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned IsBoundsSafetyCounter : 1;
LLVM_PREFERRED_TYPE(InitStorageKind)
unsigned StorageKind : 2;
- mutable unsigned CachedFieldIndex : 28;
+ mutable unsigned CachedFieldIndex : 27;
/// If this is a bitfield with a default member initializer, this
/// structure is used to represent the two expressions.
@@ -3096,8 +3098,8 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
InClassInitStyle InitStyle)
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), BitField(false),
- Mutable(Mutable), StorageKind((InitStorageKind)InitStyle),
- CachedFieldIndex(0), Init() {
+ Mutable(Mutable), IsBoundsSafetyCounter(false),
+ StorageKind((InitStorageKind)InitStyle), CachedFieldIndex(0), Init() {
if (BW)
setBitWidth(BW);
}
@@ -3127,6 +3129,11 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
/// Determines whether this is an unnamed bitfield.
bool isUnnamedBitField() const { return isBitField() && !getDeclName(); }
+ /// Returns true if this field decl is referenced by one of the bounds
+ /// safety counter attributes.
+ bool isBoundsSafetyCounter() const { return IsBoundsSafetyCounter; }
+ void setBoundsSafetyCounter(bool V) { IsBoundsSafetyCounter = V; }
+
/// Determines whether this field is a
/// representative for an anonymous struct or union. Such fields are
/// unnamed and are implicitly generated by the implementation to
diff --git a/clang/lib/Sema/SemaBoundsSafety.cpp b/clang/lib/Sema/SemaBoundsSafety.cpp
index d63a2389ea11de..7d39cbd39c98ed 100644
--- a/clang/lib/Sema/SemaBoundsSafety.cpp
+++ b/clang/lib/Sema/SemaBoundsSafety.cpp
@@ -162,6 +162,8 @@ bool Sema::CheckCountedByAttrOnField(FieldDecl *FD, Expr *E, bool CountInBytes,
return true;
}
+ CountFD->setBoundsSafetyCounter(true);
+
if (FD->getParent() != CountFD->getParent()) {
if (CountFD->getParent()->isUnion()) {
Diag(CountFD->getBeginLoc(), diag::err_count_attr_refer_to_union)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 273d4a1ee37816..bab44c2dd7acf8 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5618,12 +5618,70 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
diag::err_builtin_counted_by_ref_must_be_flex_array_member)
<< Arg->getSourceRange();
- if (ME->getMemberDecl()->getType()->isCountAttributedType())
- if (const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl()))
- if (const FieldDecl *CountFD = FAMDecl->findCountedByField())
- // The proper return type should be a pointer to the type of the
- // counted_by's 'count' field.
- TheCall->setType(Context.getPointerType(CountFD->getType()));
+ if (ME->getMemberDecl()->getType()->isCountAttributedType()) {
+ if (FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
+ if (FieldDecl *CountFD = FAMDecl->findCountedByField()) {
+ // Reverse through any anonymous structs / unions surrounding the
+ // flexible array member. We'll build any necessary MemberExpr's to
+ // anonymous structs / unions when building a reference to the
+ // 'count' field.
+ RecordDecl *RD = FAMDecl->getParent();
+ DeclContext *DC = RD;
+ for (; DC->isRecord(); DC = DC->getLexicalParent()) {
+ if (!RD->isAnonymousStructOrUnion())
+ break;
+ RD = cast<RecordDecl>(DC);
+ if (auto *Base = dyn_cast<MemberExpr>(ME->getBase()))
+ ME = Base;
+ }
+
+ // See if the count's FieldDecl is within anonymous structs.
+ SmallVector<NamedDecl *, 2> PathToFD;
+ for (Decl *D : RD->decls()) {
+ if (auto *IFD = dyn_cast<IndirectFieldDecl>(D);
+ IFD && IFD->getAnonField() == CountFD) {
+ PathToFD.insert(PathToFD.begin(), IFD->chain_begin(),
+ IFD->chain_end());
+ break;
+ }
+ }
+
+ if (PathToFD.empty())
+ PathToFD.push_back(CountFD);
+
+ // Build a MemberExpr to the 'count' field. This accounts for any
+ // anonymous structs / unions that may contain the field. Use the
+ // CallExpr's SourceLocation for future diagnostics.
+ SourceLocation Loc = TheCall->getBeginLoc();
+ bool isArrow = ME->isArrow();
+ Expr *New = ME->getBase();
+ for (NamedDecl *ND : PathToFD) {
+ ValueDecl *VD = cast<ValueDecl>(ND);
+ auto *ME = MemberExpr::CreateImplicit(Context, New, isArrow, VD,
+ VD->getType(), VK_PRValue,
+ OK_Ordinary);
+ ME->setMemberLoc(Loc);
+ New = ME;
+ isArrow = false;
+ }
+
+ return ExprResult(UnaryOperator::Create(
+ Context, New, UO_AddrOf,
+ Context.getPointerType(CountFD->getType()), VK_LValue,
+ OK_Ordinary, Loc, false, FPOptionsOverride()));
+ } else {
+ auto *A = FAMDecl->getAttr<CountedByAttr>();
+ auto *CountDecl = cast<DeclRefExpr>(A->getCount())->getDecl();
+
+ Diag(Arg->getBeginLoc(), diag::err_count_attr_must_be_in_structure)
+ << CountDecl << 0 << Arg->getSourceRange();
+ Diag(CountDecl->getBeginLoc(),
+ diag::note_flexible_array_counted_by_attr_field)
+ << CountDecl << CountDecl->getSourceRange();
+ return ExprError();
+ }
+ }
+ }
}
return false;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 36f9a4f87e9d07..d980955728d820 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -9192,18 +9192,16 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
auto FindBuiltinCountedByRefExpr = [](Expr *E) {
struct BuiltinCountedByRefVisitor
: public RecursiveASTVisitor<BuiltinCountedByRefVisitor> {
- CallExpr *TheCall = nullptr;
- bool VisitCallExpr(CallExpr *E) {
- if (FunctionDecl *FD = E->getDirectCallee())
- if (FD->getBuiltinID() == Builtin::BI__builtin_counted_by_ref) {
- TheCall = E;
- return true;
- }
- return false;
+ MemberExpr *ME = nullptr;
+ bool VisitMemberExpr(MemberExpr *E) {
+ if (auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
+ FD && FD->isBoundsSafetyCounter())
+ ME = E;
+ return true;
}
} V;
V.TraverseStmt(E);
- return V.TheCall;
+ return V.ME;
};
if (auto *CE = FindBuiltinCountedByRefExpr(RHS.get()))
Diag(CE->getExprLoc(),
@@ -13761,38 +13759,38 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
// __builtin_counted_by_ref can't be used in a binary expression or array
// subscript on the LHS.
int DiagOption = -1;
- auto FindBuiltinCountedByRefExpr = [&](Expr *E) {
+ auto FindInvalidUseOfBoundsSafetyCounter = [&](Expr *E) {
struct BuiltinCountedByRefVisitor
: public RecursiveASTVisitor<BuiltinCountedByRefVisitor> {
- CallExpr *TheCall = nullptr;
+ MemberExpr *ME = nullptr;
bool InvalidUse = false;
int Option = -1;
- bool VisitCallExpr(CallExpr *E) {
- if (FunctionDecl *FD = E->getDirectCallee();
- FD && FD->getBuiltinID() == Builtin::BI__builtin_counted_by_ref)
- TheCall = E;
- return false;
+ bool VisitMemberExpr(MemberExpr *E) {
+ if (auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
+ FD && FD->isBoundsSafetyCounter())
+ ME = E;
+ return true;
}
bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
InvalidUse = true;
Option = 0; // report 'array expression' in diagnostic.
- return VisitStmt(E->getBase()) || VisitStmt(E->getIdx());
+ return VisitStmt(E->getBase()) && VisitStmt(E->getIdx());
}
bool VisitBinaryOperator(BinaryOperator *E) {
InvalidUse = true;
Option = 1; // report 'binary expression' in diagnostic.
- return VisitStmt(E->getLHS()) || VisitStmt(E->getRHS());
+ return VisitStmt(E->getLHS()) && VisitStmt(E->getRHS());
}
} V;
V.TraverseStmt(E);
DiagOption = V.Option;
- return V.InvalidUse ? V.TheCall : nullptr;
+ return V.InvalidUse ? V.ME : nullptr;
};
- if (auto *CE = FindBuiltinCountedByRefExpr(LHSExpr))
- Diag(CE->getExprLoc(), diag::err_builtin_counted_by_ref_invalid_lhs_use)
- << DiagOption << CE->getSourceRange();
+ if (auto *E = FindInvalidUseOfBoundsSafetyCounter(LHSExpr))
+ Diag(E->getExprLoc(), diag::err_builtin_counted_by_ref_invalid_lhs_use)
+ << DiagOption << E->getSourceRange();
if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType, RHS.get(),
AssignmentAction::Assigning))
diff --git a/clang/test/CodeGen/builtin-counted-by-ref.c b/clang/test/CodeGen/builtin-counted-by-ref.c
index 3d4c042e5731ea..f27db821702f57 100644
--- a/clang/test/CodeGen/builtin-counted-by-ref.c
+++ b/clang/test/CodeGen/builtin-counted-by-ref.c
@@ -69,7 +69,7 @@ struct b {
// X86_64-NEXT: [[ADD:%.*]] = add nsw i64 [[MUL]], 4
// X86_64-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3]]
// X86_64-NEXT: [[CONV1:%.*]] = trunc i32 [[SIZE]] to i8
-// X86_64-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 12
+// X86_64-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 12
// X86_64-NEXT: store i8 [[CONV1]], ptr [[TMP0]], align 1, !tbaa [[TBAA6:![0-9]+]]
// X86_64-NEXT: ret ptr [[CALL]]
//
@@ -80,7 +80,7 @@ struct b {
// I386-NEXT: [[ADD:%.*]] = add i32 [[MUL]], 4
// I386-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3]]
// I386-NEXT: [[CONV:%.*]] = trunc i32 [[SIZE]] to i8
-// I386-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i32 12
+// I386-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i32 12
// I386-NEXT: store i8 [[CONV]], ptr [[TMP0]], align 1, !tbaa [[TBAA7:![0-9]+]]
// I386-NEXT: ret ptr [[CALL]]
//
diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index 10938ed4c59bb1..ec6985d1a4fd3a 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -4,42 +4,46 @@ struct fam_struct {
int x;
char count;
int array[] __attribute__((counted_by(count)));
-} *p;
+};
-struct non_fam_struct {
- char x;
- long *pointer;
- int array[42];
- short count;
-} *q;
-
-void g(char *);
+void test1(struct fam_struct *ptr, int size, int idx) {
+ *__builtin_counted_by_ref(ptr->array) = size; // ok
+ *__builtin_counted_by_ref(&ptr->array[idx]) = size; // ok
+}
-void *test1(int size) {
- int i = 0;
- char *ref = __builtin_counted_by_ref(p->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+void test2(struct fam_struct *ptr, int idx) {
+ __builtin_counted_by_ref(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+ __builtin_counted_by_ref(ptr->array, ptr->x, ptr->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
+ __builtin_counted_by_ref(ptr->x); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+ __builtin_counted_by_ref(&ptr->array[idx++]); // expected-warning {{'__builtin_counted_by_ref' argument has side-effects that will be discarded}} expected-warning {{expression result unused}}
+}
- ref = __builtin_counted_by_ref(p->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
- ref = (char *)(int *)(42 + &*__builtin_counted_by_ref(p->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
- g(__builtin_counted_by_ref(p->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+void foo(char *);
- *(__builtin_counted_by_ref(p->array) + 4) = 37; // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in binary expression}}
- __builtin_counted_by_ref(p->array)[3] = 37; // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in array subscript expression}}
+void *test3(struct fam_struct *ptr, int size, int idx) {
+ char *ref = __builtin_counted_by_ref(ptr->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
- *__builtin_counted_by_ref(p->array) = size; // ok
- *__builtin_counted_by_ref(&p->array[i]) = size; // ok
+ ref = __builtin_counted_by_ref(ptr->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+ ref = (char *)(int *)(42 + &*__builtin_counted_by_ref(ptr->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+ foo(__builtin_counted_by_ref(ptr->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+ *(__builtin_counted_by_ref(ptr->array) + 4) = 37; // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in a binary expression}}
+ __builtin_counted_by_ref(ptr->array)[3] = 37; // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in an array subscript expression}}
- *__builtin_counted_by_ref(q->array) = size // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
- *__builtin_counted_by_ref(&q->array[0]) = size; // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
- *__builtin_counted_by_ref(q->pointer) = size; // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
- *__builtin_counted_by_ref(&q->pointer[0]) = size; // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
- __builtin_counted_by_ref(p->x); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
- __builtin_counted_by_ref(&p->array[i++]); // expected-warning {{'__builtin_counted_by_ref' argument has side-effects that will be discarded}}
+ return __builtin_counted_by_ref(ptr->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+}
- __builtin_counted_by_ref(); // expected-error {{too few arguments to function call, expected 1, have 0}}
- __builtin_counted_by_ref(p->array, p->x, p->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
+struct non_fam_struct {
+ char x;
+ long *pointer;
+ int array[42];
+ short count;
+};
- return __builtin_counted_by_ref(p->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+void *test4(struct non_fam_struct *ptr, int size) {
+ *__builtin_counted_by_ref(ptr->array) = size // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+ *__builtin_counted_by_ref(&ptr->array[0]) = size; // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+ *__builtin_counted_by_ref(ptr->pointer) = size; // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+ *__builtin_counted_by_ref(&ptr->pointer[0]) = size; // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
}
struct char_count {
@@ -72,7 +76,7 @@ struct unsigned_long_count {
int array[] __attribute__((counted_by(count)));
} *ulp;
-void test2(void) {
+void test5(void) {
_Static_assert(_Generic(__builtin_counted_by_ref(cp->array), char * : 1, default : 0) == 1, "wrong return type");
_Static_assert(_Generic(__builtin_counted_by_ref(sp->array), short * : 1, default : 0) == 1, "wrong return type");
_Static_assert(_Generic(__builtin_counted_by_ref(ip->array), int * : 1, default : 0) == 1, "wrong return type");
>From 9b36f190be82f3300210cd8e6924aeaf2f54dc2f Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 20 Sep 2024 14:26:50 -0700
Subject: [PATCH 39/59] Remove invalid tests that take the address of the
bounds counter.
---
clang/test/CodeGen/attr-counted-by.c | 431 +++++++++++----------------
1 file changed, 179 insertions(+), 252 deletions(-)
diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c
index f70e552bca26ab..ec350991f176ef 100644
--- a/clang/test/CodeGen/attr-counted-by.c
+++ b/clang/test/CodeGen/attr-counted-by.c
@@ -931,79 +931,6 @@ size_t test10_bdos(struct union_of_fams *p) {
return __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: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
-// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
-// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOTCOUNTED_BY_GEP]], align 4
-// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[DOTCOUNTED_BY_LOAD]] to i64, !nosanitize [[META2]]
-// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META2]]
-// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label [[CONT3:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
-// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB16:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
-// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
-// SANITIZE-WITH-ATTR: cont3:
-// SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
-// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM]]
-// SANITIZE-WITH-ATTR-NEXT: store i32 4, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]]
-// 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: [[ARRAY:%.*]] = getelementptr inbounds nuw 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 i32], ptr [[ARRAY]], i64 0, 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: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
-// 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 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: [[ARRAY:%.*]] = getelementptr inbounds nuw 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 i32], ptr [[ARRAY]], i64 0, 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);
-}
-
-// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test11_bdos(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
-// SANITIZE-WITH-ATTR-NEXT: entry:
-// SANITIZE-WITH-ATTR-NEXT: ret i64 4
-//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test11_bdos(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
-// NO-SANITIZE-WITH-ATTR-NEXT: entry:
-// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 4
-//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test11_bdos(
-// SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
-// SANITIZE-WITHOUT-ATTR-NEXT: entry:
-// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 4
-//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test11_bdos(
-// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR1]] {
-// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
-// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i64 4
-//
-size_t test11_bdos(struct annotated *p) {
- return __builtin_dynamic_object_size(&p->count, 1);
-}
-
struct {
struct {
struct {
@@ -1011,62 +938,62 @@ struct {
};
};
int entries[] __attribute__((__counted_by__(num_entries)));
-} test12_foo;
+} test11_foo;
struct hang {
int entries[6];
-} test12_bar;
+} test11_bar;
-int test12_a, test12_b;
+int test11_a, test11_b;
-// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test12(
-// SANITIZE-WITH-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR4:[0-9]+]] {
+// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test11(
+// SANITIZE-WITH-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: [[BAZ:%.*]] = alloca [[STRUCT_HANG:%.*]], align 4
-// SANITIZE-WITH-ATTR-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR10:[0-9]+]]
-// SANITIZE-WITH-ATTR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test12_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT9:![0-9]+]]
+// SANITIZE-WITH-ATTR-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR11:[0-9]+]]
+// SANITIZE-WITH-ATTR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test11_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT9:![0-9]+]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ult i32 [[INDEX]], 6
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = zext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP0]], label [[CONT:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB18:[0-9]+]], i64 [[TMP1]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB17:[0-9]+]], i64 [[TMP1]]) #[[ATTR10]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont:
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [6 x i32], ptr [[BAZ]], i64 0, i64 [[TMP1]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]]
-// SANITIZE-WITH-ATTR-NEXT: store i32 [[TMP2]], ptr @test12_b, align 4, !tbaa [[TBAA4]]
-// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr @test12_foo, align 4
+// SANITIZE-WITH-ATTR-NEXT: store i32 [[TMP2]], ptr @test11_b, align 4, !tbaa [[TBAA4]]
+// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr @test11_foo, align 4
// SANITIZE-WITH-ATTR-NEXT: [[DOTNOT:%.*]] = icmp eq i32 [[DOTCOUNTED_BY_LOAD]], 0
// SANITIZE-WITH-ATTR-NEXT: br i1 [[DOTNOT]], label [[HANDLER_OUT_OF_BOUNDS4:%.*]], label [[HANDLER_TYPE_MISMATCH6:%.*]], !prof [[PROF10:![0-9]+]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds4:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB20:[0-9]+]], i64 0) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB19:[0-9]+]], i64 0) #[[ATTR10]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.type_mismatch6:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_type_mismatch_v1_abort(ptr nonnull @[[GLOB21:[0-9]+]], i64 ptrtoint (ptr getelementptr inbounds nuw (i8, ptr @test12_foo, i64 4) to i64)) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_type_mismatch_v1_abort(ptr nonnull @[[GLOB20:[0-9]+]], i64 ptrtoint (ptr getelementptr inbounds nuw (i8, ptr @test11_foo, i64 4) to i64)) #[[ATTR10]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test12(
-// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR4:[0-9]+]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test11(
+// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[BAZ:%.*]] = alloca [[STRUCT_HANG:%.*]], align 4
-// NO-SANITIZE-WITH-ATTR-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR11:[0-9]+]]
-// NO-SANITIZE-WITH-ATTR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test12_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]]
+// NO-SANITIZE-WITH-ATTR-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR12:[0-9]+]]
+// NO-SANITIZE-WITH-ATTR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test11_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]]
// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [6 x i32], ptr [[BAZ]], i64 0, i64 [[IDXPROM]]
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
-// NO-SANITIZE-WITH-ATTR-NEXT: store i32 [[TMP0]], ptr @test12_b, align 4, !tbaa [[TBAA2]]
-// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @test12_foo, i64 4), align 4, !tbaa [[TBAA2]]
-// NO-SANITIZE-WITH-ATTR-NEXT: store i32 [[TMP1]], ptr @test12_a, align 4, !tbaa [[TBAA2]]
+// NO-SANITIZE-WITH-ATTR-NEXT: store i32 [[TMP0]], ptr @test11_b, align 4, !tbaa [[TBAA2]]
+// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @test11_foo, i64 4), align 4, !tbaa [[TBAA2]]
+// NO-SANITIZE-WITH-ATTR-NEXT: store i32 [[TMP1]], ptr @test11_a, align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITH-ATTR-NEXT: br label [[FOR_COND:%.*]]
// NO-SANITIZE-WITH-ATTR: for.cond:
// NO-SANITIZE-WITH-ATTR-NEXT: br label [[FOR_COND]]
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i32 @test12(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i32 @test11(
// SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: [[BAZ:%.*]] = alloca [[STRUCT_HANG:%.*]], align 4
// SANITIZE-WITHOUT-ATTR-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR7:[0-9]+]]
-// SANITIZE-WITHOUT-ATTR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test12_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]]
+// SANITIZE-WITHOUT-ATTR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test11_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]]
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = icmp ult i32 [[INDEX]], 6
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP1:%.*]] = zext i32 [[INDEX]] to i64
// SANITIZE-WITHOUT-ATTR-NEXT: br i1 [[TMP0]], label [[CONT:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF8:![0-9]+]], !nosanitize [[META9:![0-9]+]]
@@ -1076,63 +1003,63 @@ int test12_a, test12_b;
// SANITIZE-WITHOUT-ATTR: cont:
// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [6 x i32], ptr [[BAZ]], i64 0, i64 [[TMP1]]
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
-// SANITIZE-WITHOUT-ATTR-NEXT: store i32 [[TMP2]], ptr @test12_b, align 4, !tbaa [[TBAA2]]
-// SANITIZE-WITHOUT-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr @test12_foo, align 4
+// SANITIZE-WITHOUT-ATTR-NEXT: store i32 [[TMP2]], ptr @test11_b, align 4, !tbaa [[TBAA2]]
+// SANITIZE-WITHOUT-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr @test11_foo, align 4
// SANITIZE-WITHOUT-ATTR-NEXT: [[DOTNOT:%.*]] = icmp eq i32 [[DOTCOUNTED_BY_LOAD]], 0
// SANITIZE-WITHOUT-ATTR-NEXT: br i1 [[DOTNOT]], label [[HANDLER_OUT_OF_BOUNDS4:%.*]], label [[HANDLER_TYPE_MISMATCH6:%.*]], !prof [[PROF10:![0-9]+]], !nosanitize [[META9]]
// SANITIZE-WITHOUT-ATTR: handler.out_of_bounds4:
// SANITIZE-WITHOUT-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB4:[0-9]+]], i64 0) #[[ATTR8]], !nosanitize [[META9]]
// SANITIZE-WITHOUT-ATTR-NEXT: unreachable, !nosanitize [[META9]]
// SANITIZE-WITHOUT-ATTR: handler.type_mismatch6:
-// SANITIZE-WITHOUT-ATTR-NEXT: tail call void @__ubsan_handle_type_mismatch_v1_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 ptrtoint (ptr getelementptr inbounds nuw (i8, ptr @test12_foo, i64 4) to i64)) #[[ATTR8]], !nosanitize [[META9]]
+// SANITIZE-WITHOUT-ATTR-NEXT: tail call void @__ubsan_handle_type_mismatch_v1_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 ptrtoint (ptr getelementptr inbounds nuw (i8, ptr @test11_foo, i64 4) to i64)) #[[ATTR8]], !nosanitize [[META9]]
// SANITIZE-WITHOUT-ATTR-NEXT: unreachable, !nosanitize [[META9]]
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i32 @test12(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i32 @test11(
// NO-SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[BAZ:%.*]] = alloca [[STRUCT_HANG:%.*]], align 4
// NO-SANITIZE-WITHOUT-ATTR-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR9:[0-9]+]]
-// NO-SANITIZE-WITHOUT-ATTR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test12_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]]
+// NO-SANITIZE-WITHOUT-ATTR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test11_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [6 x i32], ptr [[BAZ]], i64 0, i64 [[IDXPROM]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
-// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i32 [[TMP0]], ptr @test12_b, align 4, !tbaa [[TBAA2]]
-// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP1:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @test12_foo, i64 4), align 4, !tbaa [[TBAA2]]
-// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i32 [[TMP1]], ptr @test12_a, align 4, !tbaa [[TBAA2]]
+// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i32 [[TMP0]], ptr @test11_b, align 4, !tbaa [[TBAA2]]
+// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP1:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @test11_foo, i64 4), align 4, !tbaa [[TBAA2]]
+// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i32 [[TMP1]], ptr @test11_a, align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: br label [[FOR_COND:%.*]]
// NO-SANITIZE-WITHOUT-ATTR: for.cond:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: br label [[FOR_COND]]
//
-int test12(int index) {
- struct hang baz = test12_bar;
+int test11(int index) {
+ struct hang baz = test11_bar;
- for (;; test12_a = (&test12_foo)->entries[0])
- test12_b = baz.entries[index];
+ for (;; test11_a = (&test11_foo)->entries[0])
+ test11_b = baz.entries[index];
- return test12_b;
+ return test11_b;
}
-struct test13_foo {
- struct test13_bar *domain;
-} test13_f;
+struct test12_foo {
+ struct test12_bar *domain;
+} test12_f;
-struct test13_bar {
- struct test13_bar *parent;
+struct test12_bar {
+ struct test12_bar *parent;
int revmap_size;
- struct test13_foo *revmap[] __attribute__((__counted_by__(revmap_size)));
+ struct test12_foo *revmap[] __attribute__((__counted_by__(revmap_size)));
};
-// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test13(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test12(
// SANITIZE-WITH-ATTR-SAME: i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
-// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr @test13_f, align 8, !tbaa [[TBAA11:![0-9]+]]
+// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr @test12_f, align 8, !tbaa [[TBAA11:![0-9]+]]
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOTCOUNTED_BY_GEP]], align 4
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = zext i32 [[DOTCOUNTED_BY_LOAD]] to i64, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = icmp ult i64 [[INDEX]], [[TMP1]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label [[CONT5:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB24:[0-9]+]], i64 [[INDEX]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB23:[0-9]+]], i64 [[INDEX]]) #[[ATTR10]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont5:
// SANITIZE-WITH-ATTR-NEXT: [[REVMAP:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 16
@@ -1140,19 +1067,19 @@ struct test13_bar {
// SANITIZE-WITH-ATTR-NEXT: store ptr null, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA14:![0-9]+]]
// SANITIZE-WITH-ATTR-NEXT: ret i32 0
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test13(
-// NO-SANITIZE-WITH-ATTR-SAME: i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR7:[0-9]+]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test12(
+// NO-SANITIZE-WITH-ATTR-SAME: i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR8:[0-9]+]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
-// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr @test13_f, align 8, !tbaa [[TBAA8:![0-9]+]]
+// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr @test12_f, align 8, !tbaa [[TBAA8:![0-9]+]]
// NO-SANITIZE-WITH-ATTR-NEXT: [[REVMAP:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 16
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x ptr], ptr [[REVMAP]], i64 0, i64 [[INDEX]]
// NO-SANITIZE-WITH-ATTR-NEXT: store ptr null, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA11:![0-9]+]]
// NO-SANITIZE-WITH-ATTR-NEXT: ret i32 0
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i32 @test13(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i32 @test12(
// SANITIZE-WITHOUT-ATTR-SAME: i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
-// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr @test13_f, align 8, !tbaa [[TBAA11:![0-9]+]]
+// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr @test12_f, align 8, !tbaa [[TBAA11:![0-9]+]]
// SANITIZE-WITHOUT-ATTR-NEXT: [[DOTCOUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 8
// SANITIZE-WITHOUT-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOTCOUNTED_BY_GEP]], align 4
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP1:%.*]] = zext i32 [[DOTCOUNTED_BY_LOAD]] to i64, !nosanitize [[META9]]
@@ -1167,42 +1094,42 @@ struct test13_bar {
// SANITIZE-WITHOUT-ATTR-NEXT: store ptr null, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA14:![0-9]+]]
// SANITIZE-WITHOUT-ATTR-NEXT: ret i32 0
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i32 @test13(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i32 @test12(
// NO-SANITIZE-WITHOUT-ATTR-SAME: i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
-// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr @test13_f, align 8, !tbaa [[TBAA8:![0-9]+]]
+// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr @test12_f, align 8, !tbaa [[TBAA8:![0-9]+]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[REVMAP:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 16
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x ptr], ptr [[REVMAP]], i64 0, i64 [[INDEX]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: store ptr null, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA11:![0-9]+]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i32 0
//
-int test13(long index) {
- test13_f.domain->revmap[index] = 0;
+int test12(long index) {
+ test12_f.domain->revmap[index] = 0;
return 0;
}
-struct test14_foo {
+struct test13_foo {
int x, y;
int blah[] __attribute__((counted_by(x)));
};
-// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test14(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test13(
// SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp eq i32 [[IDX]], 0
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP0]], label [[TRAP:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB25:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB24:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: trap:
// SANITIZE-WITH-ATTR-NEXT: tail call void @llvm.trap() #[[ATTR9]]
// SANITIZE-WITH-ATTR-NEXT: unreachable
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test14(
-// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test13(
+// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR4]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
-// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_TEST14_FOO:%.*]], align 4
+// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_TEST13_FOO:%.*]], align 4
// NO-SANITIZE-WITH-ATTR-NEXT: store i32 1, ptr [[DOTCOMPOUNDLITERAL]], align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITH-ATTR-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTCOMPOUNDLITERAL]], i64 4
// NO-SANITIZE-WITH-ATTR-NEXT: store i32 2, ptr [[Y]], align 4, !tbaa [[TBAA2]]
@@ -1212,7 +1139,7 @@ struct test14_foo {
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITH-ATTR-NEXT: ret i32 [[TMP0]]
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test14(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test13(
// SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = icmp eq i32 [[IDX]], 0
@@ -1225,10 +1152,10 @@ struct test14_foo {
// SANITIZE-WITHOUT-ATTR-NEXT: tail call void @llvm.trap() #[[ATTR8]]
// SANITIZE-WITHOUT-ATTR-NEXT: unreachable
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test14(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test13(
// NO-SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR1]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
-// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_TEST14_FOO:%.*]], align 4
+// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_TEST13_FOO:%.*]], align 4
// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i32 1, ptr [[DOTCOMPOUNDLITERAL]], align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTCOMPOUNDLITERAL]], i64 4
// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i32 2, ptr [[Y]], align 4, !tbaa [[TBAA2]]
@@ -1238,32 +1165,32 @@ struct test14_foo {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i32 [[TMP0]]
//
-int test14(int idx) {
- return (struct test14_foo){ 1, 2 }.blah[idx];
+int test13(int idx) {
+ return (struct test13_foo){ 1, 2 }.blah[idx];
}
-// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test15(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test14(
// SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp eq i32 [[IDX]], 0
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP0]], label [[TRAP:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB27:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB26:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: trap:
// SANITIZE-WITH-ATTR-NEXT: tail call void @llvm.trap() #[[ATTR9]]
// SANITIZE-WITH-ATTR-NEXT: unreachable
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test15(
-// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test14(
+// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR4]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
-// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr getelementptr inbounds nuw (i8, ptr @__const.test15.foo, i64 8), i64 0, i64 [[IDXPROM]]
+// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr getelementptr inbounds nuw (i8, ptr @__const.test14.foo, i64 8), i64 0, i64 [[IDXPROM]]
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITH-ATTR-NEXT: ret i32 [[TMP0]]
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test15(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test14(
// SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = icmp eq i32 [[IDX]], 0
@@ -1276,15 +1203,15 @@ int test14(int idx) {
// SANITIZE-WITHOUT-ATTR-NEXT: tail call void @llvm.trap() #[[ATTR8]]
// SANITIZE-WITHOUT-ATTR-NEXT: unreachable
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test15(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test14(
// NO-SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR1]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
-// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr getelementptr inbounds nuw (i8, ptr @__const.test15.foo, i64 8), i64 0, i64 [[IDXPROM]]
+// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr getelementptr inbounds nuw (i8, ptr @__const.test14.foo, i64 8), i64 0, i64 [[IDXPROM]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i32 [[TMP0]]
//
-int test15(int idx) {
+int test14(int idx) {
struct {
int x, y;
int blah[] __attribute__((counted_by(x)));
@@ -1293,127 +1220,127 @@ int test15(int idx) {
return foo.blah[idx];
}
-// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test19(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test15(
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test19(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test15(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test19(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test15(
// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test19(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test15(
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR1]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
//
-size_t test19(struct annotated *p) {
+size_t test15(struct annotated *p) {
// Avoid pointer arithmetic. It could lead to security issues.
return __builtin_dynamic_object_size(&(p + 42)->array[2], 1);
}
-// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test20(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test16(
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test20(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test16(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test20(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test16(
// SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test20(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test16(
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR1]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
//
-size_t test20(struct annotated *p) {
+size_t test16(struct annotated *p) {
// Avoid side-effects.
return __builtin_dynamic_object_size(&(++p)->array[2], 1);
}
-// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test21(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test17(
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test21(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test17(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test21(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test17(
// SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test21(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test17(
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR1]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
//
-size_t test21(struct annotated *p) {
+size_t test17(struct annotated *p) {
// Avoid side-effects.
return __builtin_dynamic_object_size(&(p++)->array[2], 1);
}
-// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test22(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test18(
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test22(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test18(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test22(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test18(
// SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test22(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test18(
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR1]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
//
-size_t test22(struct annotated *p) {
+size_t test18(struct annotated *p) {
// Avoid side-effects.
return __builtin_dynamic_object_size(&(--p)->array[2], 1);
}
-// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test23(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test19(
// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test23(
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test19(
// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test23(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test19(
// SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test23(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test19(
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR1]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
//
-size_t test23(struct annotated *p) {
+size_t test19(struct annotated *p) {
// Avoid side-effects.
return __builtin_dynamic_object_size(&(p--)->array[2], 1);
}
@@ -1423,7 +1350,7 @@ struct tests_foo {
int arr[] __counted_by(count);
};
-// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test24(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test20(
// SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr noundef [[VAR:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[VAR]], i64 40
@@ -1431,40 +1358,40 @@ struct tests_foo {
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ugt i32 [[DOTCOUNTED_BY_LOAD]], 10
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP0]], label [[CONT4:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB28:[0-9]+]], i64 10) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB27:[0-9]+]], i64 10) #[[ATTR10]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont4:
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds i8, ptr [[VAR]], i64 84
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX2]], align 4, !tbaa [[TBAA4]]
// SANITIZE-WITH-ATTR-NEXT: ret i32 [[TMP1]]
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test24(
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test20(
// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[VAR:%.*]]) local_unnamed_addr #[[ATTR2]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[VAR]], i64 84
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITH-ATTR-NEXT: ret i32 [[TMP0]]
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test24(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test20(
// SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[C:%.*]], ptr noundef [[VAR:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[VAR]], i64 84
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4, !tbaa [[TBAA2]]
// SANITIZE-WITHOUT-ATTR-NEXT: ret i32 [[TMP0]]
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test24(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test20(
// NO-SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[VAR:%.*]]) local_unnamed_addr #[[ATTR6:[0-9]+]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[VAR]], i64 84
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i32 [[TMP0]]
//
-int test24(int c, struct tests_foo *var) {
+int test20(int c, struct tests_foo *var) {
// Invalid: there can't be an array of flexible arrays.
return var[10].arr[10];
}
-// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test25(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test21(
// SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr noundef [[VAR:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[VAR]], align 8, !tbaa [[TBAA14]]
@@ -1472,22 +1399,22 @@ int test24(int c, struct tests_foo *var) {
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[DOTCOUNTED_BY_LOAD]], 10
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label [[CONT5:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB29:[0-9]+]], i64 10) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB28:[0-9]+]], i64 10) #[[ATTR10]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont5:
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 44
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]]
// SANITIZE-WITH-ATTR-NEXT: ret i32 [[TMP2]]
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test25(
-// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[VAR:%.*]]) local_unnamed_addr #[[ATTR8:[0-9]+]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test21(
+// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[VAR:%.*]]) local_unnamed_addr #[[ATTR9:[0-9]+]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[VAR]], align 8, !tbaa [[TBAA11]]
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 44
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITH-ATTR-NEXT: ret i32 [[TMP1]]
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test25(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test21(
// SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[C:%.*]], ptr noundef [[VAR:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[VAR]], align 8, !tbaa [[TBAA14]]
@@ -1495,7 +1422,7 @@ int test24(int c, struct tests_foo *var) {
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
// SANITIZE-WITHOUT-ATTR-NEXT: ret i32 [[TMP1]]
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test25(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test21(
// NO-SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[VAR:%.*]]) local_unnamed_addr #[[ATTR7:[0-9]+]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[VAR]], align 8, !tbaa [[TBAA11]]
@@ -1503,18 +1430,18 @@ int test24(int c, struct tests_foo *var) {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i32 [[TMP1]]
//
-int test25(int c, struct tests_foo **var) {
+int test21(int c, struct tests_foo **var) {
// Double dereferenced variable.
return (**var).arr[10];
}
// Outer struct
-struct test26_foo {
+struct test22_foo {
int a;
struct tests_foo s;
};
-// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test26(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test22(
// SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr noundef [[FOO:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: [[S:%.*]] = getelementptr inbounds i8, ptr [[FOO]], i64 4
@@ -1524,7 +1451,7 @@ struct test26_foo {
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label [[CONT5:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB30:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB29:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont5:
// SANITIZE-WITH-ATTR-NEXT: [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
@@ -1532,7 +1459,7 @@ struct test26_foo {
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]]
// SANITIZE-WITH-ATTR-NEXT: ret i32 [[TMP2]]
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test26(
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test22(
// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[FOO:%.*]]) local_unnamed_addr #[[ATTR2]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
@@ -1541,7 +1468,7 @@ struct test26_foo {
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITH-ATTR-NEXT: ret i32 [[TMP0]]
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test26(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test22(
// SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[C:%.*]], ptr noundef [[FOO:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
@@ -1550,7 +1477,7 @@ struct test26_foo {
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
// SANITIZE-WITHOUT-ATTR-NEXT: ret i32 [[TMP0]]
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test26(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test22(
// NO-SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[FOO:%.*]]) local_unnamed_addr #[[ATTR6]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
@@ -1559,22 +1486,22 @@ struct test26_foo {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i32 [[TMP0]]
//
-int test26(int c, struct test26_foo *foo) {
+int test22(int c, struct test22_foo *foo) {
// Invalid: A structure with a flexible array must be a pointer.
return foo->s.arr[c];
}
-struct test27_baz;
+struct test23_baz;
-struct test27_bar {
+struct test23_bar {
unsigned char type;
unsigned char flags;
unsigned short use_cnt;
unsigned char hw_priv;
};
-struct test27_foo {
- struct test27_baz *a;
+struct test23_foo {
+ struct test23_baz *a;
unsigned char bit1 : 1;
unsigned char bit2 : 1;
@@ -1582,10 +1509,10 @@ struct test27_foo {
unsigned int n_tables;
unsigned long missed;
- struct test27_bar *entries[] __counted_by(n_tables);
+ struct test23_bar *entries[] __counted_by(n_tables);
};
-// SANITIZE-WITH-ATTR-LABEL: define dso_local ptr @test27(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local ptr @test23(
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[I:%.*]], i32 noundef [[J:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64
@@ -1595,17 +1522,17 @@ struct test27_foo {
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label [[CONT3:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB32:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB31:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont3:
// SANITIZE-WITH-ATTR-NEXT: [[ENTRIES:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 24
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x ptr], ptr [[ENTRIES]], i64 0, i64 [[IDXPROM]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA14]]
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM4:%.*]] = sext i32 [[J]] to i64
-// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds [[STRUCT_TEST27_BAR:%.*]], ptr [[TMP2]], i64 [[IDXPROM4]]
+// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds [[STRUCT_TEST23_BAR:%.*]], ptr [[TMP2]], i64 [[IDXPROM4]]
// SANITIZE-WITH-ATTR-NEXT: ret ptr [[ARRAYIDX5]]
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local ptr @test27(
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local ptr @test23(
// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[I:%.*]], i32 noundef [[J:%.*]]) local_unnamed_addr #[[ATTR2]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[ENTRIES:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 24
@@ -1613,10 +1540,10 @@ struct test27_foo {
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x ptr], ptr [[ENTRIES]], i64 0, i64 [[IDXPROM]]
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA11]]
// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM1:%.*]] = sext i32 [[J]] to i64
-// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [[STRUCT_TEST27_BAR:%.*]], ptr [[TMP0]], i64 [[IDXPROM1]]
+// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [[STRUCT_TEST23_BAR:%.*]], ptr [[TMP0]], i64 [[IDXPROM1]]
// NO-SANITIZE-WITH-ATTR-NEXT: ret ptr [[ARRAYIDX2]]
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local ptr @test27(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local ptr @test23(
// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[I:%.*]], i32 noundef [[J:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: [[ENTRIES:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 24
@@ -1624,10 +1551,10 @@ struct test27_foo {
// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x ptr], ptr [[ENTRIES]], i64 0, i64 [[IDXPROM]]
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA14]]
// SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM3:%.*]] = sext i32 [[J]] to i64
-// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds [[STRUCT_TEST27_BAR:%.*]], ptr [[TMP0]], i64 [[IDXPROM3]]
+// SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds [[STRUCT_TEST23_BAR:%.*]], ptr [[TMP0]], i64 [[IDXPROM3]]
// SANITIZE-WITHOUT-ATTR-NEXT: ret ptr [[ARRAYIDX4]]
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local ptr @test27(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local ptr @test23(
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[I:%.*]], i32 noundef [[J:%.*]]) local_unnamed_addr #[[ATTR6]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ENTRIES:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 24
@@ -1635,20 +1562,20 @@ struct test27_foo {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x ptr], ptr [[ENTRIES]], i64 0, i64 [[IDXPROM]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA11]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM1:%.*]] = sext i32 [[J]] to i64
-// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [[STRUCT_TEST27_BAR:%.*]], ptr [[TMP0]], i64 [[IDXPROM1]]
+// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [[STRUCT_TEST23_BAR:%.*]], ptr [[TMP0]], i64 [[IDXPROM1]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret ptr [[ARRAYIDX2]]
//
-struct test27_bar *test27(struct test27_foo *p, int i, int j) {
+struct test23_bar *test23(struct test23_foo *p, int i, int j) {
return &p->entries[i][j];
}
-struct test28_foo {
- struct test28_foo *s;
+struct test24_foo {
+ struct test24_foo *s;
int count;
int arr[] __counted_by(count);
};
-// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test28(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test24(
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P]], align 8, !tbaa [[TBAA14]]
@@ -1661,7 +1588,7 @@ struct test28_foo {
// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP4]], label [[CONT17:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB34:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB33:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont17:
// SANITIZE-WITH-ATTR-NEXT: [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP2]], i64 12
@@ -1669,8 +1596,8 @@ struct test28_foo {
// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]]
// SANITIZE-WITH-ATTR-NEXT: ret i32 [[TMP5]]
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test28(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR8]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test24(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR9]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P]], align 8, !tbaa [[TBAA11]]
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load ptr, ptr [[TMP0]], align 8, !tbaa [[TBAA11]]
@@ -1681,7 +1608,7 @@ struct test28_foo {
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITH-ATTR-NEXT: ret i32 [[TMP3]]
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test28(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test24(
// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P]], align 8, !tbaa [[TBAA14]]
@@ -1693,7 +1620,7 @@ struct test28_foo {
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP3:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
// SANITIZE-WITHOUT-ATTR-NEXT: ret i32 [[TMP3]]
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test28(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test24(
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR7]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P]], align 8, !tbaa [[TBAA11]]
@@ -1705,7 +1632,7 @@ struct test28_foo {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[TMP3:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i32 [[TMP3]]
//
-int test28(struct test28_foo *p, int i) {
+int test24(struct test24_foo *p, int i) {
return p->s->s->s->arr[i];
}
@@ -1716,14 +1643,14 @@ struct annotated_struct_array {
int array[] __counted_by(count);
};
-// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test29(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test25(
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[ANN:%.*]], i32 noundef [[IDX1:%.*]], i32 noundef [[IDX2:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ult i32 [[IDX1]], 10
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = zext i32 [[IDX1]] to i64
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP0]], label [[CONT3:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB36:[0-9]+]], i64 [[TMP1]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB35:[0-9]+]], i64 [[TMP1]]) #[[ATTR10]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont3:
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x ptr], ptr [[ANN]], i64 0, i64 [[TMP1]]
@@ -1735,7 +1662,7 @@ struct annotated_struct_array {
// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = icmp ult i64 [[IDXPROM15]], [[TMP3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP4]], label [[CONT20:%.*]], label [[HANDLER_OUT_OF_BOUNDS16:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds16:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB37:[0-9]+]], i64 [[IDXPROM15]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB36:[0-9]+]], i64 [[IDXPROM15]]) #[[ATTR10]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont20:
// SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP2]], i64 12
@@ -1746,8 +1673,8 @@ struct annotated_struct_array {
// SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX18]], align 4, !tbaa [[TBAA4]]
// SANITIZE-WITH-ATTR-NEXT: ret void
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test29(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[ANN:%.*]], i32 noundef [[IDX1:%.*]], i32 noundef [[IDX2:%.*]]) local_unnamed_addr #[[ATTR9:[0-9]+]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test25(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[ANN:%.*]], i32 noundef [[IDX1:%.*]], i32 noundef [[IDX2:%.*]]) local_unnamed_addr #[[ATTR10:[0-9]+]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX1]] to i64
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x ptr], ptr [[ANN]], i64 0, i64 [[IDXPROM]]
@@ -1763,7 +1690,7 @@ struct annotated_struct_array {
// NO-SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX5]], align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITH-ATTR-NEXT: ret void
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test29(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test25(
// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[ANN:%.*]], i32 noundef [[IDX1:%.*]], i32 noundef [[IDX2:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = icmp ult i32 [[IDX1]], 10
@@ -1781,7 +1708,7 @@ struct annotated_struct_array {
// SANITIZE-WITHOUT-ATTR-NEXT: store i32 -1, ptr [[ARRAYIDX19]], align 4, !tbaa [[TBAA2]]
// SANITIZE-WITHOUT-ATTR-NEXT: ret void
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test29(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test25(
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readonly [[ANN:%.*]], i32 noundef [[IDX1:%.*]], i32 noundef [[IDX2:%.*]]) local_unnamed_addr #[[ATTR8:[0-9]+]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX1]] to i64
@@ -1793,30 +1720,30 @@ struct annotated_struct_array {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i32 -1, ptr [[ARRAYIDX6]], align 4, !tbaa [[TBAA2]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void
//
-void test29(struct annotated_struct_array *ann, int idx1, int idx2) {
+void test25(struct annotated_struct_array *ann, int idx1, int idx2) {
ann->ann_array[idx1]->array[idx2] = __builtin_dynamic_object_size(ann->ann_array[idx1]->array, 1);
}
typedef struct {
char __padding[0];
-} test30_spinlock_t;
+} test26_spinlock_t;
-struct test30_struct {
- struct test30_decl *name_node;
+struct test26_struct {
+ struct test26_decl *name_node;
int priv_len;
- test30_spinlock_t pcpu_refcnt;
+ test26_spinlock_t pcpu_refcnt;
char priv[] __counted_by(priv_len);
};
-// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test30(
-// SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test26(
+// SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR5]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[IDX]] to i64, !nosanitize [[META2]]
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB39:[0-9]+]], i64 [[TMP0]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB38:[0-9]+]], i64 [[TMP0]]) #[[ATTR10]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test30(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test26(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR1]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[PCPU_REFCNT:%.*]] = getelementptr inbounds nuw i8, ptr [[PTR]], i64 12
// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
@@ -1824,14 +1751,14 @@ struct test30_struct {
// NO-SANITIZE-WITH-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]]
// NO-SANITIZE-WITH-ATTR-NEXT: ret void
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test30(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test26(
// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[IDX]] to i64, !nosanitize [[META9]]
// SANITIZE-WITHOUT-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB15:[0-9]+]], i64 [[TMP0]]) #[[ATTR8]], !nosanitize [[META9]]
// SANITIZE-WITHOUT-ATTR-NEXT: unreachable, !nosanitize [[META9]]
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test30(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test26(
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[PCPU_REFCNT:%.*]] = getelementptr inbounds nuw i8, ptr [[PTR]], i64 12
@@ -1840,38 +1767,38 @@ struct test30_struct {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void
//
-void test30(struct test30_struct *ptr, int idx) {
+void test26(struct test26_struct *ptr, int idx) {
ptr->pcpu_refcnt.__padding[idx] = __builtin_dynamic_object_size(ptr, 1);
}
-struct test31_empty {};
+struct test27_empty {};
-struct test31_struct {
- struct test31_empty y;
+struct test27_struct {
+ struct test27_empty y;
int s;
int x[] __counted_by(s);
};
-// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test31(
-// SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test27(
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR2]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: ret i32 -1
//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test31(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test27(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR2]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: ret i32 -1
//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test31(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test27(
// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR2]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: ret i32 -1
//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test31(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test27(
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR1]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i32 -1
//
-int test31(struct test31_struct *ptr, int idx) {
+int test27(struct test27_struct *ptr, int idx) {
return __builtin_dynamic_object_size(ptr, 0);
}
>From c08d8d96815d445d55b99b42163bbe18029b99a9 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 20 Sep 2024 14:59:08 -0700
Subject: [PATCH 40/59] Add testcase that discards side-effects.
---
clang/test/CodeGen/builtin-counted-by-ref.c | 38 +++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/clang/test/CodeGen/builtin-counted-by-ref.c b/clang/test/CodeGen/builtin-counted-by-ref.c
index f27db821702f57..2c7994a92b3d6c 100644
--- a/clang/test/CodeGen/builtin-counted-by-ref.c
+++ b/clang/test/CodeGen/builtin-counted-by-ref.c
@@ -123,6 +123,44 @@ struct c *test3(int size) {
return p;
}
+
+struct d {
+ char x;
+ short count;
+ int array[] __attribute__((counted_by(count)));
+};
+
+// X86_64-LABEL: define dso_local noalias noundef ptr @test4(
+// X86_64-SAME: i32 noundef [[SIZE:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// X86_64-NEXT: [[ENTRY:.*:]]
+// X86_64-NEXT: [[CONV:%.*]] = sext i32 [[SIZE]] to i64
+// X86_64-NEXT: [[MUL:%.*]] = shl nsw i64 [[CONV]], 2
+// X86_64-NEXT: [[ADD:%.*]] = add nsw i64 [[MUL]], 4
+// X86_64-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3]]
+// X86_64-NEXT: [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 2
+// X86_64-NEXT: [[CONV1:%.*]] = trunc i32 [[SIZE]] to i16
+// X86_64-NEXT: store i16 [[CONV1]], ptr [[COUNT]], align 2, !tbaa [[TBAA2]]
+// X86_64-NEXT: ret ptr [[CALL]]
+//
+// I386-LABEL: define dso_local noalias noundef ptr @test4(
+// I386-SAME: i32 noundef [[SIZE:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// I386-NEXT: [[ENTRY:.*:]]
+// I386-NEXT: [[MUL:%.*]] = shl i32 [[SIZE]], 2
+// I386-NEXT: [[ADD:%.*]] = add i32 [[MUL]], 4
+// I386-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3]]
+// I386-NEXT: [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i32 2
+// I386-NEXT: [[CONV:%.*]] = trunc i32 [[SIZE]] to i16
+// I386-NEXT: store i16 [[CONV]], ptr [[COUNT]], align 2, !tbaa [[TBAA3]]
+// I386-NEXT: ret ptr [[CALL]]
+//
+struct d *test4(int size, int idx) {
+ struct d *p = __builtin_malloc(sizeof(struct d) + sizeof(int) * size);
+
+ if (__builtin_counted_by_ref(&p->array[0]))
+ *__builtin_counted_by_ref(&p->array[idx++]) = size;
+
+ return p;
+}
//.
// X86_64: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
// X86_64: [[META3]] = !{!"short", [[META4:![0-9]+]], i64 0}
>From 906dd2e7b3da3ea17bc33774b9734bedbc814358 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 26 Sep 2024 14:40:21 -0700
Subject: [PATCH 41/59] Delay warnings for _Generic statements.
---
clang/docs/LanguageExtensions.rst | 24 +++++++++-------
clang/lib/AST/Decl.cpp | 4 +++
clang/lib/Parse/ParseExpr.cpp | 2 ++
clang/lib/Sema/AnalysisBasedWarnings.cpp | 31 +++++++++++++++++++--
clang/lib/Sema/SemaChecking.cpp | 27 +++++++++++++++++-
clang/lib/Sema/SemaExpr.cpp | 1 -
clang/test/CodeGen/builtin-counted-by-ref.c | 14 +++++++---
clang/test/Sema/builtin-counted-by-ref.c | 7 +++++
8 files changed, 92 insertions(+), 18 deletions(-)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index c9915a16480c98..2d487a09617d7f 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3782,7 +3782,7 @@ as ``unsigned __int128`` and C23 ``unsigned _BitInt(N)``.
The argument must be a pointer to a flexible array member. If the argument
isn't a flexible array member or doesn't have the ``counted_by`` attribute, the
-builtin returns ``(size_t *)0``.
+builtin returns ``(void *)0``.
**Syntax**:
@@ -3794,12 +3794,16 @@ builtin returns ``(size_t *)0``.
.. code-block:: c
- #define alloc(P, FAM, COUNT) ({ \
+ #define alloc(P, FAM, COUNT) ({ \
+ sizeof_t __ignored_assignment; \
typeof(P) __p = NULL; \
__p = malloc(MAX(sizeof(*__p), \
sizeof(*__p) + sizeof(*__p->FAM) * COUNT)); \
- if (__builtin_counted_by_ref(__p->FAM)) \
- *__builtin_counted_by_ref(__p->FAM) = COUNT; \
+ \
+ *_Generic( \
+ __builtin_counted_by_ref(__p->FAM), \
+ void *: &__ignored_assignment, \
+ default: __builtin_counted_by_ref(__p->FAM)) = COUNT; \
__p; \
})
@@ -3817,7 +3821,7 @@ initialize the flexible array before setting the ``count`` field:
struct s {
int dummy;
short count;
- long array[];
+ long array[] __attribute__((counted_by(count)));
};
struct s *ptr = malloc(sizeof(struct s) + sizeof(long) * COUNT);
@@ -3828,14 +3832,14 @@ initialize the flexible array before setting the ``count`` field:
ptr->count = COUNT;
Enforcing the rule that ``ptr->count = COUNT;`` must occur after every
-allocation of a struct with a flexible array member that has the ``counted_by``
+allocation of a struct with a flexible array member with the ``counted_by``
attribute is prone to failure in large code bases. This builtin mitigates this
-for allocators (like in Linux) that are implemented via macros where the
-assignment happens automatically.
+for allocators (like in Linux) that are implemented in a way where the counter
+assignment can happen automatically.
**Note: The value returned by ``__builtin_counted_by_ref`` cannot be assigned
-to a variable or passed into a function. Doing so violates bounds safety
-conventions.**
+to a variable or passed into a function, because doing so violates bounds
+safety conventions.**
Multiprecision Arithmetic Builtins
----------------------------------
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 86913763ef9ff5..29c10d9be3b585 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3656,6 +3656,10 @@ unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const {
(!hasAttr<ArmBuiltinAliasAttr>() && !hasAttr<BuiltinAliasAttr>()))
return 0;
+ if (getASTContext().getLangOpts().CPlusPlus &&
+ BuiltinID == Builtin::BI__builtin_counted_by_ref)
+ return 0;
+
const ASTContext &Context = getASTContext();
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return BuiltinID;
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 4570a18bc0d5e5..c9856ce1547945 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -3536,6 +3536,8 @@ ExprResult Parser::ParseGenericSelectionExpression() {
// FIXME: These expressions should be parsed in a potentially potentially
// evaluated context.
+ EnterExpressionEvaluationContext PotentiallyEvaluatedIfUsed(
+ Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed);
ExprResult ER(
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
if (ER.isInvalid()) {
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index c76733e9a774b6..968c4d5644de8d 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2697,8 +2697,35 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
break;
}
}
- // If we cannot map to a basic block, assume the statement is
- // reachable.
+
+ // A Stmt in a _Generic statement may not be reachable and so we
+ // don't want to emit diagnostics.
+ auto FindGenericSelectionParent = [&](const Stmt *S) ->
+ std::pair<const GenericSelectionExpr *, const Stmt *> {
+ ParentMap &PM = AC.getParentMap();
+
+ while (PM.hasParent(S)) {
+ const Stmt *Parent = PM.getParent(S);
+ if (const auto *GSE = dyn_cast<GenericSelectionExpr>(Parent))
+ return std::make_pair(GSE, S);
+ S = Parent;
+ }
+
+ return std::make_pair(nullptr, nullptr);
+ };
+ if (auto GenericStmt = FindGenericSelectionParent(S);
+ GenericStmt.first) {
+ const GenericSelectionExpr *GSE =
+ cast<GenericSelectionExpr>(GenericStmt.first);
+ const Stmt *Entry = GenericStmt.second;
+
+ if (GSE->getControllingExpr() != Entry &&
+ GSE->getResultExpr() != Entry)
+ AllReachable = false;
+ }
+
+ // If we cannot map to a basic block or _Generic statement, assume
+ // the statement is reachable.
}
if (AllReachable)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index bab44c2dd7acf8..86f73575d9dd98 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -31,6 +31,7 @@
#include "clang/AST/NSAPI.h"
#include "clang/AST/NonTrivialTypeVisitor.h"
#include "clang/AST/OperationKinds.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/TemplateBase.h"
@@ -5665,6 +5666,22 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
isArrow = false;
}
+ // Mark the DeclRefExpr as used.
+ auto DoMarkDeclRefUsed = [&](Expr *E) {
+ struct FindDeclRefVisitor
+ : public RecursiveASTVisitor<FindDeclRefVisitor> {
+ DeclRefExpr *DRE = nullptr;
+ bool VisitDeclRefExpr(DeclRefExpr *E) {
+ DRE = E;
+ return true;
+ }
+ } V;
+ V.TraverseStmt(E);
+ return V.DRE;
+ };
+ if (DeclRefExpr *DRE = DoMarkDeclRefUsed(New))
+ DRE->getDecl()->setIsUsed();
+
return ExprResult(UnaryOperator::Create(
Context, New, UO_AddrOf,
Context.getPointerType(CountFD->getType()), VK_LValue,
@@ -5684,7 +5701,15 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
}
}
- return false;
+ QualType SizeTypePtrTy = Context.VoidPtrTy;
+ QualType NullPtrTy =
+ Context.getIntTypeForBitwidth(Context.getIntWidth(SizeTypePtrTy), true);
+
+ return ExprResult(ImplicitCastExpr::Create(
+ Context, SizeTypePtrTy, CK_IntegralToPointer,
+ IntegerLiteral::Create(Context, Context.MakeIntValue(0, NullPtrTy),
+ NullPtrTy, SourceLocation()),
+ nullptr, VK_LValue, FPOptionsOverride()));
}
namespace {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index d980955728d820..bc02a519e06a14 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -28,7 +28,6 @@
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/OperationKinds.h"
-#include "clang/AST/ParentMapContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
diff --git a/clang/test/CodeGen/builtin-counted-by-ref.c b/clang/test/CodeGen/builtin-counted-by-ref.c
index 2c7994a92b3d6c..12da2bfba8bce7 100644
--- a/clang/test/CodeGen/builtin-counted-by-ref.c
+++ b/clang/test/CodeGen/builtin-counted-by-ref.c
@@ -117,9 +117,12 @@ struct c {
//
struct c *test3(int size) {
struct c *p = __builtin_malloc(sizeof(struct c) + sizeof(int) * size);
+ unsigned long int __ignored;
- if (__builtin_counted_by_ref(&p->array[0]))
- *__builtin_counted_by_ref(&p->array[0]) = size;
+ *_Generic(
+ __builtin_counted_by_ref(&p->array[0]),
+ void *: &__ignored,
+ default: __builtin_counted_by_ref(&p->array[0])) = size;
return p;
}
@@ -155,9 +158,12 @@ struct d {
//
struct d *test4(int size, int idx) {
struct d *p = __builtin_malloc(sizeof(struct d) + sizeof(int) * size);
+ unsigned long int __ignored;
- if (__builtin_counted_by_ref(&p->array[0]))
- *__builtin_counted_by_ref(&p->array[idx++]) = size;
+ *_Generic(
+ __builtin_counted_by_ref(&p->array[0]),
+ void *: &__ignored,
+ default: __builtin_counted_by_ref(&p->array[idx++])) = size;
return p;
}
diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index ec6985d1a4fd3a..2013cec3e82655 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -9,6 +9,13 @@ struct fam_struct {
void test1(struct fam_struct *ptr, int size, int idx) {
*__builtin_counted_by_ref(ptr->array) = size; // ok
*__builtin_counted_by_ref(&ptr->array[idx]) = size; // ok
+
+ {
+ size_t __ignored_assignment;
+ *_Generic(__builtin_counted_by_ref(p->array),
+ void *: &__ignored_assignment,
+ default: __builtin_counted_by_ref(p->array)) = 42; // ok
+ }
}
void test2(struct fam_struct *ptr, int idx) {
>From e3fbc031a403dd1c00726ec9339c7714537e8888 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 3 Oct 2024 16:43:56 -0700
Subject: [PATCH 42/59] Marking some diagnostics as 'potentially evaluated'
somehow prevented variables from being marked as 'used'. >_<
---
clang/lib/Parse/ParseExpr.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index c9856ce1547945..4570a18bc0d5e5 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -3536,8 +3536,6 @@ ExprResult Parser::ParseGenericSelectionExpression() {
// FIXME: These expressions should be parsed in a potentially potentially
// evaluated context.
- EnterExpressionEvaluationContext PotentiallyEvaluatedIfUsed(
- Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed);
ExprResult ER(
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
if (ER.isInvalid()) {
>From ac5ff7ce1067b9cacca9904c5b14561ea3e9e62f Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 3 Oct 2024 16:51:31 -0700
Subject: [PATCH 43/59] Regenerate testcase.
---
clang/test/CodeGen/builtin-counted-by-ref.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/test/CodeGen/builtin-counted-by-ref.c b/clang/test/CodeGen/builtin-counted-by-ref.c
index 12da2bfba8bce7..8fcab0086521fd 100644
--- a/clang/test/CodeGen/builtin-counted-by-ref.c
+++ b/clang/test/CodeGen/builtin-counted-by-ref.c
@@ -140,8 +140,8 @@ struct d {
// X86_64-NEXT: [[MUL:%.*]] = shl nsw i64 [[CONV]], 2
// X86_64-NEXT: [[ADD:%.*]] = add nsw i64 [[MUL]], 4
// X86_64-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3]]
-// X86_64-NEXT: [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 2
// X86_64-NEXT: [[CONV1:%.*]] = trunc i32 [[SIZE]] to i16
+// X86_64-NEXT: [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 2
// X86_64-NEXT: store i16 [[CONV1]], ptr [[COUNT]], align 2, !tbaa [[TBAA2]]
// X86_64-NEXT: ret ptr [[CALL]]
//
@@ -151,8 +151,8 @@ struct d {
// I386-NEXT: [[MUL:%.*]] = shl i32 [[SIZE]], 2
// I386-NEXT: [[ADD:%.*]] = add i32 [[MUL]], 4
// I386-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3]]
-// I386-NEXT: [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i32 2
// I386-NEXT: [[CONV:%.*]] = trunc i32 [[SIZE]] to i16
+// I386-NEXT: [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i32 2
// I386-NEXT: store i16 [[CONV]], ptr [[COUNT]], align 2, !tbaa [[TBAA3]]
// I386-NEXT: ret ptr [[CALL]]
//
>From 072f7e4acf46c8e10cc208d3e8b5da27b91aec5d Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 3 Oct 2024 16:53:47 -0700
Subject: [PATCH 44/59] Fix testcase.
---
clang/test/Sema/builtin-counted-by-ref.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index 2013cec3e82655..ff863f06007bb2 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -std=c99 -fsyntax-only -verify %s
+typedef unsigned long int size_t;
+
struct fam_struct {
int x;
char count;
@@ -12,9 +14,9 @@ void test1(struct fam_struct *ptr, int size, int idx) {
{
size_t __ignored_assignment;
- *_Generic(__builtin_counted_by_ref(p->array),
+ *_Generic(__builtin_counted_by_ref(ptr->array),
void *: &__ignored_assignment,
- default: __builtin_counted_by_ref(p->array)) = 42; // ok
+ default: __builtin_counted_by_ref(ptr->array)) = 42; // ok
}
}
>From 391e2f683c44ad3322e623c3078742ea35ee0795 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 4 Oct 2024 16:04:19 -0700
Subject: [PATCH 45/59] Fix some of the naming and remove dead code.
---
clang/docs/LanguageExtensions.rst | 1 +
clang/docs/ReleaseNotes.rst | 15 +++++----
clang/include/clang/Basic/DiagnosticGroups.td | 4 +--
.../clang/Basic/DiagnosticSemaKinds.td | 2 +-
clang/lib/Sema/AnalysisBasedWarnings.cpp | 31 ++-----------------
clang/lib/Sema/SemaChecking.cpp | 16 ----------
6 files changed, 15 insertions(+), 54 deletions(-)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 2d487a09617d7f..40a0cc6542f555 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3804,6 +3804,7 @@ builtin returns ``(void *)0``.
__builtin_counted_by_ref(__p->FAM), \
void *: &__ignored_assignment, \
default: __builtin_counted_by_ref(__p->FAM)) = COUNT; \
+ \
__p; \
})
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d63697cd37a86f..7ce8647e7b7cfd 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -298,12 +298,15 @@ Non-comprehensive list of changes in this release
/* A simplified version of Linux allocation macros */
#define alloc(PTR, FAM, COUNT) ({ \
- typeof(P) __p; \
- size_t __size = sizeof(*P) + sizeof(*P->FAM) * COUNT; \
- __p = malloc(__size); \
- if (__builtin_counted_by_ref(__p->FAM)) \
- *__builtin_counted_by_ref(__p->FAM) = COUNT; \
- __p; \
+ sizeof_t __ignored_assignment; \
+ typeof(P) __p; \
+ size_t __size = sizeof(*P) + sizeof(*P->FAM) * COUNT; \
+ __p = malloc(__size); \
+ *_Generic( \
+ __builtin_counted_by_ref(__p->FAM), \
+ void *: &__ignored_assignment, \
+ default: __builtin_counted_by_ref(__p->FAM)) = COUNT; \
+ __p; \
})
The flexible array member (FAM) can now be accessed immediately without causing
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index e27a94a623fea2..f5e9c252b1a209 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1483,8 +1483,8 @@ def BoundsSafetyCountedByEltTyUnknownSize :
DiagGroup<"bounds-safety-counted-by-elt-type-unknown-size">;
// counted_by warnings
-def CountedByAttribute
- : DiagGroup<"get-counted-by-side-effects">;
+def CountedByRefSideEffects
+ : DiagGroup<"counted-by-ref-side-effects">;
// A group for cross translation unit static analysis related warnings.
def CrossTU : DiagGroup<"ctu">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 637cf13ad53f4d..6b07589eb9eb47 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6664,7 +6664,7 @@ def err_builtin_counted_by_ref_invalid_lhs_use : Error<
def warn_builtin_counted_by_ref_has_side_effects : Warning<
"'__builtin_counted_by_ref' argument has side-effects that will be discarded">,
- InGroup<CountedByAttribute>;
+ InGroup<CountedByRefSideEffects>;
let CategoryName = "ARC Semantic Issue" in {
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 968c4d5644de8d..c76733e9a774b6 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2697,35 +2697,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
break;
}
}
-
- // A Stmt in a _Generic statement may not be reachable and so we
- // don't want to emit diagnostics.
- auto FindGenericSelectionParent = [&](const Stmt *S) ->
- std::pair<const GenericSelectionExpr *, const Stmt *> {
- ParentMap &PM = AC.getParentMap();
-
- while (PM.hasParent(S)) {
- const Stmt *Parent = PM.getParent(S);
- if (const auto *GSE = dyn_cast<GenericSelectionExpr>(Parent))
- return std::make_pair(GSE, S);
- S = Parent;
- }
-
- return std::make_pair(nullptr, nullptr);
- };
- if (auto GenericStmt = FindGenericSelectionParent(S);
- GenericStmt.first) {
- const GenericSelectionExpr *GSE =
- cast<GenericSelectionExpr>(GenericStmt.first);
- const Stmt *Entry = GenericStmt.second;
-
- if (GSE->getControllingExpr() != Entry &&
- GSE->getResultExpr() != Entry)
- AllReachable = false;
- }
-
- // If we cannot map to a basic block or _Generic statement, assume
- // the statement is reachable.
+ // If we cannot map to a basic block, assume the statement is
+ // reachable.
}
if (AllReachable)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 86f73575d9dd98..54448d8c66e430 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5666,22 +5666,6 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
isArrow = false;
}
- // Mark the DeclRefExpr as used.
- auto DoMarkDeclRefUsed = [&](Expr *E) {
- struct FindDeclRefVisitor
- : public RecursiveASTVisitor<FindDeclRefVisitor> {
- DeclRefExpr *DRE = nullptr;
- bool VisitDeclRefExpr(DeclRefExpr *E) {
- DRE = E;
- return true;
- }
- } V;
- V.TraverseStmt(E);
- return V.DRE;
- };
- if (DeclRefExpr *DRE = DoMarkDeclRefUsed(New))
- DRE->getDecl()->setIsUsed();
-
return ExprResult(UnaryOperator::Create(
Context, New, UO_AddrOf,
Context.getPointerType(CountFD->getType()), VK_LValue,
>From 45557631ecbe94477a27a4e7f48378f579ef1578 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 4 Oct 2024 16:22:24 -0700
Subject: [PATCH 46/59] Correct include ordering.
---
clang/lib/Sema/SemaChecking.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 54448d8c66e430..04c447b8b92531 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -31,8 +31,8 @@
#include "clang/AST/NSAPI.h"
#include "clang/AST/NonTrivialTypeVisitor.h"
#include "clang/AST/OperationKinds.h"
-#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
>From 4e22bd6882a3178faa78e4369f673e98edc88435 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 16 Oct 2024 15:16:49 -0700
Subject: [PATCH 47/59] Improve the argument checking so that it's checking
specifically for 'counted_by' and not other counting attributes. Also make
the documentation better.
---
clang/docs/LanguageExtensions.rst | 12 +-
clang/include/clang/AST/Decl.h | 3 +
.../clang/Basic/DiagnosticSemaKinds.td | 2 +-
clang/lib/Sema/SemaChecking.cpp | 126 +++++++++---------
clang/lib/Sema/SemaExpr.cpp | 4 +-
clang/test/Sema/builtin-counted-by-ref.c | 17 ++-
6 files changed, 84 insertions(+), 80 deletions(-)
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 40a0cc6542f555..de6dcc0298b8c9 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3780,9 +3780,9 @@ as ``unsigned __int128`` and C23 ``unsigned _BitInt(N)``.
``__builtin_counted_by_ref`` returns a pointer to the count field from the
``counted_by`` attribute.
-The argument must be a pointer to a flexible array member. If the argument
-isn't a flexible array member or doesn't have the ``counted_by`` attribute, the
-builtin returns ``(void *)0``.
+The argument must be a flexible array member. If the argument isn't a flexible
+array member or doesn't have the ``counted_by`` attribute, the builtin returns
+``(void *)0``.
**Syntax**:
@@ -3795,7 +3795,7 @@ builtin returns ``(void *)0``.
.. code-block:: c
#define alloc(P, FAM, COUNT) ({ \
- sizeof_t __ignored_assignment; \
+ size_t __ignored_assignment; \
typeof(P) __p = NULL; \
__p = malloc(MAX(sizeof(*__p), \
sizeof(*__p) + sizeof(*__p->FAM) * COUNT)); \
@@ -3839,8 +3839,8 @@ for allocators (like in Linux) that are implemented in a way where the counter
assignment can happen automatically.
**Note: The value returned by ``__builtin_counted_by_ref`` cannot be assigned
-to a variable or passed into a function, because doing so violates bounds
-safety conventions.**
+to a variable, have its address taken, or passed into or returned from a
+function, because doing so violates bounds safety conventions.**
Multiprecision Arithmetic Builtins
----------------------------------
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 96ac7799fb05c0..68bafa572bd82a 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3059,6 +3059,9 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
unsigned BitField : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned Mutable : 1;
+ // FIXME: IsBoundsSafetyCounter can be made into an attribute, once some
+ // downstream work is in mainline.
+ // See https://github.com/llvm/llvm-project/issues/112586
LLVM_PREFERRED_TYPE(bool)
unsigned IsBoundsSafetyCounter : 1;
LLVM_PREFERRED_TYPE(InitStorageKind)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6b07589eb9eb47..5d7eafedcbd0d6 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6657,7 +6657,7 @@ def err_builtin_counted_by_ref_must_be_flex_array_member : Error<
"'__builtin_counted_by_ref' argument must reference a flexible array member">;
def err_builtin_counted_by_ref_cannot_leak_reference : Error<
"value returned by '__builtin_counted_by_ref' cannot be assigned to a "
- "variable or used as a function argument">;
+ "variable, have its address taken, or passed into or returned from a function">;
def err_builtin_counted_by_ref_invalid_lhs_use : Error<
"value returned by '__builtin_counted_by_ref' cannot be used in "
"%select{an array subscript|a binary}0 expression">;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 04c447b8b92531..71aa660c8ed2cb 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5578,10 +5578,9 @@ bool Sema::BuiltinSetjmp(CallExpr *TheCall) {
return false;
}
-bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
- // For simplicity, we support only a limited expressions for the argument.
- // Specifically 'ptr->array' and '&ptr->array[0]'. This allows us to reject
- // arguments with complex casting, which really shouldn't be a huge problem.
+ExprResult Sema::BuiltinCountedByRef(ExprResult TheCallResult) {
+ CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
+
if (checkArgCount(TheCall, 1))
return true;
@@ -5589,6 +5588,9 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
if (ArgRes.isInvalid())
return true;
+ // For simplicity, we support only limited expressions for the argument.
+ // Specifically 'ptr->array' and '&ptr->array[0]'. This allows us to reject
+ // arguments with complex casting, which really shouldn't be a huge problem.
const Expr *Arg = ArgRes.get()->IgnoreParenImpCasts();
if (!isa<PointerType>(Arg->getType()) && !Arg->getType()->isArrayType())
return Diag(Arg->getBeginLoc(),
@@ -5608,81 +5610,73 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
Arg = ASE->getBase()->IgnoreParenImpCasts();
}
- // Use 'size_t *' as the default return type. If the argument doesn't have
- // the 'counted_by' attribute, it'll return a 'nullptr'.
- TheCall->setType(Context.getPointerType(Context.getSizeType()));
-
- if (const MemberExpr *ME = dyn_cast_if_present<MemberExpr>(Arg)) {
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(Arg)) {
if (!ME->isFlexibleArrayMemberLike(
Context, getLangOpts().getStrictFlexArraysLevel()))
return Diag(Arg->getBeginLoc(),
diag::err_builtin_counted_by_ref_must_be_flex_array_member)
<< Arg->getSourceRange();
- if (ME->getMemberDecl()->getType()->isCountAttributedType()) {
+ if (auto *CATy =
+ ME->getMemberDecl()->getType()->getAs<CountAttributedType>();
+ CATy && CATy->getKind() == CountAttributedType::CountedBy) {
if (FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
- if (FieldDecl *CountFD = FAMDecl->findCountedByField()) {
- // Reverse through any anonymous structs / unions surrounding the
- // flexible array member. We'll build any necessary MemberExpr's to
- // anonymous structs / unions when building a reference to the
- // 'count' field.
- RecordDecl *RD = FAMDecl->getParent();
- DeclContext *DC = RD;
- for (; DC->isRecord(); DC = DC->getLexicalParent()) {
- if (!RD->isAnonymousStructOrUnion())
- break;
- RD = cast<RecordDecl>(DC);
- if (auto *Base = dyn_cast<MemberExpr>(ME->getBase()))
- ME = Base;
- }
-
- // See if the count's FieldDecl is within anonymous structs.
- SmallVector<NamedDecl *, 2> PathToFD;
- for (Decl *D : RD->decls()) {
- if (auto *IFD = dyn_cast<IndirectFieldDecl>(D);
- IFD && IFD->getAnonField() == CountFD) {
- PathToFD.insert(PathToFD.begin(), IFD->chain_begin(),
- IFD->chain_end());
- break;
- }
- }
+ FieldDecl *CountFD = FAMDecl->findCountedByField();
+ assert(CountFD && "'count' field couldn't be found");
+
+ // Reverse through any anonymous structs / unions surrounding the
+ // flexible array member. We'll build any necessary MemberExpr's to
+ // anonymous structs / unions when building a reference to the
+ // 'count' field.
+ RecordDecl *RD = FAMDecl->getParent();
+ DeclContext *DC = RD;
+ for (; DC->isRecord(); DC = DC->getLexicalParent()) {
+ if (!RD->isAnonymousStructOrUnion())
+ break;
+ RD = cast<RecordDecl>(DC);
+ if (auto *Base = dyn_cast<MemberExpr>(ME->getBase()))
+ ME = Base;
+ }
- if (PathToFD.empty())
- PathToFD.push_back(CountFD);
-
- // Build a MemberExpr to the 'count' field. This accounts for any
- // anonymous structs / unions that may contain the field. Use the
- // CallExpr's SourceLocation for future diagnostics.
- SourceLocation Loc = TheCall->getBeginLoc();
- bool isArrow = ME->isArrow();
- Expr *New = ME->getBase();
- for (NamedDecl *ND : PathToFD) {
- ValueDecl *VD = cast<ValueDecl>(ND);
- auto *ME = MemberExpr::CreateImplicit(Context, New, isArrow, VD,
- VD->getType(), VK_PRValue,
- OK_Ordinary);
- ME->setMemberLoc(Loc);
- New = ME;
- isArrow = false;
+ // See if the count's FieldDecl is within anonymous structs.
+ SmallVector<NamedDecl *, 2> PathToFD;
+ for (Decl *D : RD->decls()) {
+ if (auto *IFD = dyn_cast<IndirectFieldDecl>(D);
+ IFD && IFD->getAnonField() == CountFD) {
+ PathToFD.insert(PathToFD.begin(), IFD->chain_begin(),
+ IFD->chain_end());
+ break;
}
+ }
- return ExprResult(UnaryOperator::Create(
- Context, New, UO_AddrOf,
- Context.getPointerType(CountFD->getType()), VK_LValue,
- OK_Ordinary, Loc, false, FPOptionsOverride()));
- } else {
- auto *A = FAMDecl->getAttr<CountedByAttr>();
- auto *CountDecl = cast<DeclRefExpr>(A->getCount())->getDecl();
-
- Diag(Arg->getBeginLoc(), diag::err_count_attr_must_be_in_structure)
- << CountDecl << 0 << Arg->getSourceRange();
- Diag(CountDecl->getBeginLoc(),
- diag::note_flexible_array_counted_by_attr_field)
- << CountDecl << CountDecl->getSourceRange();
- return ExprError();
+ if (PathToFD.empty())
+ PathToFD.push_back(CountFD);
+
+ // Build a MemberExpr to the 'count' field. This accounts for any
+ // anonymous structs / unions that may contain the field. Use the
+ // CallExpr's SourceLocation for future diagnostics.
+ SourceLocation Loc = TheCall->getBeginLoc();
+ bool isArrow = ME->isArrow();
+ Expr *New = ME->getBase();
+ for (NamedDecl *ND : PathToFD) {
+ ValueDecl *VD = cast<ValueDecl>(ND);
+ auto *ME = MemberExpr::CreateImplicit(Context, New, isArrow, VD,
+ VD->getType(), VK_PRValue,
+ OK_Ordinary);
+ ME->setMemberLoc(Loc);
+ New = ME;
+ isArrow = false;
}
+
+ return ExprResult(UnaryOperator::Create(
+ Context, New, UO_AddrOf, Context.getPointerType(CountFD->getType()),
+ VK_LValue, OK_Ordinary, Loc, false, FPOptionsOverride()));
}
}
+ } else {
+ return Diag(Arg->getBeginLoc(),
+ diag::err_builtin_counted_by_ref_must_be_flex_array_member)
+ << Arg->getSourceRange();
}
QualType SizeTypePtrTy = Context.VoidPtrTy;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index bc02a519e06a14..2fe5bd61f41d1b 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -13775,12 +13775,12 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
InvalidUse = true;
Option = 0; // report 'array expression' in diagnostic.
- return VisitStmt(E->getBase()) && VisitStmt(E->getIdx());
+ return true;
}
bool VisitBinaryOperator(BinaryOperator *E) {
InvalidUse = true;
Option = 1; // report 'binary expression' in diagnostic.
- return VisitStmt(E->getLHS()) && VisitStmt(E->getRHS());
+ return true;
}
} V;
V.TraverseStmt(E);
diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index ff863f06007bb2..48c470948e265e 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -2,6 +2,9 @@
typedef unsigned long int size_t;
+int global_array[42];
+int global_int;
+
struct fam_struct {
int x;
char count;
@@ -24,21 +27,25 @@ void test2(struct fam_struct *ptr, int idx) {
__builtin_counted_by_ref(); // expected-error {{too few arguments to function call, expected 1, have 0}}
__builtin_counted_by_ref(ptr->array, ptr->x, ptr->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
__builtin_counted_by_ref(ptr->x); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+ __builtin_counted_by_ref(&ptr->x); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+ __builtin_counted_by_ref(global_array); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+ __builtin_counted_by_ref(global_int); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+ __builtin_counted_by_ref(&global_int); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
__builtin_counted_by_ref(&ptr->array[idx++]); // expected-warning {{'__builtin_counted_by_ref' argument has side-effects that will be discarded}} expected-warning {{expression result unused}}
}
void foo(char *);
void *test3(struct fam_struct *ptr, int size, int idx) {
- char *ref = __builtin_counted_by_ref(ptr->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+ char *ref = __builtin_counted_by_ref(ptr->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
- ref = __builtin_counted_by_ref(ptr->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
- ref = (char *)(int *)(42 + &*__builtin_counted_by_ref(ptr->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
- foo(__builtin_counted_by_ref(ptr->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+ ref = __builtin_counted_by_ref(ptr->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
+ ref = (char *)(int *)(42 + &*__builtin_counted_by_ref(ptr->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
+ foo(__builtin_counted_by_ref(ptr->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
*(__builtin_counted_by_ref(ptr->array) + 4) = 37; // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in a binary expression}}
__builtin_counted_by_ref(ptr->array)[3] = 37; // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in an array subscript expression}}
- return __builtin_counted_by_ref(ptr->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+ return __builtin_counted_by_ref(ptr->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
}
struct non_fam_struct {
>From 985cd02c9e778c8ac5ccd2dd835ca0af6764fddb Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 18 Oct 2024 14:41:18 -0700
Subject: [PATCH 48/59] Move setting that the counter is a bounds-safety
counter to where __builtin_counted_by_ref is processed so that future sema
checks are concerned only with that code path.
---
clang/lib/Sema/SemaBoundsSafety.cpp | 2 --
clang/lib/Sema/SemaChecking.cpp | 2 ++
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaBoundsSafety.cpp b/clang/lib/Sema/SemaBoundsSafety.cpp
index 7d39cbd39c98ed..d63a2389ea11de 100644
--- a/clang/lib/Sema/SemaBoundsSafety.cpp
+++ b/clang/lib/Sema/SemaBoundsSafety.cpp
@@ -162,8 +162,6 @@ bool Sema::CheckCountedByAttrOnField(FieldDecl *FD, Expr *E, bool CountInBytes,
return true;
}
- CountFD->setBoundsSafetyCounter(true);
-
if (FD->getParent() != CountFD->getParent()) {
if (CountFD->getParent()->isUnion()) {
Diag(CountFD->getBeginLoc(), diag::err_count_attr_refer_to_union)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 71aa660c8ed2cb..59915c671d31bf 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5668,6 +5668,8 @@ ExprResult Sema::BuiltinCountedByRef(ExprResult TheCallResult) {
isArrow = false;
}
+ CountFD->setBoundsSafetyCounter(true);
+
return ExprResult(UnaryOperator::Create(
Context, New, UO_AddrOf, Context.getPointerType(CountFD->getType()),
VK_LValue, OK_Ordinary, Loc, false, FPOptionsOverride()));
>From f9ebf9f1747e9aba3e9e8d25d2594b0360281ce3 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 17:12:00 -0700
Subject: [PATCH 49/59] Retain the __builtin_counted_by_ref CallExpr for AST
dumping reasons. We'll lower it during CodeGen.
---
clang/include/clang/AST/Decl.h | 16 ++------
clang/lib/Sema/SemaChecking.cpp | 72 +--------------------------------
clang/lib/Sema/SemaExpr.cpp | 33 ++++++++-------
3 files changed, 21 insertions(+), 100 deletions(-)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 68bafa572bd82a..7ff35d73df5997 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3059,14 +3059,9 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
unsigned BitField : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned Mutable : 1;
- // FIXME: IsBoundsSafetyCounter can be made into an attribute, once some
- // downstream work is in mainline.
- // See https://github.com/llvm/llvm-project/issues/112586
- LLVM_PREFERRED_TYPE(bool)
- unsigned IsBoundsSafetyCounter : 1;
LLVM_PREFERRED_TYPE(InitStorageKind)
unsigned StorageKind : 2;
- mutable unsigned CachedFieldIndex : 27;
+ mutable unsigned CachedFieldIndex : 28;
/// If this is a bitfield with a default member initializer, this
/// structure is used to represent the two expressions.
@@ -3101,8 +3096,8 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
InClassInitStyle InitStyle)
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), BitField(false),
- Mutable(Mutable), IsBoundsSafetyCounter(false),
- StorageKind((InitStorageKind)InitStyle), CachedFieldIndex(0), Init() {
+ Mutable(Mutable), StorageKind((InitStorageKind)InitStyle),
+ CachedFieldIndex(0), Init() {
if (BW)
setBitWidth(BW);
}
@@ -3132,11 +3127,6 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
/// Determines whether this is an unnamed bitfield.
bool isUnnamedBitField() const { return isBitField() && !getDeclName(); }
- /// Returns true if this field decl is referenced by one of the bounds
- /// safety counter attributes.
- bool isBoundsSafetyCounter() const { return IsBoundsSafetyCounter; }
- void setBoundsSafetyCounter(bool V) { IsBoundsSafetyCounter = V; }
-
/// Determines whether this field is a
/// representative for an anonymous struct or union. Such fields are
/// unnamed and are implicitly generated by the implementation to
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 59915c671d31bf..cf24584c918fe8 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -32,7 +32,6 @@
#include "clang/AST/NonTrivialTypeVisitor.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/RecordLayout.h"
-#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
@@ -5610,86 +5609,19 @@ ExprResult Sema::BuiltinCountedByRef(ExprResult TheCallResult) {
Arg = ASE->getBase()->IgnoreParenImpCasts();
}
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(Arg)) {
+ if (const auto *ME = dyn_cast<MemberExpr>(Arg)) {
if (!ME->isFlexibleArrayMemberLike(
Context, getLangOpts().getStrictFlexArraysLevel()))
return Diag(Arg->getBeginLoc(),
diag::err_builtin_counted_by_ref_must_be_flex_array_member)
<< Arg->getSourceRange();
-
- if (auto *CATy =
- ME->getMemberDecl()->getType()->getAs<CountAttributedType>();
- CATy && CATy->getKind() == CountAttributedType::CountedBy) {
- if (FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
- FieldDecl *CountFD = FAMDecl->findCountedByField();
- assert(CountFD && "'count' field couldn't be found");
-
- // Reverse through any anonymous structs / unions surrounding the
- // flexible array member. We'll build any necessary MemberExpr's to
- // anonymous structs / unions when building a reference to the
- // 'count' field.
- RecordDecl *RD = FAMDecl->getParent();
- DeclContext *DC = RD;
- for (; DC->isRecord(); DC = DC->getLexicalParent()) {
- if (!RD->isAnonymousStructOrUnion())
- break;
- RD = cast<RecordDecl>(DC);
- if (auto *Base = dyn_cast<MemberExpr>(ME->getBase()))
- ME = Base;
- }
-
- // See if the count's FieldDecl is within anonymous structs.
- SmallVector<NamedDecl *, 2> PathToFD;
- for (Decl *D : RD->decls()) {
- if (auto *IFD = dyn_cast<IndirectFieldDecl>(D);
- IFD && IFD->getAnonField() == CountFD) {
- PathToFD.insert(PathToFD.begin(), IFD->chain_begin(),
- IFD->chain_end());
- break;
- }
- }
-
- if (PathToFD.empty())
- PathToFD.push_back(CountFD);
-
- // Build a MemberExpr to the 'count' field. This accounts for any
- // anonymous structs / unions that may contain the field. Use the
- // CallExpr's SourceLocation for future diagnostics.
- SourceLocation Loc = TheCall->getBeginLoc();
- bool isArrow = ME->isArrow();
- Expr *New = ME->getBase();
- for (NamedDecl *ND : PathToFD) {
- ValueDecl *VD = cast<ValueDecl>(ND);
- auto *ME = MemberExpr::CreateImplicit(Context, New, isArrow, VD,
- VD->getType(), VK_PRValue,
- OK_Ordinary);
- ME->setMemberLoc(Loc);
- New = ME;
- isArrow = false;
- }
-
- CountFD->setBoundsSafetyCounter(true);
-
- return ExprResult(UnaryOperator::Create(
- Context, New, UO_AddrOf, Context.getPointerType(CountFD->getType()),
- VK_LValue, OK_Ordinary, Loc, false, FPOptionsOverride()));
- }
- }
} else {
return Diag(Arg->getBeginLoc(),
diag::err_builtin_counted_by_ref_must_be_flex_array_member)
<< Arg->getSourceRange();
}
- QualType SizeTypePtrTy = Context.VoidPtrTy;
- QualType NullPtrTy =
- Context.getIntTypeForBitwidth(Context.getIntWidth(SizeTypePtrTy), true);
-
- return ExprResult(ImplicitCastExpr::Create(
- Context, SizeTypePtrTy, CK_IntegralToPointer,
- IntegerLiteral::Create(Context, Context.MakeIntValue(0, NullPtrTy),
- NullPtrTy, SourceLocation()),
- nullptr, VK_LValue, FPOptionsOverride()));
+ return false;
}
namespace {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 2fe5bd61f41d1b..1fcbee174106d4 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -28,6 +28,7 @@
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/OperationKinds.h"
+#include "clang/AST/ParentMapContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
@@ -9191,16 +9192,15 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
auto FindBuiltinCountedByRefExpr = [](Expr *E) {
struct BuiltinCountedByRefVisitor
: public RecursiveASTVisitor<BuiltinCountedByRefVisitor> {
- MemberExpr *ME = nullptr;
- bool VisitMemberExpr(MemberExpr *E) {
- if (auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
- FD && FD->isBoundsSafetyCounter())
- ME = E;
- return true;
+ CallExpr *CE = nullptr;
+ bool VisitCallExpr(CallExpr *E) {
+ if (E->getBuiltinCallee() == Builtin::BI__builtin_counted_by_ref)
+ CE = E;
+ return false;
}
} V;
V.TraverseStmt(E);
- return V.ME;
+ return V.CE;
};
if (auto *CE = FindBuiltinCountedByRefExpr(RHS.get()))
Diag(CE->getExprLoc(),
@@ -13761,15 +13761,14 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
auto FindInvalidUseOfBoundsSafetyCounter = [&](Expr *E) {
struct BuiltinCountedByRefVisitor
: public RecursiveASTVisitor<BuiltinCountedByRefVisitor> {
- MemberExpr *ME = nullptr;
+ CallExpr *CE = nullptr;
bool InvalidUse = false;
int Option = -1;
- bool VisitMemberExpr(MemberExpr *E) {
- if (auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
- FD && FD->isBoundsSafetyCounter())
- ME = E;
- return true;
+ bool VisitCallExpr(CallExpr *E) {
+ if (E->getBuiltinCallee() == Builtin::BI__builtin_counted_by_ref)
+ CE = E;
+ return false;
}
bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
@@ -13785,11 +13784,11 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
} V;
V.TraverseStmt(E);
DiagOption = V.Option;
- return V.InvalidUse ? V.ME : nullptr;
+ return V.InvalidUse ? V.CE : nullptr;
};
- if (auto *E = FindInvalidUseOfBoundsSafetyCounter(LHSExpr))
- Diag(E->getExprLoc(), diag::err_builtin_counted_by_ref_invalid_lhs_use)
- << DiagOption << E->getSourceRange();
+ if (auto *CE = FindInvalidUseOfBoundsSafetyCounter(LHSExpr))
+ Diag(CE->getExprLoc(), diag::err_builtin_counted_by_ref_invalid_lhs_use)
+ << DiagOption << CE->getSourceRange();
if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType, RHS.get(),
AssignmentAction::Assigning))
>From a5245e5d6e026f389e64245a8ce4df643abec4a5 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 17:59:11 -0700
Subject: [PATCH 50/59] Fix
---
clang/lib/Sema/SemaChecking.cpp | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index cf24584c918fe8..f5969cf3e26e8d 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5577,9 +5577,7 @@ bool Sema::BuiltinSetjmp(CallExpr *TheCall) {
return false;
}
-ExprResult Sema::BuiltinCountedByRef(ExprResult TheCallResult) {
- CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
-
+bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
if (checkArgCount(TheCall, 1))
return true;
>From 271bb8f9a3d80ca9e3f51c3401d8561496be0355 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 18:10:49 -0700
Subject: [PATCH 51/59] Reformat
---
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 b6b30beede8c29..c28f5dd26e3bd9 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -30,7 +30,6 @@
#include "clang/AST/OSLog.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/Type.h"
-#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
@@ -3692,6 +3691,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(emitBuiltinObjectSize(E->getArg(0), Type, ResType,
/*EmittedE=*/nullptr, IsDynamic));
}
+#if 0
case Builtin::BI__builtin_counted_by_ref: {
llvm::Value *Result = llvm::ConstantPointerNull::get(
cast<llvm::PointerType>(ConvertType(E->getType())));
@@ -3767,6 +3767,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Result);
}
+#endif
case Builtin::BI__builtin_prefetch: {
Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0));
// FIXME: Technically these constants should of type 'int', yes?
>From ceb43e5ee00c34fcd6bfc87e7af1a4e57b0bc57f Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 19:37:17 -0700
Subject: [PATCH 52/59] Add correct attribute checking and set the return type.
---
clang/lib/Sema/SemaChecking.cpp | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index f5969cf3e26e8d..3b0bcb63d4cb5f 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5613,12 +5613,23 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
return Diag(Arg->getBeginLoc(),
diag::err_builtin_counted_by_ref_must_be_flex_array_member)
<< Arg->getSourceRange();
+
+ if (auto *CATy =
+ ME->getMemberDecl()->getType()->getAs<CountAttributedType>();
+ CATy && CATy->getKind() == CountAttributedType::CountedBy) {
+ const auto *FAMDecl = cast<FieldDecl>(ME->getMemberDecl());
+ if (const FieldDecl *CountFD = FAMDecl->findCountedByField()) {
+ TheCall->setType(Context.getPointerType(CountFD->getType()));
+ return false;
+ }
+ }
} else {
return Diag(Arg->getBeginLoc(),
diag::err_builtin_counted_by_ref_must_be_flex_array_member)
<< Arg->getSourceRange();
}
+ TheCall->setType(Context.getPointerType(Context.VoidTy));
return false;
}
>From b01526d897516fe35a7a50403a5eed39075fbe97 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 19:38:01 -0700
Subject: [PATCH 53/59] Generate LLVM IR for the __builtin_counted_by_ref.
---
clang/lib/CodeGen/CGBuiltin.cpp | 66 +++++----------------------------
1 file changed, 9 insertions(+), 57 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index c28f5dd26e3bd9..e382f8b3d3d2cf 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3691,10 +3691,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(emitBuiltinObjectSize(E->getArg(0), Type, ResType,
/*EmittedE=*/nullptr, IsDynamic));
}
-#if 0
case Builtin::BI__builtin_counted_by_ref: {
+ // Default to returning '(void *) 0'.
llvm::Value *Result = llvm::ConstantPointerNull::get(
- cast<llvm::PointerType>(ConvertType(E->getType())));
+ llvm::PointerType::getUnqual(getLLVMContext()));
const Expr *Arg = E->getArg(0)->IgnoreParenImpCasts();
@@ -3707,67 +3707,19 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}
if (const MemberExpr *ME = dyn_cast_if_present<MemberExpr>(Arg)) {
- bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
- getContext(), getLangOpts().getStrictFlexArraysLevel());
-
- if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
- ME->getMemberDecl()->getType()->isCountAttributedType()) {
- FieldDecl *FAMDecl = cast<FieldDecl>(ME->getMemberDecl());
- if (FieldDecl *CountFD = FAMDecl->findCountedByField()) {
- QualType CountTy = CountFD->getType();
- SmallVector<NamedDecl *, 2> PathToFD;
-
- // Reverse through any anonymous structs / unions surrounding the
- // flexible array member. We'll build any necessary MemberExpr's to
- // anonymous structs / unions when building a reference to the
- // 'count' field.
- RecordDecl *RD = FAMDecl->getParent();
- DeclContext *DC = RD;
- for (; DC->isRecord(); DC = DC->getLexicalParent()) {
- if (!RD->isAnonymousStructOrUnion())
- break;
- RD = cast<RecordDecl>(DC);
- if (auto *Base = dyn_cast<MemberExpr>(ME->getBase()))
- ME = Base;
- }
-
- // See if the count's FieldDecl is within anonymous structs.
- for (Decl *D : RD->decls()) {
- if (auto *IFD = dyn_cast<IndirectFieldDecl>(D);
- IFD && IFD->getAnonField() == CountFD) {
- PathToFD.insert(PathToFD.begin(), IFD->chain_begin(),
- IFD->chain_end());
- break;
- }
- }
-
- if (PathToFD.empty())
- PathToFD.push_back(CountFD);
-
- // Build a MemberExpr to the 'count' field. This accounts for any
- // anonymous structs / unions that may contain the field.
- bool isArrow = ME->isArrow();
- Expr *New = ME->getBase();
- for (NamedDecl *ND : PathToFD) {
- ValueDecl *VD = cast<ValueDecl>(ND);
- New = MemberExpr::CreateImplicit(
- Ctx, New, isArrow, VD, VD->getType(), VK_PRValue, OK_Ordinary);
- isArrow = false;
- }
-
- // The result is a pointer to the 'count' field.
- Result = EmitScalarExpr(UnaryOperator::Create(
- Ctx, New, UO_AddrOf, Ctx.getPointerType(CountTy), VK_LValue,
- OK_Ordinary, SourceLocation(), false, FPOptionsOverride()));
- } else {
+ if (auto *CATy =
+ ME->getMemberDecl()->getType()->getAs<CountAttributedType>();
+ CATy && CATy->getKind() == CountAttributedType::CountedBy) {
+ const auto *FAMDecl = cast<FieldDecl>(ME->getMemberDecl());
+ if (const FieldDecl *CountFD = FAMDecl->findCountedByField())
+ Result = GetCountedByFieldExprGEP(Arg, FAMDecl, CountFD);
+ else
llvm::report_fatal_error("Cannot find the counted_by 'count' field");
- }
}
}
return RValue::get(Result);
}
-#endif
case Builtin::BI__builtin_prefetch: {
Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0));
// FIXME: Technically these constants should of type 'int', yes?
>From 76aabde4db66343a2181e39098b546e45a5fc8d3 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 19:58:11 -0700
Subject: [PATCH 54/59] Set InBounds on the GEP.
---
clang/lib/CodeGen/CGBuiltin.cpp | 7 +-
clang/test/CodeGen/attr-counted-by.c | 124 +++++++++++++--------------
2 files changed, 67 insertions(+), 64 deletions(-)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index e382f8b3d3d2cf..fb517803e77141 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3711,10 +3711,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
ME->getMemberDecl()->getType()->getAs<CountAttributedType>();
CATy && CATy->getKind() == CountAttributedType::CountedBy) {
const auto *FAMDecl = cast<FieldDecl>(ME->getMemberDecl());
- if (const FieldDecl *CountFD = FAMDecl->findCountedByField())
+ if (const FieldDecl *CountFD = FAMDecl->findCountedByField()) {
Result = GetCountedByFieldExprGEP(Arg, FAMDecl, CountFD);
- else
+ cast<llvm::GetElementPtrInst>(Result)->setNoWrapFlags(
+ GEPNoWrapFlags::inBounds());
+ } else {
llvm::report_fatal_error("Cannot find the counted_by 'count' field");
+ }
}
}
diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c
index ec350991f176ef..20406c5b86cc48 100644
--- a/clang/test/CodeGen/attr-counted-by.c
+++ b/clang/test/CodeGen/attr-counted-by.c
@@ -108,7 +108,7 @@ void test1(struct annotated *p, int index, int val) {
// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test2(
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
-// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[DOT_COUNTED_BY_LOAD]] to i64, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ult i64 [[INDEX]], [[TMP0]], !nosanitize [[META2]]
@@ -128,7 +128,7 @@ void test1(struct annotated *p, int index, int val) {
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test2(
// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
-// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0
@@ -161,7 +161,7 @@ void test2(struct annotated *p, size_t index) {
// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -8589934592, 8589934589) i64 @test2_bdos(
// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
-// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = sext i32 [[DOT_COUNTED_BY_LOAD]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl nsw i64 [[TMP0]], 2
@@ -172,7 +172,7 @@ void test2(struct annotated *p, size_t index) {
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -8589934592, 8589934589) i64 @test2_bdos(
// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
-// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = sext i32 [[DOT_COUNTED_BY_LOAD]] to i64
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl nsw i64 [[TMP0]], 2
@@ -268,7 +268,7 @@ size_t test3_bdos(struct annotated *p) {
// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test4(
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]], i32 noundef [[FAM_IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
-// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
@@ -330,7 +330,7 @@ size_t test3_bdos(struct annotated *p) {
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test4(
// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[INDEX:%.*]], i32 noundef [[FAM_IDX:%.*]]) local_unnamed_addr #[[ATTR1]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
-// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = add i32 [[TMP0]], 244
@@ -412,7 +412,7 @@ void test4(struct annotated *p, int index, int fam_idx) {
// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -17179869180, 17179869181) i64 @test4_bdos(
// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR2]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
-// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = sext i32 [[DOT_COUNTED_BY_LOAD]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = sext i32 [[INDEX]] to i64
@@ -427,7 +427,7 @@ void test4(struct annotated *p, int index, int fam_idx) {
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -17179869180, 17179869181) i64 @test4_bdos(
// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR2]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
-// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = sext i32 [[DOT_COUNTED_BY_LOAD]] to i64
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = sext i32 [[INDEX]] to i64
@@ -528,7 +528,7 @@ size_t test5_bdos(struct anon_struct *p) {
// 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: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ugt i64 [[DOT_COUNTED_BY_LOAD]], [[IDXPROM]], !nosanitize [[META2]]
@@ -549,7 +549,7 @@ size_t test5_bdos(struct anon_struct *p) {
// 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: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD_TR:%.*]] = trunc i64 [[DOT_COUNTED_BY_LOAD]] to i32
@@ -586,7 +586,7 @@ void test6(struct anon_struct *p, int index) {
// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, -3) i64 @test6_bdos(
// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
-// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = shl nuw i64 [[DOT_COUNTED_BY_LOAD]], 2
// SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0
@@ -596,7 +596,7 @@ void test6(struct anon_struct *p, int index) {
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, -3) i64 @test6_bdos(
// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
-// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = shl nuw i64 [[DOT_COUNTED_BY_LOAD]], 2
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0
@@ -693,7 +693,7 @@ size_t test7_bdos(struct union_of_fams *p) {
// 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: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i8, ptr [[DOT_COUNTED_BY_GEP]], align 4
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i8 [[DOT_COUNTED_BY_LOAD]] to i64, !nosanitize [[META2]]
@@ -703,7 +703,7 @@ size_t test7_bdos(struct union_of_fams *p) {
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB12:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont7:
-// SANITIZE-WITH-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9
+// SANITIZE-WITH-ATTR-NEXT: [[INTS:%.*]] = getelementptr i8, ptr [[P]], i64 9
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[IDXPROM]]
// SANITIZE-WITH-ATTR-NEXT: store i8 [[DOT_COUNTED_BY_LOAD]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA8]]
// SANITIZE-WITH-ATTR-NEXT: ret void
@@ -711,9 +711,9 @@ size_t test7_bdos(struct union_of_fams *p) {
// 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: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i8, ptr [[DOT_COUNTED_BY_GEP]], align 4
-// NO-SANITIZE-WITH-ATTR-NEXT: [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9
+// NO-SANITIZE-WITH-ATTR-NEXT: [[INTS:%.*]] = getelementptr 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 [[DOT_COUNTED_BY_LOAD]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]]
@@ -744,7 +744,7 @@ void test8(struct union_of_fams *p, int index) {
// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 256) i64 @test8_bdos(
// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
-// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i8, ptr [[DOT_COUNTED_BY_GEP]], align 4
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i8 [[DOT_COUNTED_BY_LOAD]] to i64
// SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP0]]
@@ -752,7 +752,7 @@ void test8(struct union_of_fams *p, int index) {
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 256) i64 @test8_bdos(
// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
-// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i8, ptr [[DOT_COUNTED_BY_GEP]], align 4
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i8 [[DOT_COUNTED_BY_LOAD]] to i64
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP0]]
@@ -847,7 +847,7 @@ size_t test9_bdos(struct union_of_fams *p) {
// 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: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[DOT_COUNTED_BY_LOAD]] to i64, !nosanitize [[META2]]
@@ -857,7 +857,7 @@ size_t test9_bdos(struct union_of_fams *p) {
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB15:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont7:
-// SANITIZE-WITH-ATTR-NEXT: [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12
+// SANITIZE-WITH-ATTR-NEXT: [[BYTES:%.*]] = getelementptr i8, ptr [[P]], i64 12
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[IDXPROM]]
// SANITIZE-WITH-ATTR-NEXT: [[NARROW:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0)
// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = trunc i32 [[NARROW]] to i8
@@ -867,11 +867,11 @@ size_t test9_bdos(struct union_of_fams *p) {
// 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: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// NO-SANITIZE-WITH-ATTR-NEXT: [[NARROW:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0)
// 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: [[BYTES:%.*]] = getelementptr 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 [[TBAA6]]
@@ -902,7 +902,7 @@ void test10(struct union_of_fams *p, int index) {
// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 2147483648) i64 @test10_bdos(
// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
-// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// SANITIZE-WITH-ATTR-NEXT: [[NARROW:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0)
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext nneg i32 [[NARROW]] to i64
@@ -911,7 +911,7 @@ void test10(struct union_of_fams *p, int index) {
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 2147483648) i64 @test10_bdos(
// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
-// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// NO-SANITIZE-WITH-ATTR-NEXT: [[NARROW:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0)
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext nneg i32 [[NARROW]] to i64
@@ -947,16 +947,16 @@ struct hang {
int test11_a, test11_b;
// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test11(
-// SANITIZE-WITH-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] {
+// SANITIZE-WITH-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR4:[0-9]+]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: [[BAZ:%.*]] = alloca [[STRUCT_HANG:%.*]], align 4
-// SANITIZE-WITH-ATTR-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR11:[0-9]+]]
+// SANITIZE-WITH-ATTR-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR10:[0-9]+]]
// SANITIZE-WITH-ATTR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test11_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT9:![0-9]+]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ult i32 [[INDEX]], 6
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = zext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP0]], label [[CONT:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB17:[0-9]+]], i64 [[TMP1]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB17:[0-9]+]], i64 [[TMP1]]) #[[ATTR9]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont:
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [6 x i32], ptr [[BAZ]], i64 0, i64 [[TMP1]]
@@ -966,17 +966,17 @@ int test11_a, test11_b;
// SANITIZE-WITH-ATTR-NEXT: [[DOTNOT:%.*]] = icmp eq i32 [[DOTCOUNTED_BY_LOAD]], 0
// SANITIZE-WITH-ATTR-NEXT: br i1 [[DOTNOT]], label [[HANDLER_OUT_OF_BOUNDS4:%.*]], label [[HANDLER_TYPE_MISMATCH6:%.*]], !prof [[PROF10:![0-9]+]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds4:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB19:[0-9]+]], i64 0) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB19:[0-9]+]], i64 0) #[[ATTR9]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.type_mismatch6:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_type_mismatch_v1_abort(ptr nonnull @[[GLOB20:[0-9]+]], i64 ptrtoint (ptr getelementptr inbounds nuw (i8, ptr @test11_foo, i64 4) to i64)) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_type_mismatch_v1_abort(ptr nonnull @[[GLOB20:[0-9]+]], i64 ptrtoint (ptr getelementptr inbounds nuw (i8, ptr @test11_foo, i64 4) to i64)) #[[ATTR9]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test11(
-// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] {
+// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR4:[0-9]+]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[BAZ:%.*]] = alloca [[STRUCT_HANG:%.*]], align 4
-// NO-SANITIZE-WITH-ATTR-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR12:[0-9]+]]
+// NO-SANITIZE-WITH-ATTR-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR11:[0-9]+]]
// NO-SANITIZE-WITH-ATTR-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test11_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]]
// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [6 x i32], ptr [[BAZ]], i64 0, i64 [[IDXPROM]]
@@ -1059,7 +1059,7 @@ struct test12_bar {
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = icmp ult i64 [[INDEX]], [[TMP1]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label [[CONT5:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB23:[0-9]+]], i64 [[INDEX]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB23:[0-9]+]], i64 [[INDEX]]) #[[ATTR9]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont5:
// SANITIZE-WITH-ATTR-NEXT: [[REVMAP:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 16
@@ -1068,7 +1068,7 @@ struct test12_bar {
// SANITIZE-WITH-ATTR-NEXT: ret i32 0
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test12(
-// NO-SANITIZE-WITH-ATTR-SAME: i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR8:[0-9]+]] {
+// NO-SANITIZE-WITH-ATTR-SAME: i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR7:[0-9]+]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr @test12_f, align 8, !tbaa [[TBAA8:![0-9]+]]
// NO-SANITIZE-WITH-ATTR-NEXT: [[REVMAP:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 16
@@ -1120,14 +1120,14 @@ struct test13_foo {
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP0]], label [[TRAP:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB24:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB24:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: trap:
// SANITIZE-WITH-ATTR-NEXT: tail call void @llvm.trap() #[[ATTR9]]
// SANITIZE-WITH-ATTR-NEXT: unreachable
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test13(
-// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_TEST13_FOO:%.*]], align 4
// NO-SANITIZE-WITH-ATTR-NEXT: store i32 1, ptr [[DOTCOMPOUNDLITERAL]], align 4, !tbaa [[TBAA2]]
@@ -1176,14 +1176,14 @@ int test13(int idx) {
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP0]], label [[TRAP:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB26:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB26:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: trap:
// SANITIZE-WITH-ATTR-NEXT: tail call void @llvm.trap() #[[ATTR9]]
// SANITIZE-WITH-ATTR-NEXT: unreachable
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test14(
-// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr getelementptr inbounds nuw (i8, ptr @__const.test14.foo, i64 8), i64 0, i64 [[IDXPROM]]
@@ -1221,12 +1221,12 @@ int test14(int idx) {
}
// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test15(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test15(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
@@ -1246,12 +1246,12 @@ size_t test15(struct annotated *p) {
}
// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test16(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test16(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
@@ -1271,12 +1271,12 @@ size_t test16(struct annotated *p) {
}
// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test17(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test17(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
@@ -1296,12 +1296,12 @@ size_t test17(struct annotated *p) {
}
// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test18(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test18(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
@@ -1358,7 +1358,7 @@ struct tests_foo {
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ugt i32 [[DOTCOUNTED_BY_LOAD]], 10
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP0]], label [[CONT4:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB27:[0-9]+]], i64 10) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB27:[0-9]+]], i64 10) #[[ATTR9]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont4:
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds i8, ptr [[VAR]], i64 84
@@ -1399,7 +1399,7 @@ int test20(int c, struct tests_foo *var) {
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[DOTCOUNTED_BY_LOAD]], 10
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label [[CONT5:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB28:[0-9]+]], i64 10) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB28:[0-9]+]], i64 10) #[[ATTR9]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont5:
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 44
@@ -1407,7 +1407,7 @@ int test20(int c, struct tests_foo *var) {
// SANITIZE-WITH-ATTR-NEXT: ret i32 [[TMP2]]
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test21(
-// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[VAR:%.*]]) local_unnamed_addr #[[ATTR9:[0-9]+]] {
+// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[VAR:%.*]]) local_unnamed_addr #[[ATTR8:[0-9]+]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[VAR]], align 8, !tbaa [[TBAA11]]
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 44
@@ -1451,7 +1451,7 @@ struct test22_foo {
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label [[CONT5:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB29:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB29:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont5:
// SANITIZE-WITH-ATTR-NEXT: [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
@@ -1522,7 +1522,7 @@ struct test23_foo {
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label [[CONT3:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB31:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB31:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont3:
// SANITIZE-WITH-ATTR-NEXT: [[ENTRIES:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 24
@@ -1588,7 +1588,7 @@ struct test24_foo {
// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP4]], label [[CONT17:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB33:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB33:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont17:
// SANITIZE-WITH-ATTR-NEXT: [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP2]], i64 12
@@ -1597,7 +1597,7 @@ struct test24_foo {
// SANITIZE-WITH-ATTR-NEXT: ret i32 [[TMP5]]
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test24(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR9]] {
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR8]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P]], align 8, !tbaa [[TBAA11]]
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load ptr, ptr [[TMP0]], align 8, !tbaa [[TBAA11]]
@@ -1650,19 +1650,19 @@ struct annotated_struct_array {
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = zext i32 [[IDX1]] to i64
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP0]], label [[CONT3:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB35:[0-9]+]], i64 [[TMP1]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB35:[0-9]+]], i64 [[TMP1]]) #[[ATTR9]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont3:
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x ptr], ptr [[ANN]], i64 0, i64 [[TMP1]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA14]]
-// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP2]], i64 8
+// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[TMP2]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM15:%.*]] = sext i32 [[IDX2]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i32 [[DOT_COUNTED_BY_LOAD]] to i64, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = icmp ult i64 [[IDXPROM15]], [[TMP3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP4]], label [[CONT20:%.*]], label [[HANDLER_OUT_OF_BOUNDS16:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds16:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB36:[0-9]+]], i64 [[IDXPROM15]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB36:[0-9]+]], i64 [[IDXPROM15]]) #[[ATTR9]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont20:
// SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP2]], i64 12
@@ -1674,12 +1674,12 @@ struct annotated_struct_array {
// SANITIZE-WITH-ATTR-NEXT: ret void
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test25(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[ANN:%.*]], i32 noundef [[IDX1:%.*]], i32 noundef [[IDX2:%.*]]) local_unnamed_addr #[[ATTR10:[0-9]+]] {
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[ANN:%.*]], i32 noundef [[IDX1:%.*]], i32 noundef [[IDX2:%.*]]) local_unnamed_addr #[[ATTR9:[0-9]+]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX1]] to i64
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x ptr], ptr [[ANN]], i64 0, i64 [[IDXPROM]]
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA11]]
-// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[TMP0]], i64 8
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0
@@ -1736,14 +1736,14 @@ struct test26_struct {
};
// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test26(
-// SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR5]] {
+// SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR4]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[IDX]] to i64, !nosanitize [[META2]]
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB38:[0-9]+]], i64 [[TMP0]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB38:[0-9]+]], i64 [[TMP0]]) #[[ATTR9]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test26(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR1]] {
+// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[PCPU_REFCNT:%.*]] = getelementptr inbounds nuw i8, ptr [[PTR]], i64 12
// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
@@ -1780,12 +1780,12 @@ struct test27_struct {
};
// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test27(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: ret i32 -1
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test27(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: ret i32 -1
//
>From c3901685b754eec3a949365f00b608c06db20d51 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 19:59:42 -0700
Subject: [PATCH 55/59] Regenerate testcase.
---
clang/test/CodeGen/builtin-counted-by-ref.c | 24 ++++++++++-----------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/clang/test/CodeGen/builtin-counted-by-ref.c b/clang/test/CodeGen/builtin-counted-by-ref.c
index 8fcab0086521fd..fdb63c17673962 100644
--- a/clang/test/CodeGen/builtin-counted-by-ref.c
+++ b/clang/test/CodeGen/builtin-counted-by-ref.c
@@ -16,8 +16,8 @@ struct a {
// X86_64-NEXT: [[ADD:%.*]] = add nsw i64 [[MUL]], 4
// X86_64-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3:[0-9]+]]
// X86_64-NEXT: [[CONV1:%.*]] = trunc i32 [[SIZE]] to i16
-// X86_64-NEXT: [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 2
-// X86_64-NEXT: store i16 [[CONV1]], ptr [[COUNT]], align 2, !tbaa [[TBAA2:![0-9]+]]
+// X86_64-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 2
+// X86_64-NEXT: store i16 [[CONV1]], ptr [[DOT_COUNTED_BY_GEP]], align 2, !tbaa [[TBAA2:![0-9]+]]
// X86_64-NEXT: ret ptr [[CALL]]
//
// I386-LABEL: define dso_local noalias noundef ptr @test1(
@@ -27,8 +27,8 @@ struct a {
// I386-NEXT: [[ADD:%.*]] = add i32 [[MUL]], 4
// I386-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3:[0-9]+]]
// I386-NEXT: [[CONV:%.*]] = trunc i32 [[SIZE]] to i16
-// I386-NEXT: [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i32 2
-// I386-NEXT: store i16 [[CONV]], ptr [[COUNT]], align 2, !tbaa [[TBAA3:![0-9]+]]
+// I386-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i32 2
+// I386-NEXT: store i16 [[CONV]], ptr [[DOT_COUNTED_BY_GEP]], align 2, !tbaa [[TBAA3:![0-9]+]]
// I386-NEXT: ret ptr [[CALL]]
//
struct a *test1(int size) {
@@ -69,8 +69,8 @@ struct b {
// X86_64-NEXT: [[ADD:%.*]] = add nsw i64 [[MUL]], 4
// X86_64-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3]]
// X86_64-NEXT: [[CONV1:%.*]] = trunc i32 [[SIZE]] to i8
-// X86_64-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 12
-// X86_64-NEXT: store i8 [[CONV1]], ptr [[TMP0]], align 1, !tbaa [[TBAA6:![0-9]+]]
+// X86_64-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 12
+// X86_64-NEXT: store i8 [[CONV1]], ptr [[DOT_COUNTED_BY_GEP]], align 1, !tbaa [[TBAA6:![0-9]+]]
// X86_64-NEXT: ret ptr [[CALL]]
//
// I386-LABEL: define dso_local noalias noundef ptr @test2(
@@ -80,8 +80,8 @@ struct b {
// I386-NEXT: [[ADD:%.*]] = add i32 [[MUL]], 4
// I386-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3]]
// I386-NEXT: [[CONV:%.*]] = trunc i32 [[SIZE]] to i8
-// I386-NEXT: [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i32 12
-// I386-NEXT: store i8 [[CONV]], ptr [[TMP0]], align 1, !tbaa [[TBAA7:![0-9]+]]
+// I386-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i32 12
+// I386-NEXT: store i8 [[CONV]], ptr [[DOT_COUNTED_BY_GEP]], align 1, !tbaa [[TBAA7:![0-9]+]]
// I386-NEXT: ret ptr [[CALL]]
//
struct b *test2(int size) {
@@ -141,8 +141,8 @@ struct d {
// X86_64-NEXT: [[ADD:%.*]] = add nsw i64 [[MUL]], 4
// X86_64-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3]]
// X86_64-NEXT: [[CONV1:%.*]] = trunc i32 [[SIZE]] to i16
-// X86_64-NEXT: [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 2
-// X86_64-NEXT: store i16 [[CONV1]], ptr [[COUNT]], align 2, !tbaa [[TBAA2]]
+// X86_64-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 2
+// X86_64-NEXT: store i16 [[CONV1]], ptr [[DOT_COUNTED_BY_GEP]], align 2, !tbaa [[TBAA2]]
// X86_64-NEXT: ret ptr [[CALL]]
//
// I386-LABEL: define dso_local noalias noundef ptr @test4(
@@ -152,8 +152,8 @@ struct d {
// I386-NEXT: [[ADD:%.*]] = add i32 [[MUL]], 4
// I386-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3]]
// I386-NEXT: [[CONV:%.*]] = trunc i32 [[SIZE]] to i16
-// I386-NEXT: [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i32 2
-// I386-NEXT: store i16 [[CONV]], ptr [[COUNT]], align 2, !tbaa [[TBAA3]]
+// I386-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i32 2
+// I386-NEXT: store i16 [[CONV]], ptr [[DOT_COUNTED_BY_GEP]], align 2, !tbaa [[TBAA3]]
// I386-NEXT: ret ptr [[CALL]]
//
struct d *test4(int size, int idx) {
>From 213b00df1ee1e39dc555f0c6ac6210043fc2655f Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 20:05:46 -0700
Subject: [PATCH 56/59] Remove warning that no longer shows up.
---
clang/test/Sema/builtin-counted-by-ref.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index 48c470948e265e..20fa634fcbdf07 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -31,7 +31,7 @@ void test2(struct fam_struct *ptr, int idx) {
__builtin_counted_by_ref(global_array); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
__builtin_counted_by_ref(global_int); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
__builtin_counted_by_ref(&global_int); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
- __builtin_counted_by_ref(&ptr->array[idx++]); // expected-warning {{'__builtin_counted_by_ref' argument has side-effects that will be discarded}} expected-warning {{expression result unused}}
+ __builtin_counted_by_ref(&ptr->array[idx++]); // expected-warning {{'__builtin_counted_by_ref' argument has side-effects that will be discarded}}
}
void foo(char *);
>From c4509f2d26c4f3308ef1d0d97499ed76b59940e3 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 20:07:20 -0700
Subject: [PATCH 57/59] Regenerate testcase
---
clang/test/CodeGen/attr-counted-by-pr110385.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/clang/test/CodeGen/attr-counted-by-pr110385.c b/clang/test/CodeGen/attr-counted-by-pr110385.c
index e120dcc583578d..6136ce77a2570b 100644
--- a/clang/test/CodeGen/attr-counted-by-pr110385.c
+++ b/clang/test/CodeGen/attr-counted-by-pr110385.c
@@ -31,7 +31,7 @@ void init(void * __attribute__((pass_dynamic_object_size(0))));
// CHECK-NEXT: [[GROWABLE:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[GROWABLE]], align 8, !tbaa [[TBAA2:![0-9]+]]
// CHECK-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 12
-// CHECK-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 8
+// CHECK-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[TMP0]], i64 8
// CHECK-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[DOT_COUNTED_BY_LOAD]] to i64
// CHECK-NEXT: [[TMP2:%.*]] = shl nsw i64 [[TMP1]], 1
@@ -48,7 +48,7 @@ void test1(struct bucket *foo) {
// CHECK-SAME: ptr noundef [[FOO:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 16
-// CHECK-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[FOO]], i64 12
+// CHECK-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[FOO]], i64 12
// CHECK-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[DOT_COUNTED_BY_LOAD]] to i64
// CHECK-NEXT: [[TMP1:%.*]] = shl nsw i64 [[TMP0]], 1
@@ -60,3 +60,11 @@ void test1(struct bucket *foo) {
void test2(struct bucket2 *foo) {
init(foo->growable.array);
}
+//.
+// CHECK: [[TBAA2]] = !{[[META3:![0-9]+]], [[META7:![0-9]+]], i64 8}
+// CHECK: [[META3]] = !{!"bucket", [[META4:![0-9]+]], i64 0, [[META7]], i64 8, [[META4]], i64 16}
+// CHECK: [[META4]] = !{!"int", [[META5:![0-9]+]], i64 0}
+// CHECK: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0}
+// CHECK: [[META6]] = !{!"Simple C/C++ TBAA"}
+// CHECK: [[META7]] = !{!"any pointer", [[META5]], i64 0}
+//.
>From e22f7ef2028ef4e2e4ccab94a19d393cffcf29ad Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 1 Nov 2024 15:28:12 -0700
Subject: [PATCH 58/59] Expand testing. This includes a hack to prevent
multiple diagnostics for the same issue.
---
clang/lib/Sema/SemaExpr.cpp | 34 +++++++++++++++++-------
clang/test/Sema/builtin-counted-by-ref.c | 28 +++++++++++++++----
2 files changed, 47 insertions(+), 15 deletions(-)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 1fcbee174106d4..fc3438bc1207b6 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -9189,23 +9189,35 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// __builtin_counted_by_ref cannot be assigned to a variable, used in
// function call, or in a return.
- auto FindBuiltinCountedByRefExpr = [](Expr *E) {
+ auto FindBuiltinCountedByRefExpr = [&](Expr *E) -> CallExpr * {
struct BuiltinCountedByRefVisitor
: public RecursiveASTVisitor<BuiltinCountedByRefVisitor> {
- CallExpr *CE = nullptr;
- bool VisitCallExpr(CallExpr *E) {
- if (E->getBuiltinCallee() == Builtin::BI__builtin_counted_by_ref)
- CE = E;
+ CallExpr *TheCall = nullptr;
+ bool VisitCallExpr(CallExpr *CE) {
+ if (CE->getBuiltinCallee() == Builtin::BI__builtin_counted_by_ref) {
+ TheCall = CE;
+ return false;
+ }
+ return true;
+ }
+ bool VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE) {
+ // A UnaryExprOrTypeTraitExpr---e.g. sizeof, __alignof, etc.---isn't
+ // the same as a CallExpr, so if we find a __builtin_counted_by_ref()
+ // call in one, ignore it.
return false;
}
} V;
V.TraverseStmt(E);
- return V.CE;
+ return V.TheCall;
};
- if (auto *CE = FindBuiltinCountedByRefExpr(RHS.get()))
+ static llvm::SmallPtrSet<CallExpr *, 4> Diagnosed;
+ if (auto *CE = FindBuiltinCountedByRefExpr(RHS.get());
+ CE && !Diagnosed.count(CE)) {
+ Diagnosed.insert(CE);
Diag(CE->getExprLoc(),
diag::err_builtin_counted_by_ref_cannot_leak_reference)
<< CE->getSourceRange();
+ }
// Common case: no conversion required.
if (LHSType == RHSType) {
@@ -13758,7 +13770,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
// __builtin_counted_by_ref can't be used in a binary expression or array
// subscript on the LHS.
int DiagOption = -1;
- auto FindInvalidUseOfBoundsSafetyCounter = [&](Expr *E) {
+ auto FindInvalidUseOfBoundsSafetyCounter = [&](Expr *E) -> CallExpr * {
struct BuiltinCountedByRefVisitor
: public RecursiveASTVisitor<BuiltinCountedByRefVisitor> {
CallExpr *CE = nullptr;
@@ -13766,9 +13778,11 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
int Option = -1;
bool VisitCallExpr(CallExpr *E) {
- if (E->getBuiltinCallee() == Builtin::BI__builtin_counted_by_ref)
+ if (E->getBuiltinCallee() == Builtin::BI__builtin_counted_by_ref) {
CE = E;
- return false;
+ return false;
+ }
+ return true;
}
bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index 20fa634fcbdf07..c3f59197fdc5e1 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -12,6 +12,8 @@ struct fam_struct {
};
void test1(struct fam_struct *ptr, int size, int idx) {
+ size_t size_of = sizeof(__builtin_counted_by_ref(ptr->array)); // ok
+
*__builtin_counted_by_ref(ptr->array) = size; // ok
*__builtin_counted_by_ref(&ptr->array[idx]) = size; // ok
@@ -26,28 +28,44 @@ void test1(struct fam_struct *ptr, int size, int idx) {
void test2(struct fam_struct *ptr, int idx) {
__builtin_counted_by_ref(); // expected-error {{too few arguments to function call, expected 1, have 0}}
__builtin_counted_by_ref(ptr->array, ptr->x, ptr->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
+}
+
+void test3(struct fam_struct *ptr, int idx) {
__builtin_counted_by_ref(ptr->x); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
__builtin_counted_by_ref(&ptr->x); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
__builtin_counted_by_ref(global_array); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
__builtin_counted_by_ref(global_int); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
__builtin_counted_by_ref(&global_int); // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+}
+
+void test4(struct fam_struct *ptr, int idx) {
__builtin_counted_by_ref(&ptr->array[idx++]); // expected-warning {{'__builtin_counted_by_ref' argument has side-effects that will be discarded}}
}
void foo(char *);
-void *test3(struct fam_struct *ptr, int size, int idx) {
+void *test5(struct fam_struct *ptr, int size, int idx) {
char *ref = __builtin_counted_by_ref(ptr->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
ref = __builtin_counted_by_ref(ptr->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
ref = (char *)(int *)(42 + &*__builtin_counted_by_ref(ptr->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
foo(__builtin_counted_by_ref(ptr->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
- *(__builtin_counted_by_ref(ptr->array) + 4) = 37; // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in a binary expression}}
- __builtin_counted_by_ref(ptr->array)[3] = 37; // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in an array subscript expression}}
+ foo(ref = __builtin_counted_by_ref(ptr->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
+
+ if ((ref = __builtin_counted_by_ref(ptr->array))) // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
+ ;
+
+ for (char *p = __builtin_counted_by_ref(ptr->array); p && *p; ++p) // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
+ ;
return __builtin_counted_by_ref(ptr->array); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
}
+void test6(struct fam_struct *ptr, int size, int idx) {
+ *(__builtin_counted_by_ref(ptr->array) + 4) = 37; // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in a binary expression}}
+ __builtin_counted_by_ref(ptr->array)[3] = 37; // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in an array subscript expression}}
+}
+
struct non_fam_struct {
char x;
long *pointer;
@@ -55,7 +73,7 @@ struct non_fam_struct {
short count;
};
-void *test4(struct non_fam_struct *ptr, int size) {
+void *test7(struct non_fam_struct *ptr, int size) {
*__builtin_counted_by_ref(ptr->array) = size // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
*__builtin_counted_by_ref(&ptr->array[0]) = size; // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
*__builtin_counted_by_ref(ptr->pointer) = size; // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
@@ -92,7 +110,7 @@ struct unsigned_long_count {
int array[] __attribute__((counted_by(count)));
} *ulp;
-void test5(void) {
+void test8(void) {
_Static_assert(_Generic(__builtin_counted_by_ref(cp->array), char * : 1, default : 0) == 1, "wrong return type");
_Static_assert(_Generic(__builtin_counted_by_ref(sp->array), short * : 1, default : 0) == 1, "wrong return type");
_Static_assert(_Generic(__builtin_counted_by_ref(ip->array), int * : 1, default : 0) == 1, "wrong return type");
>From 90d6ea82c7a01d1ce5e67f07762838efc826f8db Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 1 Nov 2024 15:43:38 -0700
Subject: [PATCH 59/59] Add test rejecting using of 'counted_by' in C++.
---
clang/test/Sema/builtin-counted-by-ref.cpp | 8 ++++++++
1 file changed, 8 insertions(+)
create mode 100644 clang/test/Sema/builtin-counted-by-ref.cpp
diff --git a/clang/test/Sema/builtin-counted-by-ref.cpp b/clang/test/Sema/builtin-counted-by-ref.cpp
new file mode 100644
index 00000000000000..b9ec9c908dcaa6
--- /dev/null
+++ b/clang/test/Sema/builtin-counted-by-ref.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify %s
+
+struct fam_struct {
+ int x;
+ char count;
+ int array[] __attribute__((counted_by(count))); // expected-warning {{'counted_by' attribute ignored}}
+};
+
More information about the cfe-commits
mailing list