Skip to content

Commit f7722fb

Browse files
committed
Add support for the __sized_by attribute on a 'void *'.
1 parent 638dbc8 commit f7722fb

File tree

2 files changed

+109
-10
lines changed

2 files changed

+109
-10
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,6 +1286,26 @@ llvm::Value *CodeGenFunction::emitCountedByPointerSize(
12861286

12871287
bool IsSigned = CountFD->getType()->isSignedIntegerType();
12881288

1289+
// array_base_size = sizeof (*ptr->array);
1290+
ASTContext &Ctx = getContext();
1291+
QualType ArrayBaseTy = ArrayBaseFD->getType()->getPointeeType();
1292+
CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayBaseTy);
1293+
if (BaseSize.isZero()) {
1294+
// This might be a __sized_by on a 'void *', which counts bytes, not
1295+
// elements.
1296+
auto *CAT = ArrayBaseFD->getType()->getAs<CountAttributedType>();
1297+
if (CAT->getKind() != CountAttributedType::SizedBy &&
1298+
CAT->getKind() != CountAttributedType::SizedByOrNull)
1299+
// Okay, not sure what it is now.
1300+
// FIXME: Should this be an assert?
1301+
return nullptr;
1302+
1303+
BaseSize = CharUnits::One();
1304+
}
1305+
1306+
auto *ArrayBaseSize =
1307+
llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
1308+
12891309
// count = ptr->count;
12901310
Value *Count = EmitLoadOfCountedByField(ME, ArrayBaseFD, CountFD);
12911311
if (!Count)
@@ -1300,13 +1320,6 @@ llvm::Value *CodeGenFunction::emitCountedByPointerSize(
13001320
Index = Builder.CreateIntCast(Index, ResType, IdxSigned, "index");
13011321
}
13021322

1303-
// array_base_size = sizeof (*ptr->array);
1304-
ASTContext &Ctx = getContext();
1305-
QualType ArrayBaseTy = ArrayBaseFD->getType()->getPointeeType();
1306-
CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayBaseTy);
1307-
auto *ArrayBaseSize =
1308-
llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned);
1309-
13101323
// array_size = count * array_base_size;
13111324
Value *ArraySize = Builder.CreateMul(Count, ArrayBaseSize, "array_size",
13121325
!IsSigned, IsSigned);

clang/test/CodeGen/attr-counted-by-for-pointers.c

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 3
2-
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -DCOUNTED_BY -Wall -fsanitize=array-bounds,object-size,local-bounds -fstrict-flex-arrays=3 -fexperimental-late-parse-attributes -emit-llvm -o - %s | FileCheck --check-prefix=SANITIZE-WITH-ATTR %s
3-
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -DCOUNTED_BY -Wall -fstrict-flex-arrays=3 -fexperimental-late-parse-attributes -emit-llvm -o - %s | FileCheck --check-prefix=NO-SANITIZE-WITH-ATTR %s
2+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -DWITH_ATTRS -Wall -fsanitize=array-bounds,object-size,local-bounds -fstrict-flex-arrays=3 -fexperimental-late-parse-attributes -emit-llvm -o - %s | FileCheck --check-prefix=SANITIZE-WITH-ATTR %s
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -DWITH_ATTRS -Wall -fstrict-flex-arrays=3 -fexperimental-late-parse-attributes -emit-llvm -o - %s | FileCheck --check-prefix=NO-SANITIZE-WITH-ATTR %s
44
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -Wall -fsanitize=array-bounds,object-size,local-bounds -fstrict-flex-arrays=3 -fexperimental-late-parse-attributes -emit-llvm -o - %s | FileCheck --check-prefix=SANITIZE-WITHOUT-ATTR %s
55
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -Wall -fstrict-flex-arrays=3 -fexperimental-late-parse-attributes -emit-llvm -o - %s | FileCheck --check-prefix=NO-SANITIZE-WITHOUT-ATTR %s
66

77
#if !__has_attribute(counted_by)
88
#error "has attribute broken"
99
#endif
1010

11-
#ifdef COUNTED_BY
11+
#ifdef WITH_ATTRS
1212
#define __counted_by(member) __attribute__((__counted_by__(member)))
13+
#define __sized_by(member) __attribute__((__sized_by__(member)))
1314
#else
1415
#define __counted_by(member)
16+
#define __sized_by(member)
1517
#endif
1618

1719
#define __bdos(P) __builtin_dynamic_object_size(P, 0)
@@ -214,3 +216,87 @@ size_t test3(struct annotated_ptr *p, int index) {
214216
size_t test4(struct annotated_ptr *p, int index) {
215217
return __bdos(&p->buf[index]);
216218
}
219+
220+
struct annotated_sized_ptr {
221+
unsigned long flags;
222+
void *buf __sized_by(ptr_count);
223+
int ptr_count;
224+
};
225+
226+
// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 2147483648) i64 @test5(
227+
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
228+
// SANITIZE-WITH-ATTR-NEXT: entry:
229+
// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16
230+
// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4
231+
// SANITIZE-WITH-ATTR-NEXT: [[NARROW:%.*]] = tail call i32 @llvm.smax.i32(i32 [[COUNTED_BY_LOAD]], i32 0)
232+
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext nneg i32 [[NARROW]] to i64
233+
// SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP0]]
234+
//
235+
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 2147483648) i64 @test5(
236+
// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef readonly captures(none) [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] {
237+
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
238+
// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16
239+
// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4
240+
// NO-SANITIZE-WITH-ATTR-NEXT: [[NARROW:%.*]] = tail call i32 @llvm.smax.i32(i32 [[COUNTED_BY_LOAD]], i32 0)
241+
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext nneg i32 [[NARROW]] to i64
242+
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP0]]
243+
//
244+
// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test5(
245+
// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
246+
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
247+
// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
248+
//
249+
// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test5(
250+
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef readonly captures(none) [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] {
251+
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
252+
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
253+
//
254+
size_t test5(struct annotated_sized_ptr *p, int index) {
255+
return __bdos(p->buf);
256+
}
257+
258+
// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 2147483648) i64 @test6(
259+
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
260+
// SANITIZE-WITH-ATTR-NEXT: entry:
261+
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
262+
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16
263+
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOTCOUNTED_BY_GEP]], align 4
264+
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[DOTCOUNTED_BY_LOAD]] to i64, !nosanitize [[META2]]
265+
// SANITIZE-WITH-ATTR-NEXT: [[DOTNOT:%.*]] = icmp ugt i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META2]]
266+
// SANITIZE-WITH-ATTR-NEXT: br i1 [[DOTNOT]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], label [[CONT8:%.*]], !prof [[PROF14]], !nosanitize [[META2]]
267+
// SANITIZE-WITH-ATTR: handler.out_of_bounds:
268+
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB6:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR3]], !nosanitize [[META2]]
269+
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
270+
// SANITIZE-WITH-ATTR: cont8:
271+
// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[DOTCOUNTED_BY_LOAD]] to i64
272+
// SANITIZE-WITH-ATTR-NEXT: [[RESULT:%.*]] = sub nsw i64 [[COUNT]], [[IDXPROM]]
273+
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = tail call i64 @llvm.smax.i64(i64 [[RESULT]], i64 0)
274+
// SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]]
275+
//
276+
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -4294967295, 4294967296) i64 @test6(
277+
// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef readonly captures(none) [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] {
278+
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
279+
// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
280+
// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16
281+
// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4
282+
// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64
283+
// NO-SANITIZE-WITH-ATTR-NEXT: [[RESULT:%.*]] = sub nsw i64 [[COUNT]], [[IDXPROM]]
284+
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp sgt i64 [[RESULT]], -1
285+
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[INDEX]], -1
286+
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]]
287+
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i64 [[RESULT]], i64 0
288+
// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP3]]
289+
//
290+
// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test6(
291+
// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
292+
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
293+
// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
294+
//
295+
// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test6(
296+
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef readonly captures(none) [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] {
297+
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
298+
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1
299+
//
300+
size_t test6(struct annotated_sized_ptr *p, int index) {
301+
return __bdos(&p->buf[index]);
302+
}

0 commit comments

Comments
 (0)