Linux Hardening
 help / color / mirror / Atom feed
From: "Gustavo A. R. Silva" <garsilva@embeddedor.com>
To: Jakub Jelinek <jakub@redhat.com>,
	Richard Biener <richard.guenther@gmail.com>,
	Siddhesh Poyarekar <siddhesh@gotplt.org>,
	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: [PATCH v2] tree-object-size: Fix type-1 size for FAM subobjects under -fstrict-flex-arrays=3 [PR126975]
Date: Thu, 3 Sep 2026 20:02:20 -0600	[thread overview]
Message-ID: <apomrLZp1ee3NnBF@kspp> (raw)

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.

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));
+
+  __builtin_free (p);
+  __builtin_free (op);
+
+  DONE ();
+}
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index 54c320d36d0..90d2ac32614 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -734,10 +734,13 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
 		      }
 		    /* if the ref is to a record or union type, but the type
 		       does not include a flexible array recursively, compute
-		       the object size directly.  */
+		       the object size directly.  With -fstrict-flex-arrays=3 do
+		       the same even when it does, so type 1 measures the subobject
+		       instead of collapsing onto the whole-object type-0 size.  */
 		    if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (v)))
 		      {
-			if (!TYPE_INCLUDES_FLEXARRAY (TREE_TYPE (v)))
+			if (!TYPE_INCLUDES_FLEXARRAY (TREE_TYPE (v))
+			    || flag_strict_flex_arrays == 3)
 			  {
 			    v = NULL_TREE;
 			    break;
-- 
2.47.3


                 reply	other threads:[~2026-09-03 11:03 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=apomrLZp1ee3NnBF@kspp \
    --to=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=siddhesh@gotplt.org \
    --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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox