Skip to content

Commit b656baa

Browse files
committed
[Clang][counted_by] Support casting the array to a different type
C allows the programmer to cast the base array to a different type before applying the index. We need to handle that situation. struct annotated { unsigned long flags; int count; int array[] __counted_by(count); }; __bdos(&((unsigned short *) ((char *)p->array))[42], 1); Use the index's type when calculating the size to remove from the flexible array member's total size.
1 parent 1dbc8ef commit b656baa

File tree

2 files changed

+363
-153
lines changed

2 files changed

+363
-153
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,7 @@ class StructFieldAccess
910910

911911
public:
912912
const ArraySubscriptExpr *ASE = nullptr;
913+
QualType ArrayElementTy;
913914

914915
const Expr *VisitMemberExpr(const MemberExpr *E) {
915916
if (AddrOfSeen && E->getType()->isArrayType())
@@ -925,6 +926,7 @@ class StructFieldAccess
925926

926927
AddrOfSeen = false; // '&ptr->array[idx]' is okay.
927928
ASE = E;
929+
ArrayElementTy = E->getBase()->getType();
928930
return Visit(E->getBase());
929931
}
930932
const Expr *VisitCastExpr(const CastExpr *E) {
@@ -1101,23 +1103,23 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
11011103
// count = ptr->count;
11021104
//
11031105
// flexible_array_member_base_size = sizeof (*ptr->array);
1104-
// flexible_array_member_size =
1105-
// count * flexible_array_member_base_size;
1106+
// flexible_array_member_size = count * flexible_array_member_base_size;
11061107
//
11071108
// if (flexible_array_member_size < 0)
11081109
// return 0;
11091110
// return flexible_array_member_size;
11101111
//
1111-
// 2) '&ptr->array[idx]':
1112+
// 2) '&((cast) ptr->array)[idx]':
11121113
//
11131114
// count = ptr->count;
11141115
// index = idx;
11151116
//
1117+
// casted_flexible_array_member_base_size = sizeof (*((cast) ptr->array));
1118+
//
11161119
// flexible_array_member_base_size = sizeof (*ptr->array);
1117-
// flexible_array_member_size =
1118-
// count * flexible_array_member_base_size;
1120+
// flexible_array_member_size = count * flexible_array_member_base_size;
11191121
//
1120-
// index_size = index * flexible_array_member_base_size;
1122+
// index_size = index * casted_flexible_array_member_base_size;
11211123
//
11221124
// if (flexible_array_member_size < 0 || index < 0)
11231125
// return 0;
@@ -1129,8 +1131,7 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
11291131
// sizeof_struct = sizeof (struct s);
11301132
//
11311133
// flexible_array_member_base_size = sizeof (*ptr->array);
1132-
// flexible_array_member_size =
1133-
// count * flexible_array_member_base_size;
1134+
// flexible_array_member_size = count * flexible_array_member_base_size;
11341135
//
11351136
// field_offset = offsetof (struct s, field);
11361137
// offset_diff = sizeof_struct - field_offset;
@@ -1139,19 +1140,19 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
11391140
// return 0;
11401141
// return offset_diff + flexible_array_member_size;
11411142
//
1142-
// 4) '&ptr->field_array[idx]':
1143+
// 4) '&((cast) ptr->field_array)[idx]':
11431144
//
11441145
// count = ptr->count;
11451146
// index = idx;
11461147
// sizeof_struct = sizeof (struct s);
11471148
//
11481149
// flexible_array_member_base_size = sizeof (*ptr->array);
1149-
// flexible_array_member_size =
1150-
// count * flexible_array_member_base_size;
1150+
// flexible_array_member_size = count * flexible_array_member_base_size;
1151+
//
1152+
// casted_field_base_size = sizeof (*((cast) ptr->field_array));
11511153
//
1152-
// field_base_size = sizeof (*ptr->field_array);
11531154
// field_offset = offsetof (struct s, field)
1154-
// field_offset += index * field_base_size;
1155+
// field_offset += index * casted_field_base_size;
11551156
//
11561157
// offset_diff = sizeof_struct - field_offset;
11571158
//
@@ -1162,14 +1163,11 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
11621163
QualType CountTy = CountFD->getType();
11631164
bool IsSigned = CountTy->isSignedIntegerType();
11641165

1165-
QualType FlexibleArrayMemberTy = FlexibleArrayMemberFD->getType();
1166-
QualType FieldTy = FD->getType();
1167-
11681166
// Explicit cast because otherwise the CharWidth will promote an i32's into
11691167
// u64's leading to overflows..
11701168
int64_t CharWidth = static_cast<int64_t>(CGM.getContext().getCharWidth());
11711169

1172-
// size_t field_offset = offsetof (struct s, field);
1170+
// field_offset = offsetof (struct s, field);
11731171
Value *FieldOffset = nullptr;
11741172
if (FlexibleArrayMemberFD != FD) {
11751173
std::optional<int64_t> Offset = GetFieldOffset(Ctx, RD, FD);
@@ -1179,37 +1177,49 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
11791177
llvm::ConstantInt::get(ResType, *Offset / CharWidth, IsSigned);
11801178
}
11811179

1182-
// size_t count = (size_t) ptr->count;
1180+
// count = ptr->count;
11831181
Value *Count = EmitLoadOfCountedByField(ME, FlexibleArrayMemberFD, CountFD);
11841182
if (!Count)
11851183
return nullptr;
11861184
Count = Builder.CreateIntCast(Count, ResType, IsSigned, "count");
11871185

1188-
// size_t index = (size_t) ptr->index;
1186+
// index = ptr->index;
11891187
Value *Index = nullptr;
11901188
if (Idx) {
11911189
bool IdxSigned = Idx->getType()->isSignedIntegerType();
11921190
Index = EmitScalarExpr(Idx);
11931191
Index = Builder.CreateIntCast(Index, ResType, IdxSigned, "index");
11941192
}
11951193

1196-
// size_t flexible_array_member_base_size = sizeof (*ptr->array);
1197-
const ArrayType *ArrayTy = Ctx.getAsArrayType(FlexibleArrayMemberTy);
1198-
CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
1194+
// flexible_array_member_base_size = sizeof (*ptr->array);
1195+
QualType FlexibleArrayMemberTy = FlexibleArrayMemberFD->getType();
1196+
const ArrayType *FAMTy = Ctx.getAsArrayType(FlexibleArrayMemberTy);
1197+
CharUnits BaseSize = Ctx.getTypeSizeInChars(FAMTy->getElementType());
11991198
auto *FlexibleArrayMemberBaseSize =
12001199
llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
12011200

1202-
// size_t flexible_array_member_size =
1203-
// count * flexible_array_member_base_size;
1201+
// flexible_array_member_size = count * flexible_array_member_base_size;
12041202
Value *FlexibleArrayMemberSize =
12051203
Builder.CreateMul(Count, FlexibleArrayMemberBaseSize,
12061204
"flexible_array_member_size", !IsSigned, IsSigned);
12071205

1206+
QualType CastedArrayElementTy = Visitor.ArrayElementTy;
1207+
llvm::ConstantInt *CastedArrayElementSize = nullptr;
1208+
if (!CastedArrayElementTy.isNull() && CastedArrayElementTy->isPointerType()) {
1209+
const PointerType *FAMTy = cast<clang::PointerType>(CastedArrayElementTy);
1210+
CharUnits BaseSize = Ctx.getTypeSizeInChars(FAMTy->getPointeeType());
1211+
CastedArrayElementSize =
1212+
llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
1213+
}
1214+
12081215
Value *Res = nullptr;
12091216
if (FlexibleArrayMemberFD == FD) {
1210-
if (Idx) { // Option (2) '&ptr->array[idx]'
1211-
// size_t index_size = index * flexible_array_member_base_size;
1212-
Value *IndexSize = Builder.CreateMul(FlexibleArrayMemberBaseSize, Index,
1217+
if (Idx) { // Option (2) '&((cast) ptr->array)[idx]'
1218+
if (!CastedArrayElementSize)
1219+
CastedArrayElementSize = FlexibleArrayMemberBaseSize;
1220+
1221+
// index_size = index * flexible_array_member_base_size;
1222+
Value *IndexSize = Builder.CreateMul(CastedArrayElementSize, Index,
12131223
"index_size", !IsSigned, IsSigned);
12141224

12151225
// return flexible_array_member_size - index_size;
@@ -1220,28 +1230,30 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
12201230
Res = FlexibleArrayMemberSize;
12211231
}
12221232
} else {
1223-
// size_t sizeof_struct = sizeof (struct s);
1233+
// sizeof_struct = sizeof (struct s);
12241234
llvm::StructType *StructTy = getTypes().getCGRecordLayout(RD).getLLVMType();
12251235
const llvm::DataLayout &Layout = CGM.getDataLayout();
12261236
TypeSize Size = Layout.getTypeSizeInBits(StructTy);
12271237
Value *SizeofStruct =
12281238
llvm::ConstantInt::get(ResType, Size.getKnownMinValue() / CharWidth);
12291239

1230-
if (Idx) { // Option (4) '&ptr->field_array[idx]'
1231-
// size_t field_base_size = sizeof (*ptr->field_array);
1232-
const ArrayType *ArrayTy = Ctx.getAsArrayType(FieldTy);
1233-
CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
1234-
auto *FieldBaseSize =
1235-
llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
1240+
if (Idx) { // Option (4) '&((cast) ptr->field_array)[idx]'
1241+
// casted_field_base_size = sizeof (*((cast) ptr->field_array));
1242+
if (!CastedArrayElementSize) {
1243+
const ArrayType *ArrayTy = Ctx.getAsArrayType(FD->getType());
1244+
CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
1245+
CastedArrayElementSize =
1246+
llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
1247+
}
12361248

1237-
// field_offset += index * field_base_size;
1238-
Value *Mul = Builder.CreateMul(Index, FieldBaseSize, "field_offset",
1249+
// field_offset += index * casted_field_base_size;
1250+
Value *Mul = Builder.CreateMul(Index, CastedArrayElementSize, "field_offset",
12391251
!IsSigned, IsSigned);
12401252
FieldOffset = Builder.CreateAdd(FieldOffset, Mul);
12411253
}
12421254
// Option (3) '&ptr->field', and Option (4) continuation.
12431255

1244-
// size_t offset_diff = flexible_array_member_offset - field_offset;
1256+
// offset_diff = flexible_array_member_offset - field_offset;
12451257
Value *OffsetDiff = Builder.CreateSub(SizeofStruct, FieldOffset,
12461258
"offset_diff", !IsSigned, IsSigned);
12471259

0 commit comments

Comments
 (0)