Skip to content

Commit 108ab46

Browse files
bwendlingefriedma-quic
authored andcommitted
[Clang] Disable use of the counted_by attribute for whole struct pointers (llvm#112636)
The whole struct is specificed in the __bdos. The calculation of the whole size of the structure can be done in two ways: 1) sizeof(struct S) + count * sizeof(typeof(fam)) 2) offsetof(struct S, fam) + count * sizeof(typeof(fam)) The first will add any remaining whitespace that might exist after allocation while the second method is more precise, but not quite expected from programmers. See [1] for a discussion of the topic. GCC isn't (currently) able to calculate __bdos on a pointer to the whole structure. Therefore, because of the above issue, we'll choose to match what GCC does for consistency's sake. [1] https://lore.kernel.org/lkml/ZvV6X5FPBBW7CO1f@archlinux/ Co-authored-by: Eli Friedman <[email protected]>
1 parent 062adaf commit 108ab46

File tree

2 files changed

+107
-191
lines changed

2 files changed

+107
-191
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

+20-25
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,24 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
10011001
// Can't find the field referenced by the "counted_by" attribute.
10021002
return nullptr;
10031003

1004+
if (isa<DeclRefExpr>(Base))
1005+
// The whole struct is specificed in the __bdos. The calculation of the
1006+
// whole size of the structure can be done in two ways:
1007+
//
1008+
// 1) sizeof(struct S) + count * sizeof(typeof(fam))
1009+
// 2) offsetof(struct S, fam) + count * sizeof(typeof(fam))
1010+
//
1011+
// The first will add additional padding after the end of the array,
1012+
// allocation while the second method is more precise, but not quite
1013+
// expected from programmers. See
1014+
// https://lore.kernel.org/lkml/ZvV6X5FPBBW7CO1f@archlinux/ for a
1015+
// discussion of the topic.
1016+
//
1017+
// GCC isn't (currently) able to calculate __bdos on a pointer to the whole
1018+
// structure. Therefore, because of the above issue, we'll choose to match
1019+
// what GCC does for consistency's sake.
1020+
return nullptr;
1021+
10041022
// Build a load of the counted_by field.
10051023
bool IsSigned = CountedByFD->getType()->isSignedIntegerType();
10061024
Value *CountedByInst = EmitCountedByFieldExpr(Base, FAMDecl, CountedByFD);
@@ -1031,32 +1049,9 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
10311049
CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
10321050
llvm::Constant *ElemSize =
10331051
llvm::ConstantInt::get(ResType, Size.getQuantity(), IsSigned);
1034-
Value *FAMSize =
1052+
Value *Res =
10351053
Builder.CreateMul(CountedByInst, ElemSize, "", !IsSigned, IsSigned);
1036-
FAMSize = Builder.CreateIntCast(FAMSize, ResType, IsSigned);
1037-
Value *Res = FAMSize;
1038-
1039-
if (isa<DeclRefExpr>(Base)) {
1040-
// The whole struct is specificed in the __bdos.
1041-
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD);
1042-
1043-
// Get the offset of the FAM.
1044-
llvm::Constant *FAMOffset = ConstantInt::get(ResType, Offset, IsSigned);
1045-
Value *OffsetAndFAMSize =
1046-
Builder.CreateAdd(FAMOffset, Res, "", !IsSigned, IsSigned);
1047-
1048-
// Get the full size of the struct.
1049-
llvm::Constant *SizeofStruct =
1050-
ConstantInt::get(ResType, Layout.getSize().getQuantity(), IsSigned);
1051-
1052-
// max(sizeof(struct s),
1053-
// offsetof(struct s, array) + p->count * sizeof(*p->array))
1054-
Res = IsSigned
1055-
? Builder.CreateBinaryIntrinsic(llvm::Intrinsic::smax,
1056-
OffsetAndFAMSize, SizeofStruct)
1057-
: Builder.CreateBinaryIntrinsic(llvm::Intrinsic::umax,
1058-
OffsetAndFAMSize, SizeofStruct);
1059-
}
1054+
Res = Builder.CreateIntCast(Res, ResType, IsSigned);
10601055

10611056
// A negative \p IdxInst or \p CountedByInst means that the index lands
10621057
// outside of the flexible array member. If that's the case, we want to

0 commit comments

Comments
 (0)