-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C #90786
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6533,8 +6533,10 @@ def warn_superclass_variable_sized_type_not_at_end : Warning< | |
|
||
def err_flexible_array_count_not_in_same_struct : Error< | ||
"'counted_by' field %0 isn't within the same struct as the flexible array">; | ||
def err_counted_by_attr_not_on_flexible_array_member : Error< | ||
"'counted_by' only applies to C99 flexible array members">; | ||
def err_counted_by_attr_not_on_ptr_or_flexible_array_member : Error< | ||
"'counted_by' only applies to pointers or C99 flexible array members">; | ||
def err_counted_by_attr_on_array_not_flexible_array_member : Error< | ||
"'counted_by' on arrays only applies to C99 flexible array members">; | ||
def err_counted_by_attr_refer_to_itself : Error< | ||
"'counted_by' cannot refer to the flexible array member %0">; | ||
def err_counted_by_must_be_in_structure : Error< | ||
|
@@ -6549,6 +6551,17 @@ def err_counted_by_attr_refer_to_union : Error< | |
"'counted_by' argument cannot refer to a union member">; | ||
def note_flexible_array_counted_by_attr_field : Note< | ||
"field %0 declared here">; | ||
def err_counted_by_attr_pointee_unknown_size : Error< | ||
"'counted_by' cannot be applied to %select{" | ||
"a pointer with pointee|" // pointer | ||
"an array with element}0" // array | ||
" of unknown size because %1 is %select{" | ||
"an incomplete type|" // CountedByInvalidPointeeTypeKind::INCOMPLETE | ||
"a sizeless type|" // CountedByInvalidPointeeTypeKind::SIZELESS | ||
"a function type|" // CountedByInvalidPointeeTypeKind::FUNCTION | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a bit confused why a function type is excluded. Isn't it just a pointer? @kees can correct me, but I think the point of struct s {
int count;
int *ptr __counted_by(count);
};
struct s *alloc(size_t num_elems) {
struct s *p = malloc(sizeof(struct s));
p->count = num_elems;
p->ptr = calloc(num_elems, sizeof(int));
return p;
} If that's the case, then any pointer should be okay. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @bwendling I was also confused by this initially. A "function type" and "function pointer type" are different. A function type doesn't have a size so we have to forbid it, but a function pointer does have a size (it's the size of a pointer). Hopefully these examples illustrate the problem: #define __counted_by(f) __attribute__((counted_by(f)))
typedef void(fn_ty)(int);
typedef void(*fn_ptr_ty)(int);
struct a {
int count;
// Buffer of functions is invalid. A "function" has no size
fn_ty* buffer __counted_by(count);
fn_ptr_ty buffer2 __counted_by(count);
};
struct b {
int count;
// Valid: A buffer of function pointers is allowed
fn_ty** buffer __counted_by(count);
fn_ptr_ty* buffer2 __counted_by(count);
}; A similar thing exists for arrays. If you write this struct c {
fn_ty Arr[];
}; this produces the following error:
However these two struct definitions are allowed by clang: struct d {
fn_ty* Arr[];
};
struct e {
fn_ptr_ty Arr2[];
}; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Ah! my mistake. :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Side note: Given the above I expected pointer arithmetic on a function pointer to be forbidden but it's not... typedef void(fn_ty)(int);
typedef void(*fn_ptr_ty)(int);
void test(fn_ty* fn) {
fn(5); // ok
// WHAT!?: How can pointer arithmetic be possible when the size of
// the function isn't a defined thing...
//
// Turns out clang codegens this as if `sizeof(*fn) == 1`
_Static_assert(sizeof(*fn) == 1, "oh boy...we're in for a wild ride");
++fn;
// Let's jump somewhere into the function that's 1 byte along from the start.
// what could possibly go wrong!?
fn(5); // CRASH
return;
} It's fine to do pointer arithmetic on an array of function pointers though typedef void(fn_ty)(int);
typedef void(*fn_ptr_ty)(int);
void do_something(int i) { printf("hello %d\n", i);}
void do_something2(int i) { printf("hello2 %d\n", i);}
fn_ptr_ty Funcs[] = { do_something, do_something2};
void test2(fn_ty** fn) {
// fn == do_something
(*fn)(5);
++fn;
// Now fn == do_something2
(*fn)(5);
return;
}
int main(void) {
test2(Funcs);
return 0;
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that as long as it's a pointer we're okay, at least w.r.t. the |
||
// CountedByInvalidPointeeTypeKind::FLEXIBLE_ARRAY_MEMBER | ||
"a struct type with a flexible array member" | ||
"}2">; | ||
|
||
let CategoryName = "ARC Semantic Issue" in { | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should mention that
counted_by
was extended to work with pointers in structs first. Otherwise, "last parsing" of the attribute doesn't make a lot of sense since a flexible array member is at the end of a struct.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can mention it but I'm wondering if it should be in the release notes at all because this patch only makes parsing work. I've not done anything on the codegen side to make use of the attribute on pointers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it doesn't have a use yet, maybe you don't need to add it in the release notes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So to add some context here. The original reason there was a release note is because in #88596 (which this patch builds upon) @AaronBallman asked for there to be a release note about the new
-fexperimental-late-parse-attributes
flag. This patch means-fexperimental-late-parse-attributes
actually does something now (before it did nothing) so I updated the release notes on that flag and it "felt" like it made sense to explain in the release notes the change on the attributes in relation to the flag.I don't have strong opinions here. I'm ok to drop the changes to the release notes or keep them or something in between. @AaronBallman any opinions here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a strong opinion either. :-) It's fine to keep the blurb in.