-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[Clang][counted_by] Support casting the array to a different type #136239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
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.
@llvm/pr-subscribers-clang Author: Bill Wendling (bwendling) ChangesC allows the programmer to cast the base array to a different type before applying the index. We need to handle that situation.
Use the index's type when calculating the size to remove from the flexible array member's total size. Patch is 96.02 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/136239.diff 2 Files Affected:
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 1e4e055e04afd..47aea8281287e 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -910,6 +910,7 @@ class StructFieldAccess
public:
const ArraySubscriptExpr *ASE = nullptr;
+ QualType ArrayElementTy;
const Expr *VisitMemberExpr(const MemberExpr *E) {
if (AddrOfSeen && E->getType()->isArrayType())
@@ -925,6 +926,7 @@ class StructFieldAccess
AddrOfSeen = false; // '&ptr->array[idx]' is okay.
ASE = E;
+ ArrayElementTy = E->getBase()->getType();
return Visit(E->getBase());
}
const Expr *VisitCastExpr(const CastExpr *E) {
@@ -1101,23 +1103,23 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
// count = ptr->count;
//
// flexible_array_member_base_size = sizeof (*ptr->array);
- // flexible_array_member_size =
- // count * flexible_array_member_base_size;
+ // flexible_array_member_size = count * flexible_array_member_base_size;
//
// if (flexible_array_member_size < 0)
// return 0;
// return flexible_array_member_size;
//
- // 2) '&ptr->array[idx]':
+ // 2) '&((cast) ptr->array)[idx]':
//
// count = ptr->count;
// index = idx;
//
+ // casted_flexible_array_member_base_size = sizeof (*((cast) ptr->array));
+ //
// flexible_array_member_base_size = sizeof (*ptr->array);
- // flexible_array_member_size =
- // count * flexible_array_member_base_size;
+ // flexible_array_member_size = count * flexible_array_member_base_size;
//
- // index_size = index * flexible_array_member_base_size;
+ // index_size = index * casted_flexible_array_member_base_size;
//
// if (flexible_array_member_size < 0 || index < 0)
// return 0;
@@ -1129,8 +1131,7 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
// sizeof_struct = sizeof (struct s);
//
// flexible_array_member_base_size = sizeof (*ptr->array);
- // flexible_array_member_size =
- // count * flexible_array_member_base_size;
+ // flexible_array_member_size = count * flexible_array_member_base_size;
//
// field_offset = offsetof (struct s, field);
// offset_diff = sizeof_struct - field_offset;
@@ -1139,19 +1140,19 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
// return 0;
// return offset_diff + flexible_array_member_size;
//
- // 4) '&ptr->field_array[idx]':
+ // 4) '&((cast) ptr->field_array)[idx]':
//
// count = ptr->count;
// index = idx;
// sizeof_struct = sizeof (struct s);
//
// flexible_array_member_base_size = sizeof (*ptr->array);
- // flexible_array_member_size =
- // count * flexible_array_member_base_size;
+ // flexible_array_member_size = count * flexible_array_member_base_size;
+ //
+ // casted_field_base_size = sizeof (*((cast) ptr->field_array));
//
- // field_base_size = sizeof (*ptr->field_array);
// field_offset = offsetof (struct s, field)
- // field_offset += index * field_base_size;
+ // field_offset += index * casted_field_base_size;
//
// offset_diff = sizeof_struct - field_offset;
//
@@ -1162,14 +1163,11 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
QualType CountTy = CountFD->getType();
bool IsSigned = CountTy->isSignedIntegerType();
- QualType FlexibleArrayMemberTy = FlexibleArrayMemberFD->getType();
- QualType FieldTy = FD->getType();
-
// Explicit cast because otherwise the CharWidth will promote an i32's into
// u64's leading to overflows..
int64_t CharWidth = static_cast<int64_t>(CGM.getContext().getCharWidth());
- // size_t field_offset = offsetof (struct s, field);
+ // field_offset = offsetof (struct s, field);
Value *FieldOffset = nullptr;
if (FlexibleArrayMemberFD != FD) {
std::optional<int64_t> Offset = GetFieldOffset(Ctx, RD, FD);
@@ -1179,13 +1177,13 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
llvm::ConstantInt::get(ResType, *Offset / CharWidth, IsSigned);
}
- // size_t count = (size_t) ptr->count;
+ // count = ptr->count;
Value *Count = EmitLoadOfCountedByField(ME, FlexibleArrayMemberFD, CountFD);
if (!Count)
return nullptr;
Count = Builder.CreateIntCast(Count, ResType, IsSigned, "count");
- // size_t index = (size_t) ptr->index;
+ // index = ptr->index;
Value *Index = nullptr;
if (Idx) {
bool IdxSigned = Idx->getType()->isSignedIntegerType();
@@ -1193,23 +1191,35 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
Index = Builder.CreateIntCast(Index, ResType, IdxSigned, "index");
}
- // size_t flexible_array_member_base_size = sizeof (*ptr->array);
- const ArrayType *ArrayTy = Ctx.getAsArrayType(FlexibleArrayMemberTy);
- CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
+ // flexible_array_member_base_size = sizeof (*ptr->array);
+ QualType FlexibleArrayMemberTy = FlexibleArrayMemberFD->getType();
+ const ArrayType *FAMTy = Ctx.getAsArrayType(FlexibleArrayMemberTy);
+ CharUnits BaseSize = Ctx.getTypeSizeInChars(FAMTy->getElementType());
auto *FlexibleArrayMemberBaseSize =
llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
- // size_t flexible_array_member_size =
- // count * flexible_array_member_base_size;
+ // flexible_array_member_size = count * flexible_array_member_base_size;
Value *FlexibleArrayMemberSize =
Builder.CreateMul(Count, FlexibleArrayMemberBaseSize,
"flexible_array_member_size", !IsSigned, IsSigned);
+ QualType CastedArrayElementTy = Visitor.ArrayElementTy;
+ llvm::ConstantInt *CastedArrayElementSize = nullptr;
+ if (!CastedArrayElementTy.isNull() && CastedArrayElementTy->isPointerType()) {
+ const PointerType *FAMTy = cast<clang::PointerType>(CastedArrayElementTy);
+ CharUnits BaseSize = Ctx.getTypeSizeInChars(FAMTy->getPointeeType());
+ CastedArrayElementSize =
+ llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
+ }
+
Value *Res = nullptr;
if (FlexibleArrayMemberFD == FD) {
- if (Idx) { // Option (2) '&ptr->array[idx]'
- // size_t index_size = index * flexible_array_member_base_size;
- Value *IndexSize = Builder.CreateMul(FlexibleArrayMemberBaseSize, Index,
+ if (Idx) { // Option (2) '&((cast) ptr->array)[idx]'
+ if (!CastedArrayElementSize)
+ CastedArrayElementSize = FlexibleArrayMemberBaseSize;
+
+ // index_size = index * flexible_array_member_base_size;
+ Value *IndexSize = Builder.CreateMul(CastedArrayElementSize, Index,
"index_size", !IsSigned, IsSigned);
// return flexible_array_member_size - index_size;
@@ -1220,28 +1230,30 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
Res = FlexibleArrayMemberSize;
}
} else {
- // size_t sizeof_struct = sizeof (struct s);
+ // sizeof_struct = sizeof (struct s);
llvm::StructType *StructTy = getTypes().getCGRecordLayout(RD).getLLVMType();
const llvm::DataLayout &Layout = CGM.getDataLayout();
TypeSize Size = Layout.getTypeSizeInBits(StructTy);
Value *SizeofStruct =
llvm::ConstantInt::get(ResType, Size.getKnownMinValue() / CharWidth);
- if (Idx) { // Option (4) '&ptr->field_array[idx]'
- // size_t field_base_size = sizeof (*ptr->field_array);
- const ArrayType *ArrayTy = Ctx.getAsArrayType(FieldTy);
- CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
- auto *FieldBaseSize =
- llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
+ if (Idx) { // Option (4) '&((cast) ptr->field_array)[idx]'
+ // casted_field_base_size = sizeof (*((cast) ptr->field_array));
+ if (!CastedArrayElementSize) {
+ const ArrayType *ArrayTy = Ctx.getAsArrayType(FD->getType());
+ CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
+ CastedArrayElementSize =
+ llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
+ }
- // field_offset += index * field_base_size;
- Value *Mul = Builder.CreateMul(Index, FieldBaseSize, "field_offset",
+ // field_offset += index * casted_field_base_size;
+ Value *Mul = Builder.CreateMul(Index, CastedArrayElementSize, "field_offset",
!IsSigned, IsSigned);
FieldOffset = Builder.CreateAdd(FieldOffset, Mul);
}
// Option (3) '&ptr->field', and Option (4) continuation.
- // size_t offset_diff = flexible_array_member_offset - field_offset;
+ // offset_diff = flexible_array_member_offset - field_offset;
Value *OffsetDiff = Builder.CreateSub(SizeofStruct, FieldOffset,
"offset_diff", !IsSigned, IsSigned);
diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c
index 8e062629464dd..101949af208e1 100644
--- a/clang/test/CodeGen/attr-counted-by.c
+++ b/clang/test/CodeGen/attr-counted-by.c
@@ -68,7 +68,7 @@ struct anon_struct {
// 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:![0-9]+]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR12:[0-9]+]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR8:[0-9]+]], !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
@@ -116,7 +116,7 @@ void test1(struct annotated *p, int index, int val) {
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ult i64 [[INDEX]], [[TMP0]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label [[CONT6:%.*]], 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 @[[GLOB3:[0-9]+]], i64 [[INDEX]]) #[[ATTR12]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB3:[0-9]+]], i64 [[INDEX]]) #[[ATTR8]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont6:
// SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
@@ -159,7 +159,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 noundef [[P:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
+// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4
@@ -181,7 +181,7 @@ void test2(struct annotated *p, size_t index) {
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]]
//
// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test2_bdos(
-// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
+// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
//
@@ -194,6 +194,42 @@ size_t test2_bdos(struct annotated *p) {
return __bdos(p->array);
}
+// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -8589934592, 8589934589) i64 @test2_bdos_cast(
+// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SANITIZE-WITH-ATTR-NEXT: entry:
+// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4
+// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64
+// SANITIZE-WITH-ATTR-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl nsw i64 [[COUNT]], 2
+// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[COUNTED_BY_LOAD]], -1
+// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = select i1 [[TMP0]], i64 [[FLEXIBLE_ARRAY_MEMBER_SIZE]], i64 0
+// SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]]
+//
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -8589934592, 8589934589) i64 @test2_bdos_cast(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef readonly captures(none) [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// NO-SANITIZE-WITH-ATTR-NEXT: entry:
+// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4
+// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64
+// NO-SANITIZE-WITH-ATTR-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl nsw i64 [[COUNT]], 2
+// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[COUNTED_BY_LOAD]], -1
+// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = select i1 [[TMP0]], i64 [[FLEXIBLE_ARRAY_MEMBER_SIZE]], i64 0
+// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]]
+//
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test2_bdos_cast(
+// 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 @test2_bdos_cast(
+// 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 test2_bdos_cast(struct annotated *p) {
+ return __bdos((char *)p->array);
+}
+
// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test3(
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
@@ -203,7 +239,7 @@ size_t test2_bdos(struct annotated *p) {
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ult i64 [[INDEX]], [[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 @[[GLOB4:[0-9]+]], i64 [[INDEX]]) #[[ATTR12]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB4:[0-9]+]], i64 [[INDEX]]) #[[ATTR8]], !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
@@ -242,7 +278,7 @@ void test3(struct annotated *p, size_t index) {
}
// SANITIZE-WITH-ATTR-LABEL: define dso_local i64 @test3_bdos(
-// SANITIZE-WITH-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] {
+// SANITIZE-WITH-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
@@ -252,7 +288,7 @@ void test3(struct annotated *p, size_t index) {
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test3_bdos(
-// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] {
+// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
//
@@ -265,6 +301,30 @@ size_t test3_bdos(struct annotated *p) {
return __bdos(p);
}
+// SANITIZE-WITH-ATTR-LABEL: define dso_local i64 @test3_bdos_cast(
+// SANITIZE-WITH-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// SANITIZE-WITH-ATTR-NEXT: entry:
+// SANITIZE-WITH-ATTR-NEXT: ret i64 -1
+//
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i64 @test3_bdos_cast(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr 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 i64 @test3_bdos_cast(
+// SANITIZE-WITHOUT-ATTR-SAME: ptr 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 i64 @test3_bdos_cast(
+// 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 test3_bdos_cast(struct annotated *p) {
+ return __bdos((char *)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:
@@ -275,7 +335,7 @@ size_t test3_bdos(struct annotated *p) {
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[DOTCOUNTED_BY_LOAD]], 2
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label [[CONT1:%.*]], 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 @[[GLOB5:[0-9]+]], i64 3) #[[ATTR12]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 3) #[[ATTR8]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont1:
// SANITIZE-WITH-ATTR-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl i32 [[DOTCOUNTED_BY_LOAD]], 2
@@ -283,7 +343,7 @@ size_t test3_bdos(struct annotated *p) {
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label [[CONT12:%.*]], label [[HANDLER_OUT_OF_BOUNDS8:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds8:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB6:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR12]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB6:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR8]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont12:
// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 2
@@ -295,7 +355,7 @@ size_t test3_bdos(struct annotated *p) {
// SANITIZE-WITH-ATTR-NEXT: [[DOTNOT81:%.*]] = icmp eq i32 [[DOTCOUNTED_BY_LOAD]], 3
// SANITIZE-WITH-ATTR-NEXT: br i1 [[DOTNOT81]], label [[HANDLER_OUT_OF_BOUNDS18:%.*]], label [[CONT19:%.*]], !prof [[PROF8:![0-9]+]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds18:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB7:[0-9]+]], i64 4) #[[ATTR12]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(...
[truncated]
|
@llvm/pr-subscribers-clang-codegen Author: Bill Wendling (bwendling) ChangesC allows the programmer to cast the base array to a different type before applying the index. We need to handle that situation.
Use the index's type when calculating the size to remove from the flexible array member's total size. Patch is 96.02 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/136239.diff 2 Files Affected:
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 1e4e055e04afd..47aea8281287e 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -910,6 +910,7 @@ class StructFieldAccess
public:
const ArraySubscriptExpr *ASE = nullptr;
+ QualType ArrayElementTy;
const Expr *VisitMemberExpr(const MemberExpr *E) {
if (AddrOfSeen && E->getType()->isArrayType())
@@ -925,6 +926,7 @@ class StructFieldAccess
AddrOfSeen = false; // '&ptr->array[idx]' is okay.
ASE = E;
+ ArrayElementTy = E->getBase()->getType();
return Visit(E->getBase());
}
const Expr *VisitCastExpr(const CastExpr *E) {
@@ -1101,23 +1103,23 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
// count = ptr->count;
//
// flexible_array_member_base_size = sizeof (*ptr->array);
- // flexible_array_member_size =
- // count * flexible_array_member_base_size;
+ // flexible_array_member_size = count * flexible_array_member_base_size;
//
// if (flexible_array_member_size < 0)
// return 0;
// return flexible_array_member_size;
//
- // 2) '&ptr->array[idx]':
+ // 2) '&((cast) ptr->array)[idx]':
//
// count = ptr->count;
// index = idx;
//
+ // casted_flexible_array_member_base_size = sizeof (*((cast) ptr->array));
+ //
// flexible_array_member_base_size = sizeof (*ptr->array);
- // flexible_array_member_size =
- // count * flexible_array_member_base_size;
+ // flexible_array_member_size = count * flexible_array_member_base_size;
//
- // index_size = index * flexible_array_member_base_size;
+ // index_size = index * casted_flexible_array_member_base_size;
//
// if (flexible_array_member_size < 0 || index < 0)
// return 0;
@@ -1129,8 +1131,7 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
// sizeof_struct = sizeof (struct s);
//
// flexible_array_member_base_size = sizeof (*ptr->array);
- // flexible_array_member_size =
- // count * flexible_array_member_base_size;
+ // flexible_array_member_size = count * flexible_array_member_base_size;
//
// field_offset = offsetof (struct s, field);
// offset_diff = sizeof_struct - field_offset;
@@ -1139,19 +1140,19 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
// return 0;
// return offset_diff + flexible_array_member_size;
//
- // 4) '&ptr->field_array[idx]':
+ // 4) '&((cast) ptr->field_array)[idx]':
//
// count = ptr->count;
// index = idx;
// sizeof_struct = sizeof (struct s);
//
// flexible_array_member_base_size = sizeof (*ptr->array);
- // flexible_array_member_size =
- // count * flexible_array_member_base_size;
+ // flexible_array_member_size = count * flexible_array_member_base_size;
+ //
+ // casted_field_base_size = sizeof (*((cast) ptr->field_array));
//
- // field_base_size = sizeof (*ptr->field_array);
// field_offset = offsetof (struct s, field)
- // field_offset += index * field_base_size;
+ // field_offset += index * casted_field_base_size;
//
// offset_diff = sizeof_struct - field_offset;
//
@@ -1162,14 +1163,11 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
QualType CountTy = CountFD->getType();
bool IsSigned = CountTy->isSignedIntegerType();
- QualType FlexibleArrayMemberTy = FlexibleArrayMemberFD->getType();
- QualType FieldTy = FD->getType();
-
// Explicit cast because otherwise the CharWidth will promote an i32's into
// u64's leading to overflows..
int64_t CharWidth = static_cast<int64_t>(CGM.getContext().getCharWidth());
- // size_t field_offset = offsetof (struct s, field);
+ // field_offset = offsetof (struct s, field);
Value *FieldOffset = nullptr;
if (FlexibleArrayMemberFD != FD) {
std::optional<int64_t> Offset = GetFieldOffset(Ctx, RD, FD);
@@ -1179,13 +1177,13 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
llvm::ConstantInt::get(ResType, *Offset / CharWidth, IsSigned);
}
- // size_t count = (size_t) ptr->count;
+ // count = ptr->count;
Value *Count = EmitLoadOfCountedByField(ME, FlexibleArrayMemberFD, CountFD);
if (!Count)
return nullptr;
Count = Builder.CreateIntCast(Count, ResType, IsSigned, "count");
- // size_t index = (size_t) ptr->index;
+ // index = ptr->index;
Value *Index = nullptr;
if (Idx) {
bool IdxSigned = Idx->getType()->isSignedIntegerType();
@@ -1193,23 +1191,35 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
Index = Builder.CreateIntCast(Index, ResType, IdxSigned, "index");
}
- // size_t flexible_array_member_base_size = sizeof (*ptr->array);
- const ArrayType *ArrayTy = Ctx.getAsArrayType(FlexibleArrayMemberTy);
- CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
+ // flexible_array_member_base_size = sizeof (*ptr->array);
+ QualType FlexibleArrayMemberTy = FlexibleArrayMemberFD->getType();
+ const ArrayType *FAMTy = Ctx.getAsArrayType(FlexibleArrayMemberTy);
+ CharUnits BaseSize = Ctx.getTypeSizeInChars(FAMTy->getElementType());
auto *FlexibleArrayMemberBaseSize =
llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
- // size_t flexible_array_member_size =
- // count * flexible_array_member_base_size;
+ // flexible_array_member_size = count * flexible_array_member_base_size;
Value *FlexibleArrayMemberSize =
Builder.CreateMul(Count, FlexibleArrayMemberBaseSize,
"flexible_array_member_size", !IsSigned, IsSigned);
+ QualType CastedArrayElementTy = Visitor.ArrayElementTy;
+ llvm::ConstantInt *CastedArrayElementSize = nullptr;
+ if (!CastedArrayElementTy.isNull() && CastedArrayElementTy->isPointerType()) {
+ const PointerType *FAMTy = cast<clang::PointerType>(CastedArrayElementTy);
+ CharUnits BaseSize = Ctx.getTypeSizeInChars(FAMTy->getPointeeType());
+ CastedArrayElementSize =
+ llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
+ }
+
Value *Res = nullptr;
if (FlexibleArrayMemberFD == FD) {
- if (Idx) { // Option (2) '&ptr->array[idx]'
- // size_t index_size = index * flexible_array_member_base_size;
- Value *IndexSize = Builder.CreateMul(FlexibleArrayMemberBaseSize, Index,
+ if (Idx) { // Option (2) '&((cast) ptr->array)[idx]'
+ if (!CastedArrayElementSize)
+ CastedArrayElementSize = FlexibleArrayMemberBaseSize;
+
+ // index_size = index * flexible_array_member_base_size;
+ Value *IndexSize = Builder.CreateMul(CastedArrayElementSize, Index,
"index_size", !IsSigned, IsSigned);
// return flexible_array_member_size - index_size;
@@ -1220,28 +1230,30 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE,
Res = FlexibleArrayMemberSize;
}
} else {
- // size_t sizeof_struct = sizeof (struct s);
+ // sizeof_struct = sizeof (struct s);
llvm::StructType *StructTy = getTypes().getCGRecordLayout(RD).getLLVMType();
const llvm::DataLayout &Layout = CGM.getDataLayout();
TypeSize Size = Layout.getTypeSizeInBits(StructTy);
Value *SizeofStruct =
llvm::ConstantInt::get(ResType, Size.getKnownMinValue() / CharWidth);
- if (Idx) { // Option (4) '&ptr->field_array[idx]'
- // size_t field_base_size = sizeof (*ptr->field_array);
- const ArrayType *ArrayTy = Ctx.getAsArrayType(FieldTy);
- CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
- auto *FieldBaseSize =
- llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
+ if (Idx) { // Option (4) '&((cast) ptr->field_array)[idx]'
+ // casted_field_base_size = sizeof (*((cast) ptr->field_array));
+ if (!CastedArrayElementSize) {
+ const ArrayType *ArrayTy = Ctx.getAsArrayType(FD->getType());
+ CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
+ CastedArrayElementSize =
+ llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
+ }
- // field_offset += index * field_base_size;
- Value *Mul = Builder.CreateMul(Index, FieldBaseSize, "field_offset",
+ // field_offset += index * casted_field_base_size;
+ Value *Mul = Builder.CreateMul(Index, CastedArrayElementSize, "field_offset",
!IsSigned, IsSigned);
FieldOffset = Builder.CreateAdd(FieldOffset, Mul);
}
// Option (3) '&ptr->field', and Option (4) continuation.
- // size_t offset_diff = flexible_array_member_offset - field_offset;
+ // offset_diff = flexible_array_member_offset - field_offset;
Value *OffsetDiff = Builder.CreateSub(SizeofStruct, FieldOffset,
"offset_diff", !IsSigned, IsSigned);
diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c
index 8e062629464dd..101949af208e1 100644
--- a/clang/test/CodeGen/attr-counted-by.c
+++ b/clang/test/CodeGen/attr-counted-by.c
@@ -68,7 +68,7 @@ struct anon_struct {
// 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:![0-9]+]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR12:[0-9]+]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR8:[0-9]+]], !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
@@ -116,7 +116,7 @@ void test1(struct annotated *p, int index, int val) {
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ult i64 [[INDEX]], [[TMP0]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label [[CONT6:%.*]], 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 @[[GLOB3:[0-9]+]], i64 [[INDEX]]) #[[ATTR12]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB3:[0-9]+]], i64 [[INDEX]]) #[[ATTR8]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont6:
// SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
@@ -159,7 +159,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 noundef [[P:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
+// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4
@@ -181,7 +181,7 @@ void test2(struct annotated *p, size_t index) {
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]]
//
// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test2_bdos(
-// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
+// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
//
@@ -194,6 +194,42 @@ size_t test2_bdos(struct annotated *p) {
return __bdos(p->array);
}
+// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -8589934592, 8589934589) i64 @test2_bdos_cast(
+// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SANITIZE-WITH-ATTR-NEXT: entry:
+// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4
+// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64
+// SANITIZE-WITH-ATTR-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl nsw i64 [[COUNT]], 2
+// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[COUNTED_BY_LOAD]], -1
+// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = select i1 [[TMP0]], i64 [[FLEXIBLE_ARRAY_MEMBER_SIZE]], i64 0
+// SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]]
+//
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -8589934592, 8589934589) i64 @test2_bdos_cast(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef readonly captures(none) [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// NO-SANITIZE-WITH-ATTR-NEXT: entry:
+// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4
+// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64
+// NO-SANITIZE-WITH-ATTR-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl nsw i64 [[COUNT]], 2
+// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[COUNTED_BY_LOAD]], -1
+// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = select i1 [[TMP0]], i64 [[FLEXIBLE_ARRAY_MEMBER_SIZE]], i64 0
+// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]]
+//
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test2_bdos_cast(
+// 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 @test2_bdos_cast(
+// 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 test2_bdos_cast(struct annotated *p) {
+ return __bdos((char *)p->array);
+}
+
// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test3(
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
@@ -203,7 +239,7 @@ size_t test2_bdos(struct annotated *p) {
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ult i64 [[INDEX]], [[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 @[[GLOB4:[0-9]+]], i64 [[INDEX]]) #[[ATTR12]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB4:[0-9]+]], i64 [[INDEX]]) #[[ATTR8]], !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
@@ -242,7 +278,7 @@ void test3(struct annotated *p, size_t index) {
}
// SANITIZE-WITH-ATTR-LABEL: define dso_local i64 @test3_bdos(
-// SANITIZE-WITH-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] {
+// SANITIZE-WITH-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
@@ -252,7 +288,7 @@ void test3(struct annotated *p, size_t index) {
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 -1
//
// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test3_bdos(
-// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] {
+// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
//
@@ -265,6 +301,30 @@ size_t test3_bdos(struct annotated *p) {
return __bdos(p);
}
+// SANITIZE-WITH-ATTR-LABEL: define dso_local i64 @test3_bdos_cast(
+// SANITIZE-WITH-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// SANITIZE-WITH-ATTR-NEXT: entry:
+// SANITIZE-WITH-ATTR-NEXT: ret i64 -1
+//
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i64 @test3_bdos_cast(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr 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 i64 @test3_bdos_cast(
+// SANITIZE-WITHOUT-ATTR-SAME: ptr 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 i64 @test3_bdos_cast(
+// 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 test3_bdos_cast(struct annotated *p) {
+ return __bdos((char *)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:
@@ -275,7 +335,7 @@ size_t test3_bdos(struct annotated *p) {
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[DOTCOUNTED_BY_LOAD]], 2
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label [[CONT1:%.*]], 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 @[[GLOB5:[0-9]+]], i64 3) #[[ATTR12]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 3) #[[ATTR8]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont1:
// SANITIZE-WITH-ATTR-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl i32 [[DOTCOUNTED_BY_LOAD]], 2
@@ -283,7 +343,7 @@ size_t test3_bdos(struct annotated *p) {
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label [[CONT12:%.*]], label [[HANDLER_OUT_OF_BOUNDS8:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds8:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB6:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR12]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB6:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR8]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: cont12:
// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 2
@@ -295,7 +355,7 @@ size_t test3_bdos(struct annotated *p) {
// SANITIZE-WITH-ATTR-NEXT: [[DOTNOT81:%.*]] = icmp eq i32 [[DOTCOUNTED_BY_LOAD]], 3
// SANITIZE-WITH-ATTR-NEXT: br i1 [[DOTNOT81]], label [[HANDLER_OUT_OF_BOUNDS18:%.*]], label [[CONT19:%.*]], !prof [[PROF8:![0-9]+]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR: handler.out_of_bounds18:
-// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB7:[0-9]+]], i64 4) #[[ATTR12]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(...
[truncated]
|
I added testcases and also ran tests to make sure that the correct value's returned by __bdos. |
✅ With the latest revision this PR passed the C/C++ code formatter. |
Also, I'm going to have a larger patch coming after this which will support __bdos on pointers with __counted_by. It contains some refactoring which will help readability a bit more. |
C allows the programmer to cast the base array to a different type before applying the index. We need to handle that situation.
Use the index's type when calculating the size to remove from the flexible array member's total size.