@@ -851,78 +851,94 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
851851 // max(sizeof(struct s),
852852 // offsetof(struct s, array) + p->count * sizeof(*p->array))
853853 //
854+ ASTContext &Ctx = getContext();
854855 const Expr *Base = E->IgnoreParenImpCasts();
855856 const Expr *Idx = nullptr;
856857
857858 if (const auto *UO = dyn_cast<UnaryOperator>(Base);
858859 UO && UO->getOpcode() == UO_AddrOf) {
859- if (const auto *ASE =
860- dyn_cast<ArraySubscriptExpr>(UO->getSubExpr()->IgnoreParens() )) {
861- Base = ASE->getBase();
860+ Expr *SubExpr = UO->getSubExpr()->IgnoreParenImpCasts();
861+ if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(SubExpr )) {
862+ Base = ASE->getBase()->IgnoreParenImpCasts() ;
862863 Idx = ASE->getIdx()->IgnoreParenImpCasts();
863864
864- if (const auto *IL = dyn_cast<IntegerLiteral>(Idx);
865- IL && !IL->getValue().getSExtValue())
866- Idx = nullptr;
865+ if (const auto *IL = dyn_cast<IntegerLiteral>(Idx)) {
866+ int64_t Val = IL->getValue().getSExtValue();
867+ if (Val < 0)
868+ // __bdos returns 0 for negative indexes into an array in a struct.
869+ return getDefaultBuiltinObjectSizeResult(Type, ResType);
870+
871+ if (Val == 0)
872+ // The index is 0, so we don't need to take it into account.
873+ Idx = nullptr;
874+ }
875+ } else {
876+ // Potential pointer to another element in the struct.
877+ Base = SubExpr;
867878 }
868879 }
869880
881+ // Get the flexible array member Decl.
882+ const ValueDecl *FAMDecl = nullptr;
883+ if (const auto *ME = dyn_cast<MemberExpr>(Base)) {
884+ // Check if \p Base is referencing the FAM itself.
885+ if (const ValueDecl *MD = ME->getMemberDecl()) {
886+ const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
887+ getLangOpts().getStrictFlexArraysLevel();
888+ if (!Decl::isFlexibleArrayMemberLike(
889+ Ctx, MD, MD->getType(), StrictFlexArraysLevel,
890+ /*IgnoreTemplateOrMacroSubstitution=*/true))
891+ return nullptr;
892+
893+ FAMDecl = MD;
894+ }
895+ } else if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
896+ // Check if we're pointing to the whole struct.
897+ QualType Ty = DRE->getDecl()->getType();
898+ if (Ty->isPointerType())
899+ Ty = Ty->getPointeeType();
900+
901+ if (const auto *RD = Ty->getAsRecordDecl())
902+ // Don't use the outer lexical record because the FAM might be in a
903+ // different RecordDecl.
904+ FAMDecl = FindFlexibleArrayMemberField(Ctx, RD);
905+ }
906+
907+ if (!FAMDecl || !FAMDecl->hasAttr<CountedByAttr>())
908+ // No flexible array member found or it doesn't have the "counted_by"
909+ // attribute.
910+ return nullptr;
911+
870912 const ValueDecl *CountedByFD = FindCountedByField(Base);
871913 if (!CountedByFD)
872914 // Can't find the field referenced by the "counted_by" attribute.
873915 return nullptr;
874916
875917 // Build a load of the counted_by field.
876918 bool IsSigned = CountedByFD->getType()->isSignedIntegerType();
877- const RecordDecl *OuterRD =
878- CountedByFD->getDeclContext()->getOuterLexicalRecordContext();
879- ASTContext &Ctx = getContext();
880-
881- // Load the counted_by field.
882919 const Expr *CountedByExpr = BuildCountedByFieldExpr(Base, CountedByFD);
883920 Value *CountedByInst = EmitAnyExprToTemp(CountedByExpr).getScalarVal();
884921 llvm::Type *CountedByTy = CountedByInst->getType();
885922
923+ // Build a load of the index and subtract it from the count.
924+ Value *IdxInst = nullptr;
886925 if (Idx) {
887- // There's an index into the array. Remove it from the count.
888926 bool IdxSigned = Idx->getType()->isSignedIntegerType();
889- Value * IdxInst = EmitAnyExprToTemp(Idx).getScalarVal();
927+ IdxInst = EmitAnyExprToTemp(Idx).getScalarVal();
890928 IdxInst = IdxSigned ? Builder.CreateSExtOrTrunc(IdxInst, CountedByTy)
891929 : Builder.CreateZExtOrTrunc(IdxInst, CountedByTy);
892930
893- // If the index is negative, don't subtract it from the counted_by
894- // value. The pointer is pointing to something before the FAM.
895- IdxInst = Builder.CreateNeg(IdxInst, "", !IdxSigned, IdxSigned);
931+ // We go ahead with the calculation here. If the index turns out to be
932+ // negative, we'll catch it at the end.
896933 CountedByInst =
897- Builder.CreateAdd (CountedByInst, IdxInst, "", !IsSigned, IsSigned);
934+ Builder.CreateSub (CountedByInst, IdxInst, "", !IsSigned, IsSigned);
898935 }
899936
900- // Get the size of the flexible array member's base type.
901- const ValueDecl *FAMDecl = nullptr;
902- if (const auto *ME = dyn_cast<MemberExpr>(Base)) {
903- const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
904- getLangOpts().getStrictFlexArraysLevel();
905- if (const ValueDecl *MD = ME->getMemberDecl()) {
906- if (!Decl::isFlexibleArrayMemberLike(
907- Ctx, MD, MD->getType(), StrictFlexArraysLevel,
908- /*IgnoreTemplateOrMacroSubstitution=*/true))
909- return nullptr;
910- // Base is referencing the FAM itself.
911- FAMDecl = MD;
912- }
913- }
914-
915- if (!FAMDecl)
916- FAMDecl = FindFlexibleArrayMemberField(Ctx, OuterRD);
917-
918- assert(FAMDecl && "Can't find the flexible array member field");
919-
937+ // Calculate how large the flexible array member is in bytes.
920938 const ArrayType *ArrayTy = Ctx.getAsArrayType(FAMDecl->getType());
921939 CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
922940 llvm::Constant *ElemSize =
923941 llvm::ConstantInt::get(CountedByTy, Size.getQuantity(), IsSigned);
924-
925- // Calculate how large the flexible array member is in bytes.
926942 Value *FAMSize =
927943 Builder.CreateMul(CountedByInst, ElemSize, "", !IsSigned, IsSigned);
928944 FAMSize = IsSigned ? Builder.CreateSExtOrTrunc(FAMSize, ResType)
@@ -931,47 +947,38 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
931947
932948 if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
933949 // The whole struct is specificed in the __bdos.
950+ const RecordDecl *OuterRD =
951+ CountedByFD->getDeclContext()->getOuterLexicalRecordContext();
934952 const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD);
935953
936954 // Get the offset of the FAM.
937955 CharUnits Offset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAMDecl));
938956 llvm::Constant *FAMOffset =
939957 ConstantInt::get(ResType, Offset.getQuantity(), IsSigned);
940-
941- // max(sizeof(struct s),
942- // offsetof(struct s, array) + p->count * sizeof(*p->array))
943958 Value *OffsetAndFAMSize =
944959 Builder.CreateAdd(FAMOffset, Res, "", !IsSigned, IsSigned);
945960
946961 // Get the full size of the struct.
947962 llvm::Constant *SizeofStruct =
948963 ConstantInt::get(ResType, Layout.getSize().getQuantity(), IsSigned);
949964
965+ // max(sizeof(struct s),
966+ // offsetof(struct s, array) + p->count * sizeof(*p->array))
950967 Res = IsSigned
951968 ? Builder.CreateBinaryIntrinsic(llvm::Intrinsic::smax,
952969 OffsetAndFAMSize, SizeofStruct)
953970 : Builder.CreateBinaryIntrinsic(llvm::Intrinsic::umax,
954971 OffsetAndFAMSize, SizeofStruct);
955- } else if (const auto *ME = dyn_cast<MemberExpr>(Base)) {
956- // Pointing to a place before the FAM. Add the difference to the FAM's
957- // size.
958- if (const ValueDecl *MD = ME->getMemberDecl(); MD != FAMDecl) {
959- CharUnits Offset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(MD));
960- CharUnits FAMOffset =
961- Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAMDecl));
962-
963- Res = Builder.CreateAdd(
964- Res, ConstantInt::get(ResType, FAMOffset.getQuantity() -
965- Offset.getQuantity()));
966- }
967972 }
968973
969- // A negative 'FAMSize' means that the index was greater than the count,
970- // or an improperly set count field. Return -1 (for types 0 and 1) or 0
971- // (for types 2 and 3).
972- return Builder.CreateSelect(Builder.CreateIsNeg(FAMSize),
973- getDefaultBuiltinObjectSizeResult(Type, ResType),
974- Res);
974+ // A negative \p IdxInst or \p CountedByInst means that the index lands
975+ // outside of the flexible array member. If that's the case, we want to
976+ // return 0.
977+ Value *Cmp = Builder.CreateIsNotNeg(CountedByInst);
978+ if (IdxInst)
979+ Cmp = Builder.CreateAnd(Builder.CreateIsNotNeg(IdxInst), Cmp);
980+
981+ return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, IsSigned));
975982}
976983
977984/// Returns a Value corresponding to the size of the given expression.
@@ -1006,19 +1013,19 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type,
10061013 }
10071014 }
10081015
1009- // LLVM can't handle Type=3 appropriately, and __builtin_object_size shouldn't
1010- // evaluate E for side-effects. In either case, we shouldn't lower to
1011- // @llvm.objectsize.
1012- if (Type == 3 || (!EmittedE && E->HasSideEffects(getContext())))
1013- return getDefaultBuiltinObjectSizeResult(Type, ResType);
1014-
10151016 if (IsDynamic) {
10161017 // Emit special code for a flexible array member with the "counted_by"
10171018 // attribute.
10181019 if (Value *V = emitFlexibleArrayMemberSize(E, Type, ResType))
10191020 return V;
10201021 }
10211022
1023+ // LLVM can't handle Type=3 appropriately, and __builtin_object_size shouldn't
1024+ // evaluate E for side-effects. In either case, we shouldn't lower to
1025+ // @llvm.objectsize.
1026+ if (Type == 3 || (!EmittedE && E->HasSideEffects(getContext())))
1027+ return getDefaultBuiltinObjectSizeResult(Type, ResType);
1028+
10221029 Value *Ptr = EmittedE ? EmittedE : EmitScalarExpr(E);
10231030 assert(Ptr->getType()->isPointerTy() &&
10241031 "Non-pointer passed to __builtin_object_size?");
0 commit comments