From: Siddhesh Poyarekar <siddhesh@gotplt.org>
To: "Gustavo A. R. Silva" <garsilva@embeddedor.com>,
Jakub Jelinek <jakub@redhat.com>,
Richard Biener <richard.guenther@gmail.com>,
Kees Cook <kees@kernel.org>
Cc: gcc-patches@gcc.gnu.org, Martin Uecker <uecker@tugraz.at>,
josmyers@redhat.com, Bill Wendling <morbo@google.com>,
linux-hardening@vger.kernel.org,
"Gustavo A. R. Silva" <gustavoars@kernel.org>
Subject: Re: [PATCH v2] tree-object-size: Fix type-1 size for FAM subobjects under -fstrict-flex-arrays=3 [PR126975]
Date: Fri, 18 Sep 2026 12:19:22 -0400 [thread overview]
Message-ID: <9074daad-836b-4eeb-bf1d-01a5b11cea69@gotplt.org> (raw)
In-Reply-To: <apomrLZp1ee3NnBF@kspp>
On 2026-09-03 22:02, 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.
>
> Fix this by computing the size directly from the referenced record/union
> instead of walking up, under -fstrict-flex-arrays=3 specifically to avoid
> conflicting with -fstrict-flex-arrays semantics at lower levels, thereby
> restoring the type-0/type-1 distinction that Clang already implements.
I don't understand the rationale, why is only the declared size the
correct answer for maximum size even for -fstrict-flex-arrays=3? The
correct maximum size answer should also include the computed size of the
flex array since it's part of the inner object.
> Bootstrapped and regtested on x86_64-linux-gnu.
>
> Changes in v2:
> - Change behavior under -fstrict-flex-arrays=3 only.
> - Update subject line and changelog text.
> - Document the new type-1 behavior in extend.texi.
>
> v1:
> - Link: https://lore.kernel.org/linux-hardening/aojDH2Db6XIkVqcf@kspp/
>
> PR tree-optimization/126975
>
> gcc/ChangeLog:
>
> * tree-object-size.cc (addr_object_size): For a reference to a
> record or union type that recursively includes a flexible-array
> member, compute the object size from the referenced subobject
> instead of walking up to the enclosing object when
> -fstrict-flex-arrays=3 is in effect.
> * doc/extend.texi (__builtin_object_size): Document the type-1
> behavior for pointers to subobjects that end in a flexible array
> member, and its interaction with -fstrict-flex-arrays=3.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.dg/builtin-object-size-pr126975.c: New test.
>
> Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
> ---
> gcc/doc/extend.texi | 32 +++++++++++++
> .../gcc.dg/builtin-object-size-pr126975.c | 45 +++++++++++++++++++
> gcc/tree-object-size.cc | 7 ++-
> 3 files changed, 82 insertions(+), 2 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr126975.c
>
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index 397b05ab87d..30fdc702f13 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -17894,6 +17894,38 @@ assert (__builtin_object_size (q, 0)
> /* The subobject q points to is var.b. */
> assert (__builtin_object_size (q, 1) == sizeof (var.b));
> @end smallexample
> +
> +When, for @var{type} 1, the closest surrounding subobject is of a
> +@code{struct} or @code{union} type that ends in a flexible array
> +(@pxref{Zero Length,,Arrays of Length Zero}), either directly or through a
> +trailing nested struct, that subobject can be extended past its declared
> +size. Its size is therefore constrained only by the enclosing complete
> +object, as it is for @var{type} 0.
> +
> +Under @option{-fstrict-flex-arrays=3}, where only a true C99
> +flexible array member is treated as a flexible array, the declared size of
> +the referenced subobject is used instead, which restores the distinction
> +between @var{type} 0 and @var{type} 1 for such pointers.
> +
> +@smallexample
> +/* Compiled with -fstrict-flex-arrays=3. */
> +struct A @{ int n; char data[]; @};
> +struct B @{ int m; struct A a; @};
> +struct B *b = malloc (sizeof (struct B) + 48);
> +struct B *volatile vp = malloc (sizeof (struct B) + 48);
> +struct B *op = vp;
> +
> +/* &b->a ends in a flexible array member, but -fstrict-flex-arrays=3 makes
> + type 1 its declared size, not the whole-object (type 0) size. */
> +assert (__builtin_object_size (&b->a, 1) == sizeof (b->a));
> +/* Likewise when op is opaque, where type 0 would be (size_t) -1. */
> +assert (__builtin_object_size (&op->a, 1) == sizeof (op->a));
> +
> +/* For a pointer to the flexible array member itself, type 0 and type 1
> + both return (size_t) -1 here. */
> +assert (__builtin_object_size (op->a.data, 0) == (size_t) -1);
> +assert (__builtin_object_size (op->a.data, 1) == (size_t) -1);
> +@end smallexample
> @enddefbuiltin
>
> @defbuiltin{{size_t} __builtin_dynamic_object_size (const void * @var{ptr}, int @var{type})}
> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr126975.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr126975.c
> new file mode 100644
> index 00000000000..c8c60c4f76e
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr126975.c
> @@ -0,0 +1,45 @@
> +/* PR 126975:
> + Under -fstrict-flex-arrays=3 only a true C99 flexible-array member is
> + treated as flexible. For &subobject whose type ends in such a member,
> + __builtin_object_size/__builtin_dynamic_object_size type 1 must measure
> + the subobject, not the tail of the allocation (type 0). */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -fstrict-flex-arrays=3" } */
> +
> +#include "builtin-object-size-common.h"
> +
> +struct flex {
> + size_t count;
> + char fam[];
> +};
> +
> +struct outer {
> + int hdr;
> + struct flex inner;
> +};
> +
> +int main (void)
> +{
> + struct outer *p = __builtin_malloc (sizeof(*p) + 48);
> + struct outer *volatile vp = __builtin_malloc (sizeof(*vp) + 48);
> + struct outer *op = vp;
> +
> + /* True C99 flexible-array member: type 1 measures the subobject. */
> + EXPECT(__builtin_object_size(&p->inner, 1), sizeof(p->inner));
> + EXPECT(__builtin_dynamic_object_size(&p->inner, 1), sizeof(p->inner));
> +
> + /* Type 0 still reports the whole tail of the allocation. */
> + EXPECT(__builtin_object_size(&p->inner, 0), sizeof(p->inner) + 48);
> + EXPECT(__builtin_dynamic_object_size(&p->inner, 0), sizeof(p->inner) + 48);
> +
> + /* When op is opaque, type 0 is unknown (-1), but type 1 still measures
> + the subobject. */
> + EXPECT(__builtin_object_size(&op->inner, 0), -1);
> + EXPECT(__builtin_object_size(&op->inner, 1), sizeof(op->inner));
> + EXPECT(__builtin_dynamic_object_size(&op->inner, 1), sizeof(op->inner));
I think the ideal correct answer for __bdos(&op->inner, 1) is in fact
`sizeof (*op) + 48 - __offsetof (outer, inner)` since fam is part of
inner. The bare sizeof excludes memory allocated for the fam.
In case of an opaque pointer one may estimate the *minimum* subobject
size as being just sizeof (inner).
Thanks,
Sid
next prev parent reply other threads:[~2026-09-18 16:19 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-04 2:02 [PATCH v2] tree-object-size: Fix type-1 size for FAM subobjects under -fstrict-flex-arrays=3 [PR126975] Gustavo A. R. Silva
2026-09-17 6:58 ` Gustavo A. R. Silva
2026-09-18 16:19 ` Siddhesh Poyarekar [this message]
2026-09-19 4:22 ` Kees Cook
2026-09-19 13:27 ` Siddhesh Poyarekar
2026-09-21 11:48 ` Gustavo A. R. Silva
2026-09-21 12:46 ` Siddhesh Poyarekar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=9074daad-836b-4eeb-bf1d-01a5b11cea69@gotplt.org \
--to=siddhesh@gotplt.org \
--cc=garsilva@embeddedor.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=gustavoars@kernel.org \
--cc=jakub@redhat.com \
--cc=josmyers@redhat.com \
--cc=kees@kernel.org \
--cc=linux-hardening@vger.kernel.org \
--cc=morbo@google.com \
--cc=richard.guenther@gmail.com \
--cc=uecker@tugraz.at \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.