[clang] [Clang] Fix __builtin_dynamic_object_size off by 4 (PR #111015)
Jan Hendrik Farr via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 4 11:16:21 PDT 2024
Cydox wrote:
> The point of __counted_by is precisely to supplement the normal standard rules: specifically, if you have counted_by, the size of the flexible array is precisely the size specified by the attribute. Not whatever size is implied by the access. Otherwise, it would be illegal for __bdos to use the counted_by attribute at all. The size of the array can't change based on how __bdos is queried.
Let's say we simply define a `count` that is inconsistent with the size of the object as undefined behavior.
I agree that the size of the flexible array member when the __counted_by attribute is used is exactly count multiplied by size of each element. And this PR changes none of that.
```C
__builtin_dynamic_object_size(acl->a_entries)
```
Still does exactly that and therefore bounds-checking even an off-by-1 scenario will work correctly.
This PR only changes the behavior of:
```C
__builtin_dynamic_object_size(acl)
```
Here you are not asking for the size of the FAM, but of the whole struct object. The size of that object is whatever you gave to `malloc`. **There are multiple possible sizes you could have given to `malloc` that are consistent with the same `count`**, because the standard says that "it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed". As long as the elements of the array are larger than 1 byte there are multiple `malloc` sizes that have the same correct `count`.
This is different when you ask for the size of the FAM itself, each size of the FAM only has a single correct value of `count`.
This is why I believe the gcc behavior is correct. When it knows the size given to `malloc` it uses that. When it doesn't know that it simply returns INT_MAX. When you ask gcc for the `__bdos` of the FAM it will use the `count` to calculate the size.
> `sizeof(struct s) + p->count * sizeof(*p->array))` is a weird compromise: it's not unbounded, but it's larger than the size specified by the standard.
I agree that it is a weird compromise, I'm thinking clang should to with the gcc behavior here instead.
---
However:
> but it's larger than the size specified by the standard
Can you tell me what the size specified by the standard is? Let's say for these two examples:
(1)
```
struct posix_acl *acl = malloc(sizeof(struct posix_acl) + sizeof(struct posix_acl_entry) * 1);
acl.a_count = 1;
```
(2)
```
struct posix_acl *acl = malloc(offsetof(struct posix_acl, a_entries) + sizeof(struct posix_acl_entry) * 1);
acl.a_count = 1;
```
What is the size of the object `acl` points to according to the C standard?
My answers:
(1): 40
(2): 36
https://github.com/llvm/llvm-project/pull/111015
More information about the cfe-commits
mailing list