Skip to content

Commit 26aaa04

Browse files
committed
[Clang] Fix 'counted_by' for nested struct pointers
Fixes #110385 Fix counted_by attribute for cases where the flexible array member is accessed through struct pointer inside another struct: struct variable { int a; int b; int length; short array[] __attribute__((counted_by(length))); }; struct bucket { int a; struct variable *growable; int b; }; __builtin_dynamic_object_size(p->growable->array, 0); This commit makes sure that if the StructBase is both a MemberExpr and a pointer, it is treated as a pointer. Otherwise clang will generate to code to access the address of p->growable intead of loading the value of p->growable->length.
1 parent e203a67 commit 26aaa04

File tree

2 files changed

+44
-4
lines changed

2 files changed

+44
-4
lines changed

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,15 +1165,15 @@ llvm::Value *CodeGenFunction::EmitLoadOfCountedByField(
11651165
Res = EmitDeclRefLValue(DRE).getPointer(*this);
11661166
Res = Builder.CreateAlignedLoad(ConvertType(DRE->getType()), Res,
11671167
getPointerAlign(), "dre.load");
1168-
} else if (const MemberExpr *ME = dyn_cast<MemberExpr>(StructBase)) {
1169-
LValue LV = EmitMemberExpr(ME);
1170-
Address Addr = LV.getAddress();
1171-
Res = Addr.emitRawPointer(*this);
11721168
} else if (StructBase->getType()->isPointerType()) {
11731169
LValueBaseInfo BaseInfo;
11741170
TBAAAccessInfo TBAAInfo;
11751171
Address Addr = EmitPointerWithAlignment(StructBase, &BaseInfo, &TBAAInfo);
11761172
Res = Addr.emitRawPointer(*this);
1173+
} else if (const MemberExpr *ME = dyn_cast<MemberExpr>(StructBase)) {
1174+
LValue LV = EmitMemberExpr(ME);
1175+
Address Addr = LV.getAddress();
1176+
Res = Addr.emitRawPointer(*this);
11771177
} else {
11781178
return nullptr;
11791179
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 4
2+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -Wno-missing-declarations -emit-llvm -o - %s | FileCheck %s
3+
4+
// See #110385
5+
// Based on reproducer from Kees Cook:
6+
// https://lore.kernel.org/all/202409170436.C3C6E7F7A@keescook/
7+
8+
struct variable {
9+
int a;
10+
int b;
11+
int length;
12+
short array[] __attribute__((counted_by(length)));
13+
};
14+
15+
struct bucket {
16+
int a;
17+
struct variable *growable;
18+
int b;
19+
};
20+
21+
void init(void * __attribute__((pass_dynamic_object_size(0))));
22+
23+
// CHECK-LABEL: define dso_local void @test1(
24+
// CHECK-SAME: ptr nocapture noundef readonly [[FOO:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
25+
// CHECK-NEXT: entry:
26+
// CHECK-NEXT: [[GROWABLE:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
27+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[GROWABLE]], align 8, !tbaa [[TBAA2:![0-9]+]]
28+
// CHECK-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 12
29+
// CHECK-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 8
30+
// CHECK-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
31+
// CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[DOT_COUNTED_BY_LOAD]] to i64
32+
// CHECK-NEXT: [[TMP2:%.*]] = shl nsw i64 [[TMP1]], 1
33+
// CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[DOT_COUNTED_BY_LOAD]], -1
34+
// CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i64 [[TMP2]], i64 0
35+
// CHECK-NEXT: tail call void @init(ptr noundef nonnull [[ARRAY]], i64 noundef [[TMP4]]) #[[ATTR2:[0-9]+]]
36+
// CHECK-NEXT: ret void
37+
//
38+
void test1(struct bucket *foo) {
39+
init(foo->growable->array);
40+
}

0 commit comments

Comments
 (0)