Skip to content

Commit 4439836

Browse files
committed
Take casted arrays into account when calculating the size.
1 parent 84e9ecc commit 4439836

File tree

3 files changed

+180
-82
lines changed

3 files changed

+180
-82
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

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

911911
public:
912912
const Expr *ArrayIndex = 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
ArrayIndex = E->getIdx();
929+
ArrayElementTy = E->getBase()->getType();
928930
return Visit(E->getBase());
929931
}
930932
const Expr *VisitCastExpr(const CastExpr *E) {
@@ -1059,15 +1061,17 @@ llvm::Value *CodeGenFunction::emitCountedBySize(const Expr *E,
10591061
}
10601062
}
10611063

1064+
// __counted_by on either a flexible array member or a pointer into a struct
1065+
// with a flexible array member.
10621066
if (const auto *ME = dyn_cast<MemberExpr>(E))
1063-
// This is either a flexible array member or a pointer into a struct with a
1064-
// flexible array member.
1065-
return emitCountedByMemberSize(ME, Idx, EmittedE, Type, ResType);
1067+
return emitCountedByMemberSize(ME, Idx, EmittedE, Visitor.ArrayElementTy,
1068+
Type, ResType);
10661069

1070+
// __counted_by on a pointer in a struct.
10671071
if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E);
10681072
ICE && ICE->getCastKind() == CK_LValueToRValue)
1069-
// This may be a pointer.
1070-
return emitCountedByPointerSize(ICE, Idx, EmittedE, Type, ResType);
1073+
return emitCountedByPointerSize(ICE, Idx, EmittedE, Visitor.ArrayElementTy,
1074+
Type, ResType);
10711075

10721076
return nullptr;
10731077
}
@@ -1111,7 +1115,7 @@ GetCountFieldAndIndex(CodeGenFunction &CGF, const MemberExpr *ME,
11111115

11121116
llvm::Value *CodeGenFunction::emitCountedByPointerSize(
11131117
const ImplicitCastExpr *E, const Expr *Idx, llvm::Value *EmittedE,
1114-
unsigned Type, llvm::IntegerType *ResType) {
1118+
QualType CastedArrayElementTy, unsigned Type, llvm::IntegerType *ResType) {
11151119
assert(E->getCastKind() == CK_LValueToRValue &&
11161120
"must be an LValue to RValue cast");
11171121

@@ -1144,52 +1148,67 @@ llvm::Value *CodeGenFunction::emitCountedByPointerSize(
11441148
//
11451149
// count = ptr->count;
11461150
//
1147-
// array_base_size = sizeof (*ptr->array);
1148-
// array_size = count * array_base_size;
1151+
// array_element_size = sizeof (*ptr->array);
1152+
// array_size = count * array_element_size;
11491153
//
11501154
// result = array_size;
11511155
//
11521156
// cmp = (result >= 0)
11531157
// return cmp ? result : 0;
11541158
//
1155-
// 2) '&ptr->array[idx]':
1159+
// 2) '&((cast) ptr->array)[idx]':
11561160
//
11571161
// count = ptr->count;
11581162
// index = idx;
11591163
//
1160-
// array_base_size = sizeof (*ptr->array_base_size);
1161-
// array_size = count * array_base_size;
1164+
// array_element_size = sizeof (*ptr->array);
1165+
// array_size = count * array_element_size;
11621166
//
1163-
// index_size = index * array_base_size;
1167+
// casted_array_element_size = sizeof (*((cast) ptr->array));
11641168
//
1169+
// index_size = index * casted_array_element_size;
11651170
// result = array_size - index_size;
11661171
//
11671172
// cmp = (result >= 0)
11681173
// if (index)
11691174
// cmp = (cmp && index > 0)
11701175
// return cmp ? result : 0;
11711176

1172-
bool IsSigned = CountFD->getType()->isSignedIntegerType();
1177+
auto GetElementBaseSize = [&](QualType ElementTy) {
1178+
CharUnits ElementSize =
1179+
getContext().getTypeSizeInChars(ElementTy->getPointeeType());
1180+
1181+
if (ElementSize.isZero()) {
1182+
// This might be a __sized_by on a 'void *', which counts bytes, not
1183+
// elements.
1184+
auto *CAT = ElementTy->getAs<CountAttributedType>();
1185+
if (!CAT || (CAT->getKind() != CountAttributedType::SizedBy &&
1186+
CAT->getKind() != CountAttributedType::SizedByOrNull))
1187+
// Okay, not sure what it is now.
1188+
// FIXME: Should this be an assert?
1189+
return std::optional<CharUnits>();
1190+
1191+
ElementSize = CharUnits::One();
1192+
}
11731193

1174-
// array_base_size = sizeof (*ptr->array);
1175-
ASTContext &Ctx = getContext();
1176-
QualType ArrayBaseTy = ArrayBaseFD->getType()->getPointeeType();
1177-
CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayBaseTy);
1178-
if (BaseSize.isZero()) {
1179-
// This might be a __sized_by on a 'void *', which counts bytes, not
1180-
// elements.
1181-
auto *CAT = ArrayBaseFD->getType()->getAs<CountAttributedType>();
1182-
if (CAT->getKind() != CountAttributedType::SizedBy &&
1183-
CAT->getKind() != CountAttributedType::SizedByOrNull)
1184-
// Okay, not sure what it is now.
1185-
// FIXME: Should this be an assert?
1186-
return nullptr;
1194+
return std::optional<CharUnits>(ElementSize);
1195+
};
11871196

1188-
BaseSize = CharUnits::One();
1197+
// Get the sizes of the original array element and the casted array element,
1198+
// if different.
1199+
std::optional<CharUnits> ArrayElementBaseSize =
1200+
GetElementBaseSize(ArrayBaseFD->getType());
1201+
if (!ArrayElementBaseSize)
1202+
return nullptr;
1203+
1204+
std::optional<CharUnits> CastedArrayElementBaseSize = ArrayElementBaseSize;
1205+
if (!CastedArrayElementTy.isNull() && CastedArrayElementTy->isPointerType()) {
1206+
CastedArrayElementBaseSize = GetElementBaseSize(CastedArrayElementTy);
1207+
if (!CastedArrayElementBaseSize)
1208+
return nullptr;
11891209
}
11901210

1191-
auto *ArrayBaseSize =
1192-
llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
1211+
bool IsSigned = CountFD->getType()->isSignedIntegerType();
11931212

11941213
// count = ptr->count;
11951214
// index = ptr->index;
@@ -1199,30 +1218,38 @@ llvm::Value *CodeGenFunction::emitCountedByPointerSize(
11991218
if (!Count)
12001219
return nullptr;
12011220

1202-
// array_size = count * array_base_size;
1203-
Value *ArraySize = Builder.CreateMul(Count, ArrayBaseSize, "array_size",
1221+
// array_element_size = sizeof (*ptr->array)
1222+
auto *ArrayElementSize = llvm::ConstantInt::get(
1223+
ResType, ArrayElementBaseSize->getQuantity(), IsSigned);
1224+
1225+
// casted_array_element_size = sizeof (*((cast) ptr->array));
1226+
auto *CastedArrayElementSize = llvm::ConstantInt::get(
1227+
ResType, CastedArrayElementBaseSize->getQuantity(), IsSigned);
1228+
1229+
// array_size = count * array_element_size;
1230+
Value *ArraySize = Builder.CreateMul(Count, ArrayElementSize, "array_size",
12041231
!IsSigned, IsSigned);
12051232

12061233
// Option (1) 'ptr->array'
1207-
// result = array_size
1208-
Value *Res = ArraySize;
1234+
// result = array_size
1235+
Value *Result = ArraySize;
12091236

1210-
if (Idx) { // Option (2) '&ptr->array[idx]'
1211-
// index_size = index * array_base_size;
1212-
Value *IndexSize = Builder.CreateMul(ArrayBaseSize, Index, "index_size",
1213-
!IsSigned, IsSigned);
1237+
if (Idx) { // Option (2) '&((cast) ptr->array)[idx]'
1238+
// index_size = index * casted_array_element_size;
1239+
Value *IndexSize = Builder.CreateMul(Index, CastedArrayElementSize,
1240+
"index_size", !IsSigned, IsSigned);
12141241

12151242
// result = result - index_size;
1216-
Res = Builder.CreateSub(Res, IndexSize, "result", !IsSigned, IsSigned);
1243+
Result =
1244+
Builder.CreateSub(Result, IndexSize, "result", !IsSigned, IsSigned);
12171245
}
12181246

1219-
return EmitPositiveResultOrZero(*this, Res, Index, ResType, IsSigned);
1247+
return EmitPositiveResultOrZero(*this, Result, Index, ResType, IsSigned);
12201248
}
12211249

1222-
llvm::Value *
1223-
CodeGenFunction::emitCountedByMemberSize(const MemberExpr *ME, const Expr *Idx,
1224-
llvm::Value *EmittedE, unsigned Type,
1225-
llvm::IntegerType *ResType) {
1250+
llvm::Value *CodeGenFunction::emitCountedByMemberSize(
1251+
const MemberExpr *ME, const Expr *Idx, llvm::Value *EmittedE,
1252+
QualType CastedArrayElementTy, unsigned Type, llvm::IntegerType *ResType) {
12261253
const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
12271254
if (!FD)
12281255
return nullptr;
@@ -1264,25 +1291,27 @@ CodeGenFunction::emitCountedByMemberSize(const MemberExpr *ME, const Expr *Idx,
12641291
//
12651292
// count = ptr->count;
12661293
//
1267-
// flexible_array_member_base_size = sizeof (*ptr->array);
1294+
// flexible_array_member_element_size = sizeof (*ptr->array);
12681295
// flexible_array_member_size =
1269-
// count * flexible_array_member_base_size;
1296+
// count * flexible_array_member_element_size;
12701297
//
12711298
// result = flexible_array_member_size;
12721299
//
12731300
// cmp = (result >= 0)
12741301
// return cmp ? result : 0;
12751302
//
1276-
// 2) '&ptr->array[idx]':
1303+
// 2) '&((cast) ptr->array)[idx]':
12771304
//
12781305
// count = ptr->count;
12791306
// index = idx;
12801307
//
1281-
// flexible_array_member_base_size = sizeof (*ptr->array);
1308+
// flexible_array_member_element_size = sizeof (*ptr->array);
12821309
// flexible_array_member_size =
1283-
// count * flexible_array_member_base_size;
1310+
// count * flexible_array_member_element_size;
12841311
//
1285-
// index_size = index * flexible_array_member_base_size;
1312+
// casted_flexible_array_member_element_size =
1313+
// sizeof (*((cast) ptr->array));
1314+
// index_size = index * casted_flexible_array_member_element_size;
12861315
//
12871316
// result = flexible_array_member_size - index_size;
12881317
//
@@ -1296,9 +1325,9 @@ CodeGenFunction::emitCountedByMemberSize(const MemberExpr *ME, const Expr *Idx,
12961325
// count = ptr->count;
12971326
// sizeof_struct = sizeof (struct s);
12981327
//
1299-
// flexible_array_member_base_size = sizeof (*ptr->array);
1328+
// flexible_array_member_element_size = sizeof (*ptr->array);
13001329
// flexible_array_member_size =
1301-
// count * flexible_array_member_base_size;
1330+
// count * flexible_array_member_element_size;
13021331
//
13031332
// field_offset = offsetof (struct s, field);
13041333
// offset_diff = sizeof_struct - field_offset;
@@ -1308,19 +1337,19 @@ CodeGenFunction::emitCountedByMemberSize(const MemberExpr *ME, const Expr *Idx,
13081337
// cmp = (result >= 0)
13091338
// return cmp ? result : 0;
13101339
//
1311-
// 4) '&ptr->field_array[idx]':
1340+
// 4) '&((cast) ptr->field_array)[idx]':
13121341
//
13131342
// count = ptr->count;
13141343
// index = idx;
13151344
// sizeof_struct = sizeof (struct s);
13161345
//
1317-
// flexible_array_member_base_size = sizeof (*ptr->array);
1346+
// flexible_array_member_element_size = sizeof (*ptr->array);
13181347
// flexible_array_member_size =
1319-
// count * flexible_array_member_base_size;
1348+
// count * flexible_array_member_element_size;
13201349
//
1321-
// field_base_size = sizeof (*ptr->field_array);
1350+
// casted_field_element_size = sizeof (*((cast) ptr->field_array));
13221351
// field_offset = offsetof (struct s, field)
1323-
// field_offset += index * field_base_size;
1352+
// field_offset += index * casted_field_element_size;
13241353
//
13251354
// offset_diff = sizeof_struct - field_offset;
13261355
//
@@ -1334,7 +1363,6 @@ CodeGenFunction::emitCountedByMemberSize(const MemberExpr *ME, const Expr *Idx,
13341363
bool IsSigned = CountFD->getType()->isSignedIntegerType();
13351364

13361365
QualType FlexibleArrayMemberTy = FlexibleArrayMemberFD->getType();
1337-
QualType FieldTy = FD->getType();
13381366

13391367
// Explicit cast because otherwise the CharWidth will promote an i32's into
13401368
// u64's leading to overflows.
@@ -1358,31 +1386,43 @@ CodeGenFunction::emitCountedByMemberSize(const MemberExpr *ME, const Expr *Idx,
13581386
if (!Count)
13591387
return nullptr;
13601388

1361-
// flexible_array_member_base_size = sizeof (*ptr->array);
1389+
// flexible_array_member_element_size = sizeof (*ptr->array);
13621390
const ArrayType *ArrayTy = Ctx.getAsArrayType(FlexibleArrayMemberTy);
13631391
CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
1364-
auto *FlexibleArrayMemberBaseSize =
1392+
auto *FlexibleArrayMemberElementSize =
13651393
llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
13661394

1367-
// flexible_array_member_size =
1368-
// count * flexible_array_member_base_size;
1395+
// flexible_array_member_size = count * flexible_array_member_element_size;
13691396
Value *FlexibleArrayMemberSize =
1370-
Builder.CreateMul(Count, FlexibleArrayMemberBaseSize,
1397+
Builder.CreateMul(Count, FlexibleArrayMemberElementSize,
13711398
"flexible_array_member_size", !IsSigned, IsSigned);
13721399

1373-
Value *Res = nullptr;
1400+
Value *Result = nullptr;
13741401
if (FlexibleArrayMemberFD == FD) {
1375-
if (Idx) { // Option (2) '&ptr->array[idx]'
1376-
// index_size = index * flexible_array_member_base_size;
1377-
Value *IndexSize = Builder.CreateMul(FlexibleArrayMemberBaseSize, Index,
1378-
"index_size", !IsSigned, IsSigned);
1402+
if (Idx) { // Option (2) '&((cast) ptr->array)[idx]'
1403+
// casted_flexible_array_member_element_size =
1404+
// sizeof (*((cast) ptr->array));
1405+
llvm::ConstantInt *CastedFlexibleArrayMemberElementSize =
1406+
FlexibleArrayMemberElementSize;
1407+
if (!CastedArrayElementTy.isNull() &&
1408+
CastedArrayElementTy->isPointerType()) {
1409+
CharUnits BaseSize =
1410+
Ctx.getTypeSizeInChars(CastedArrayElementTy->getPointeeType());
1411+
CastedFlexibleArrayMemberElementSize =
1412+
llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
1413+
}
1414+
1415+
// index_size = index * casted_flexible_array_member_element_size;
1416+
Value *IndexSize =
1417+
Builder.CreateMul(Index, CastedFlexibleArrayMemberElementSize,
1418+
"index_size", !IsSigned, IsSigned);
13791419

13801420
// result = flexible_array_member_size - index_size;
1381-
Res = Builder.CreateSub(FlexibleArrayMemberSize, IndexSize, "result",
1382-
!IsSigned, IsSigned);
1421+
Result = Builder.CreateSub(FlexibleArrayMemberSize, IndexSize, "result",
1422+
!IsSigned, IsSigned);
13831423
} else { // Option (1) 'ptr->array'
13841424
// result = flexible_array_member_size;
1385-
Res = FlexibleArrayMemberSize;
1425+
Result = FlexibleArrayMemberSize;
13861426
}
13871427
} else {
13881428
// sizeof_struct = sizeof (struct s);
@@ -1392,29 +1432,36 @@ CodeGenFunction::emitCountedByMemberSize(const MemberExpr *ME, const Expr *Idx,
13921432
Value *SizeofStruct =
13931433
llvm::ConstantInt::get(ResType, Size.getKnownMinValue() / CharWidth);
13941434

1395-
if (Idx) { // Option (4) '&ptr->field_array[idx]'
1396-
// field_base_size = sizeof (*ptr->field_array);
1397-
const ArrayType *ArrayTy = Ctx.getAsArrayType(FieldTy);
1398-
CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
1399-
auto *FieldBaseSize =
1435+
if (Idx) { // Option (4) '&((cast) ptr->field_array)[idx]'
1436+
// casted_field_element_size = sizeof (*((cast) ptr->field_array));
1437+
CharUnits BaseSize;
1438+
if (!CastedArrayElementTy.isNull() &&
1439+
CastedArrayElementTy->isPointerType()) {
1440+
BaseSize =
1441+
Ctx.getTypeSizeInChars(CastedArrayElementTy->getPointeeType());
1442+
} else {
1443+
const ArrayType *ArrayTy = Ctx.getAsArrayType(FD->getType());
1444+
BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
1445+
}
1446+
1447+
llvm::ConstantInt *CastedFieldElementSize =
14001448
llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
14011449

1402-
// field_offset += index * field_base_size;
1403-
Value *Mul = Builder.CreateMul(Index, FieldBaseSize, "field_offset",
1404-
!IsSigned, IsSigned);
1450+
// field_offset += index * casted_field_element_size;
1451+
Value *Mul = Builder.CreateMul(Index, CastedFieldElementSize,
1452+
"field_offset", !IsSigned, IsSigned);
14051453
FieldOffset = Builder.CreateAdd(FieldOffset, Mul);
14061454
}
14071455
// Option (3) '&ptr->field', and Option (4) continuation.
1408-
14091456
// offset_diff = flexible_array_member_offset - field_offset;
14101457
Value *OffsetDiff = Builder.CreateSub(SizeofStruct, FieldOffset,
14111458
"offset_diff", !IsSigned, IsSigned);
14121459

14131460
// result = offset_diff + flexible_array_member_size;
1414-
Res = Builder.CreateAdd(FlexibleArrayMemberSize, OffsetDiff, "result");
1461+
Result = Builder.CreateAdd(FlexibleArrayMemberSize, OffsetDiff, "result");
14151462
}
14161463

1417-
return EmitPositiveResultOrZero(*this, Res, Index, ResType, IsSigned);
1464+
return EmitPositiveResultOrZero(*this, Result, Index, ResType, IsSigned);
14181465
}
14191466

14201467
/// Returns a Value corresponding to the size of the given expression.

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5412,11 +5412,14 @@ class CodeGenFunction : public CodeGenTypeCache {
54125412
unsigned Type, llvm::IntegerType *ResType);
54135413

54145414
llvm::Value *emitCountedByMemberSize(const MemberExpr *E, const Expr *Idx,
5415-
llvm::Value *EmittedE, unsigned Type,
5415+
llvm::Value *EmittedE,
5416+
QualType CastedArrayElementTy,
5417+
unsigned Type,
54165418
llvm::IntegerType *ResType);
54175419

54185420
llvm::Value *emitCountedByPointerSize(const ImplicitCastExpr *E,
54195421
const Expr *Idx, llvm::Value *EmittedE,
5422+
QualType CastedArrayElementTy,
54205423
unsigned Type,
54215424
llvm::IntegerType *ResType);
54225425

0 commit comments

Comments
 (0)