All of lore.kernel.org
 help / color / mirror / Atom feed
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

  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.