Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 3 additions & 14 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -919,8 +919,7 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
// 2) bdos of the whole struct, including the flexible array:
//
// __builtin_dynamic_object_size(p, 1) ==
// max(sizeof(struct s),
// offsetof(struct s, array) + p->count * sizeof(*p->array))
// sizeof(struct s) + p->count * sizeof(*p->array))
//
ASTContext &Ctx = getContext();
const Expr *Base = E->IgnoreParenImpCasts();
Expand Down Expand Up @@ -1052,22 +1051,12 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
// The whole struct is specificed in the __bdos.
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD);

// Get the offset of the FAM.
llvm::Constant *FAMOffset = ConstantInt::get(ResType, Offset, IsSigned);
Value *OffsetAndFAMSize =
Builder.CreateAdd(FAMOffset, Res, "", !IsSigned, IsSigned);

// Get the full size of the struct.
llvm::Constant *SizeofStruct =
ConstantInt::get(ResType, Layout.getSize().getQuantity(), IsSigned);

// max(sizeof(struct s),
// offsetof(struct s, array) + p->count * sizeof(*p->array))
Res = IsSigned
? Builder.CreateBinaryIntrinsic(llvm::Intrinsic::smax,
OffsetAndFAMSize, SizeofStruct)
: Builder.CreateBinaryIntrinsic(llvm::Intrinsic::umax,
OffsetAndFAMSize, SizeofStruct);
// Add full size of struct and fam size
Res = Builder.CreateAdd(SizeofStruct, Res, "", !IsSigned, IsSigned);
}

// A negative \p IdxInst or \p CountedByInst means that the index lands
Expand Down
61 changes: 61 additions & 0 deletions clang/test/CodeGen/attr-counted-by-pr111009.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 4
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -Wno-missing-declarations -emit-llvm -o - %s | FileCheck %s

// See #111009
// Based on reproducer from Thorsten Blum:
// https://lore.kernel.org/linux-kernel/[email protected]/

typedef unsigned int uid_t;
typedef unsigned int gid_t;

typedef struct {
int counter;
} atomic_t;

typedef struct refcount_struct {
atomic_t refs;
} refcount_t;

struct callback_head {
struct callback_head *next;
void (*func)(struct callback_head *head);
} __attribute__((aligned(sizeof(void *))));
#define rcu_head callback_head

typedef struct {
uid_t val;
} kuid_t;

typedef struct {
gid_t val;
} kgid_t;

struct posix_acl_entry {
short e_tag;
unsigned short e_perm;
union {
kuid_t e_uid;
kgid_t e_gid;
};
};

struct posix_acl {
refcount_t a_refcount;
struct rcu_head a_rcu;
unsigned int a_count;
struct posix_acl_entry a_entries[] __attribute__((counted_by(a_count)));
};

// CHECK-LABEL: define dso_local range(i32 32, 25) i32 @test(
// CHECK-SAME: ptr nocapture noundef readonly [[FOO:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[FOO]], i64 24
// CHECK-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 3
// CHECK-NEXT: [[CONV:%.*]] = add i32 [[TMP0]], 32
// CHECK-NEXT: ret i32 [[CONV]]
//
int test(struct posix_acl *foo) {
return __builtin_dynamic_object_size(foo, 0);
}

Loading
Loading