On Thu, Sep 03, 2026 at 08:02:20PM -0600, Gustavo A. R. Silva wrote:
> For a pointer to a subobject whose record/union type ends in a flexible-array
> member (directly, or through a trailing nested struct), addr_object_size()
> walked up to the enclosing object (v = TREE_OPERAND (v, 0)) instead of
> measuring the referenced subobject. __builtin_object_size() and
> __builtin_dynamic_object_size() type 1 therefore returned the whole-object
> size, collapsing type 1 onto type 0 and losing the distinction between
> &p->inner and p. FORTIFY_SOURCE relies on the type-1 distinction, so this
> weakens its bounds checks.
Looking at the PR:
struct flex {
size_t count;
char fam[] __attribute__((counted_by(count)));
}; /* sizeof(struct flex) == 8 */
struct outer {
int hdr;
struct flex inner;
}; /* sizeof(struct outer) == 16 */
int main (void)
{
struct outer *p = __builtin_malloc (sizeof (*p) + 48); /* 64-byte object */
/* This is a bug. */
expect(__builtin_object_size (&p->inner, 1), sizeof(p->inner));
expect(__builtin_dynamic_object_size (&p->inner, 1), sizeof(p->inner));
...
}
Before:
WAT: __builtin_object_size (&p->inner, 1) == 56 (expected 8)
WAT: __builtin_dynamic_object_size (&p->inner, 1) == 56 (expected 8)
After:
ok: __builtin_object_size (&p->inner, 1) == 8
ok: __builtin_dynamic_object_size (&p->inner, 1) == 8
This makes sense to me, the dynamic size of "fam" is ambiguous between
being 0 or 48 (from the "alloc_size" attribute), so type 1 chooses the
smaller.
I would, however, expect the use of counted_by to change it. For
example, if it were this:
struct flex {
size_t count;
char fam[] __attribute__((counted_by(count)));
};
...
struct outer *p = __builtin_malloc (sizeof (*p) + 48); /* 64-byte object */
p->inner.count = 48;
I would expect the results to be:
ok: __builtin_object_size (&p->inner, 1) == 8 /* compile-time size */
ok: __builtin_dynamic_object_size (&p->inner, 1) == 56 /* run-time size */
As the known size of p->inner is everything contained by "inner" and
that now includes the 48 bytes of "fam".
-Kees
--
Kees Cook