public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/2]PR101832: Handle component_ref to a structure/union field including flexible array member for builtin_object_size
@ 2023-01-31 14:11 Qing Zhao
  2023-01-31 14:11 ` [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832] Qing Zhao
  2023-01-31 14:11 ` [PATCH 2/2] Documentation Update Qing Zhao
  0 siblings, 2 replies; 45+ messages in thread
From: Qing Zhao @ 2023-01-31 14:11 UTC (permalink / raw)
  To: rguenther; +Cc: gcc-patches, siddhesh, keescook, Qing Zhao

This is the patch for PR101832, to fix builtin_object_size to
correctly handle component_ref to a structure/union field that
includes a flexible array member.

also includes a documentation update for the GCC extension on embedding
a structure/union with flexible array member into another structure.

bootstrapped and regression tested on aarch64 and x86.

Okay for commit?

thanks.

Qing


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-01-31 14:11 [PATCH 0/2]PR101832: Handle component_ref to a structure/union field including flexible array member for builtin_object_size Qing Zhao
@ 2023-01-31 14:11 ` Qing Zhao
  2023-02-01 11:41   ` Richard Biener
  2023-02-01 16:48   ` Siddhesh Poyarekar
  2023-01-31 14:11 ` [PATCH 2/2] Documentation Update Qing Zhao
  1 sibling, 2 replies; 45+ messages in thread
From: Qing Zhao @ 2023-01-31 14:11 UTC (permalink / raw)
  To: rguenther; +Cc: gcc-patches, siddhesh, keescook, Qing Zhao

GCC extension accepts the case when a struct with a flexible array member
is embedded into another struct (possibly recursively).
__builtin_object_size should treat such struct as flexible size per
-fstrict-flex-arrays.

	PR tree-optimization/101832

gcc/ChangeLog:

	PR tree-optimization/101832
	* tree-object-size.cc (flexible_size_type_p): New function.
	(addr_object_size): Handle structure/union type when it has
	flexible size.

gcc/testsuite/ChangeLog:

	PR tree-optimization/101832
	* gcc.dg/builtin-object-size-pr101832-2.c: New test.
	* gcc.dg/builtin-object-size-pr101832-3.c: New test.
	* gcc.dg/builtin-object-size-pr101832-4.c: New test.
	* gcc.dg/builtin-object-size-pr101832.c: New test.
---
 .../gcc.dg/builtin-object-size-pr101832-2.c   | 135 ++++++++++++++++++
 .../gcc.dg/builtin-object-size-pr101832-3.c   | 135 ++++++++++++++++++
 .../gcc.dg/builtin-object-size-pr101832-4.c   | 135 ++++++++++++++++++
 .../gcc.dg/builtin-object-size-pr101832.c     | 119 +++++++++++++++
 gcc/tree-object-size.cc                       | 115 +++++++++++----
 5 files changed, 611 insertions(+), 28 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
 create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c

diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
new file mode 100644
index 00000000000..f38babc5415
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
@@ -0,0 +1,135 @@
+/* PR 101832: 
+   GCC extension accepts the case when a struct with a flexible array member
+   is embedded into another struct (possibly recursively).
+   __builtin_object_size will treat such struct as flexible size per
+   -fstrict-flex-arrays.  */ 
+/* { dg-do run } */
+/* { dg-options "-O2 -fstrict-flex-arrays=1" } */
+
+#include <stdio.h>
+
+unsigned n_fails = 0;
+
+#define expect(p, _v) do { \
+  size_t v = _v; \
+  if (p == v) \
+    printf("ok:  %s == %zd\n", #p, p); \
+  else {\
+    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+    n_fails++; \
+  } \
+} while (0);
+
+struct A {
+  int n;
+  char data[];/* Content following header */
+};
+
+struct B {
+  int m;
+  struct A a;
+};
+
+struct C {
+  int q;
+  struct B b;
+};
+
+struct A0 {
+  int n;
+  char data[0];/* Content following header */
+};
+
+struct B0 {
+  int m;
+  struct A0 a;
+};
+
+struct C0 {
+  int q;
+  struct B0 b;
+};
+
+struct A1 {
+  int n;
+  char data[1];/* Content following header */
+};
+
+struct B1 {
+  int m;
+  struct A1 a;
+};
+
+struct C1 {
+  int q;
+  struct B1 b;
+};
+
+struct An {
+  int n;
+  char data[8];/* Content following header */
+};
+
+struct Bn {
+  int m;
+  struct An a;
+};
+
+struct Cn {
+  int q;
+  struct Bn b;
+};
+
+volatile void *magic1, *magic2;
+
+int main(int argc, char *argv[])
+{
+    struct B *outer;
+    struct C *outest;
+
+    /* Make sure optimization can't find some other object size. */
+    outer = (void *)magic1;
+    outest = (void *)magic2;
+
+    expect(__builtin_object_size(&outer->a, 1), -1);
+    expect(__builtin_object_size(&outest->b, 1), -1);
+    expect(__builtin_object_size(&outest->b.a, 1), -1);
+
+    struct B0 *outer0;
+    struct C0 *outest0;
+
+    /* Make sure optimization can't find some other object size. */
+    outer0 = (void *)magic1;
+    outest0 = (void *)magic2;
+
+    expect(__builtin_object_size(&outer0->a, 1), -1);
+    expect(__builtin_object_size(&outest0->b, 1), -1);
+    expect(__builtin_object_size(&outest0->b.a, 1), -1);
+
+    struct B1 *outer1;
+    struct C1 *outest1;
+
+    /* Make sure optimization can't find some other object size. */
+    outer1 = (void *)magic1;
+    outest1 = (void *)magic2;
+
+    expect(__builtin_object_size(&outer1->a, 1), -1);
+    expect(__builtin_object_size(&outest1->b, 1), -1);
+    expect(__builtin_object_size(&outest1->b.a, 1), -1);
+
+    struct Bn *outern;
+    struct Cn *outestn;
+
+    /* Make sure optimization can't find some other object size. */
+    outern = (void *)magic1;
+    outestn = (void *)magic2;
+
+    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
+    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
+    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
+
+    if (n_fails > 0)
+      __builtin_abort ();
+
+    return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
new file mode 100644
index 00000000000..aaae99b8d67
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
@@ -0,0 +1,135 @@
+/* PR 101832: 
+   GCC extension accepts the case when a struct with a flexible array member
+   is embedded into another struct (possibly recursively).
+   __builtin_object_size will treat such struct as flexible size per
+   -fstrict-flex-arrays.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -fstrict-flex-arrays=2" } */
+
+#include <stdio.h>
+
+unsigned n_fails = 0;
+
+#define expect(p, _v) do { \
+  size_t v = _v; \
+  if (p == v) \
+    printf("ok:  %s == %zd\n", #p, p); \
+  else {\
+    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+    n_fails++; \
+  } \
+} while (0);
+
+struct A {
+  int n;
+  char data[];/* Content following header */
+};
+
+struct B {
+  int m;
+  struct A a;
+};
+
+struct C {
+  int q;
+  struct B b;
+};
+
+struct A0 {
+  int n;
+  char data[0];/* Content following header */
+};
+
+struct B0 {
+  int m;
+  struct A0 a;
+};
+
+struct C0 {
+  int q;
+  struct B0 b;
+};
+
+struct A1 {
+  int n;
+  char data[1];/* Content following header */
+};
+
+struct B1 {
+  int m;
+  struct A1 a;
+};
+
+struct C1 {
+  int q;
+  struct B1 b;
+};
+
+struct An {
+  int n;
+  char data[8];/* Content following header */
+};
+
+struct Bn {
+  int m;
+  struct An a;
+};
+
+struct Cn {
+  int q;
+  struct Bn b;
+};
+
+volatile void *magic1, *magic2;
+
+int main(int argc, char *argv[])
+{
+    struct B *outer;
+    struct C *outest;
+
+    /* Make sure optimization can't find some other object size. */
+    outer = (void *)magic1;
+    outest = (void *)magic2;
+
+    expect(__builtin_object_size(&outer->a, 1), -1);
+    expect(__builtin_object_size(&outest->b, 1), -1);
+    expect(__builtin_object_size(&outest->b.a, 1), -1);
+
+    struct B0 *outer0;
+    struct C0 *outest0;
+
+    /* Make sure optimization can't find some other object size. */
+    outer0 = (void *)magic1;
+    outest0 = (void *)magic2;
+
+    expect(__builtin_object_size(&outer0->a, 1), -1);
+    expect(__builtin_object_size(&outest0->b, 1), -1);
+    expect(__builtin_object_size(&outest0->b.a, 1), -1);
+
+    struct B1 *outer1;
+    struct C1 *outest1;
+
+    /* Make sure optimization can't find some other object size. */
+    outer1 = (void *)magic1;
+    outest1 = (void *)magic2;
+
+    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
+    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
+    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
+
+    struct Bn *outern;
+    struct Cn *outestn;
+
+    /* Make sure optimization can't find some other object size. */
+    outern = (void *)magic1;
+    outestn = (void *)magic2;
+
+    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
+    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
+    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
+
+    if (n_fails > 0)
+      __builtin_abort ();
+
+    return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
new file mode 100644
index 00000000000..424264e2acd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
@@ -0,0 +1,135 @@
+/* PR 101832: 
+   GCC extension accepts the case when a struct with a flexible array member
+   is embedded into another struct (possibly recursively).
+   __builtin_object_size will treat such struct as flexible size per
+   -fstrict-flex-arrays.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -fstrict-flex-arrays=3" } */
+
+#include <stdio.h>
+
+unsigned n_fails = 0;
+
+#define expect(p, _v) do { \
+  size_t v = _v; \
+  if (p == v) \
+    printf("ok:  %s == %zd\n", #p, p); \
+  else {\
+    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+    n_fails++; \
+  } \
+} while (0);
+
+struct A {
+  int n;
+  char data[];/* Content following header */
+};
+
+struct B {
+  int m;
+  struct A a;
+};
+
+struct C {
+  int q;
+  struct B b;
+};
+
+struct A0 {
+  int n;
+  char data[0];/* Content following header */
+};
+
+struct B0 {
+  int m;
+  struct A0 a;
+};
+
+struct C0 {
+  int q;
+  struct B0 b;
+};
+
+struct A1 {
+  int n;
+  char data[1];/* Content following header */
+};
+
+struct B1 {
+  int m;
+  struct A1 a;
+};
+
+struct C1 {
+  int q;
+  struct B1 b;
+};
+
+struct An {
+  int n;
+  char data[8];/* Content following header */
+};
+
+struct Bn {
+  int m;
+  struct An a;
+};
+
+struct Cn {
+  int q;
+  struct Bn b;
+};
+
+volatile void *magic1, *magic2;
+
+int main(int argc, char *argv[])
+{
+    struct B *outer;
+    struct C *outest;
+
+    /* Make sure optimization can't find some other object size. */
+    outer = (void *)magic1;
+    outest = (void *)magic2;
+
+    expect(__builtin_object_size(&outer->a, 1), -1);
+    expect(__builtin_object_size(&outest->b, 1), -1);
+    expect(__builtin_object_size(&outest->b.a, 1), -1);
+
+    struct B0 *outer0;
+    struct C0 *outest0;
+
+    /* Make sure optimization can't find some other object size. */
+    outer0 = (void *)magic1;
+    outest0 = (void *)magic2;
+
+    expect(__builtin_object_size(&outer0->a, 1), sizeof(outer0->a));
+    expect(__builtin_object_size(&outest0->b, 1), sizeof(outest0->b));
+    expect(__builtin_object_size(&outest0->b.a, 1), sizeof(outest0->b.a));
+
+    struct B1 *outer1;
+    struct C1 *outest1;
+
+    /* Make sure optimization can't find some other object size. */
+    outer1 = (void *)magic1;
+    outest1 = (void *)magic2;
+
+    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
+    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
+    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
+
+    struct Bn *outern;
+    struct Cn *outestn;
+
+    /* Make sure optimization can't find some other object size. */
+    outern = (void *)magic1;
+    outestn = (void *)magic2;
+
+    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
+    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
+    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
+
+    if (n_fails > 0)
+      __builtin_abort ();
+
+    return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
new file mode 100644
index 00000000000..8ed6980edf0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
@@ -0,0 +1,119 @@
+/* PR 101832: 
+   GCC extension accepts the case when a struct with a flexible array member
+   is embedded into another struct (possibly recursively).
+   __builtin_object_size will treat such struct as flexible size per
+   -fstrict-flex-arrays.  */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#include <stdio.h>
+
+unsigned n_fails = 0;
+
+#define expect(p, _v) do { \
+  size_t v = _v; \
+  if (p == v) \
+    printf("ok:  %s == %zd\n", #p, p); \
+  else {\
+    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
+    n_fails++; \
+  } \
+} while (0);
+
+struct A {
+  int n;
+  char data[];/* Content following header */
+};
+
+struct B {
+  int m;
+  struct A a;
+};
+
+struct C {
+  int q;
+  struct B b;
+};
+
+struct A0 {
+  int n;
+  char data[0];/* Content following header */
+};
+
+struct B0 {
+  int m;
+  struct A0 a;
+};
+
+struct C0 {
+  int q;
+  struct B0 b;
+};
+
+struct A1 {
+  int n;
+  char data[1];/* Content following header */
+};
+
+struct B1 {
+  int m;
+  struct A1 a;
+};
+
+struct C1 {
+  int q;
+  struct B1 b;
+};
+
+struct An {
+  int n;
+  char data[8];/* Content following header */
+};
+
+struct Bn {
+  int m;
+  struct An a;
+};
+
+struct Cn {
+  int q;
+  struct Bn b;
+};
+
+volatile void *magic1, *magic2;
+
+int main(int argc, char *argv[])
+{
+    struct B *outer = (void *)magic1;
+    struct C *outest = (void *)magic2;
+
+    expect(__builtin_object_size(&outer->a, 1), -1);
+    expect(__builtin_object_size(&outest->b, 1), -1);
+    expect(__builtin_object_size(&outest->b.a, 1), -1);
+
+    struct B0 *outer0 = (void *)magic1;
+    struct C0 *outest0 = (void *)magic2;
+
+    expect(__builtin_object_size(&outer0->a, 1), -1);
+    expect(__builtin_object_size(&outest0->b, 1), -1);
+    expect(__builtin_object_size(&outest0->b.a, 1), -1);
+
+    struct B1 *outer1 = (void *)magic1;
+    struct C1 *outest1 = (void *)magic2;
+
+    expect(__builtin_object_size(&outer1->a, 1), -1);
+    expect(__builtin_object_size(&outest1->b, 1), -1);
+    expect(__builtin_object_size(&outest1->b.a, 1), -1);
+
+    struct Bn *outern = (void *)magic1;
+    struct Cn *outestn = (void *)magic2;
+
+    expect(__builtin_object_size(&outern->a, 1), -1);
+    expect(__builtin_object_size(&outestn->b, 1), -1);
+    expect(__builtin_object_size(&outestn->b.a, 1), -1);
+
+    if (n_fails > 0)
+      __builtin_abort ();
+
+    return 0;
+}
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index 9a936a91983..56b78ca2a8c 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -500,6 +500,42 @@ decl_init_size (tree decl, bool min)
   return size;
 }
 
+/* Determine whether TYPE is a structure with a flexible array member
+   per -fstrict-flex-array or a union containing such a structure
+   (possibly recursively).  */
+static bool
+flexible_size_type_p (const_tree type)
+{
+  tree x = NULL_TREE;
+  tree last = NULL_TREE;
+  switch (TREE_CODE (type))
+    {
+    case RECORD_TYPE:
+      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
+	if (TREE_CODE (x) == FIELD_DECL)
+	  last = x;
+      if (last == NULL_TREE)
+	return false;
+      if (TREE_CODE (TREE_TYPE (last)) == ARRAY_TYPE
+	  && !DECL_NOT_FLEXARRAY (last))
+	return true;
+      else if (TREE_CODE (TREE_TYPE (last)) == RECORD_TYPE
+	       || TREE_CODE (TREE_TYPE (last)) == UNION_TYPE)
+	return flexible_size_type_p (TREE_TYPE (last));
+      return false;
+    case UNION_TYPE:
+      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
+	{
+	  if (TREE_CODE (x) == FIELD_DECL
+	      && flexible_array_type_p (TREE_TYPE (x)))
+	    return true;
+	}
+      return false;
+    default:
+      return false;
+  }
+}
+
 /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
    OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
    If unknown, return size_unknown (object_size_type).  */
@@ -633,45 +669,68 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
 		    v = NULL_TREE;
 		    break;
 		  case COMPONENT_REF:
-		    if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
+		    /* When the ref is not to an array, a record or a union, it
+		       will not have flexible size, compute the object size
+		       directly.  */
+		    if ((TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
+			&& (TREE_CODE (TREE_TYPE (v)) != RECORD_TYPE)
+			&& (TREE_CODE (TREE_TYPE (v)) != UNION_TYPE))
 		      {
 			v = NULL_TREE;
 			break;
 		      }
-		    is_flexible_array_mem_ref = array_ref_flexible_size_p (v);
-		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
-		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
-			  != UNION_TYPE
-			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
-			  != QUAL_UNION_TYPE)
-			break;
-		      else
-			v = TREE_OPERAND (v, 0);
-		    if (TREE_CODE (v) == COMPONENT_REF
-			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
-			   == RECORD_TYPE)
+		    /* if the record or union does not have flexible size
+		       compute the object size directly.  */
+		    if (TREE_CODE (TREE_TYPE (v)) == RECORD_TYPE
+			|| TREE_CODE (TREE_TYPE (v)) == UNION_TYPE)
 		      {
-			/* compute object size only if v is not a
-			   flexible array member.  */
-			if (!is_flexible_array_mem_ref)
+			if (!flexible_size_type_p (TREE_TYPE (v)))
 			  {
 			    v = NULL_TREE;
 			    break;
 			  }
-			v = TREE_OPERAND (v, 0);
+			else
+			  v = TREE_OPERAND (v, 0);
 		      }
-		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
-		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
-			  != UNION_TYPE
-			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
-			  != QUAL_UNION_TYPE)
-			break;
-		      else
-			v = TREE_OPERAND (v, 0);
-		    if (v != pt_var)
-		      v = NULL_TREE;
 		    else
-		      v = pt_var;
+		      {
+			/* Now the ref is to an array type.  */
+			is_flexible_array_mem_ref
+			  = array_ref_flexible_size_p (v);
+			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
+			if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+			      != UNION_TYPE
+			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+				 != QUAL_UNION_TYPE)
+			  break;
+			else
+			  v = TREE_OPERAND (v, 0);
+			if (TREE_CODE (v) == COMPONENT_REF
+			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+				 == RECORD_TYPE)
+			  {
+			    /* compute object size only if v is not a
+			       flexible array member.  */
+			    if (!is_flexible_array_mem_ref)
+			      {
+				v = NULL_TREE;
+				break;
+			      }
+			    v = TREE_OPERAND (v, 0);
+			  }
+			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
+			  if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+				!= UNION_TYPE
+			      && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+				   != QUAL_UNION_TYPE)
+			    break;
+			  else
+			    v = TREE_OPERAND (v, 0);
+			if (v != pt_var)
+			  v = NULL_TREE;
+			else
+			  v = pt_var;
+		      }
 		    break;
 		  default:
 		    v = pt_var;
-- 
2.31.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH 2/2] Documentation Update.
  2023-01-31 14:11 [PATCH 0/2]PR101832: Handle component_ref to a structure/union field including flexible array member for builtin_object_size Qing Zhao
  2023-01-31 14:11 ` [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832] Qing Zhao
@ 2023-01-31 14:11 ` Qing Zhao
  2023-02-01 16:55   ` Siddhesh Poyarekar
  1 sibling, 1 reply; 45+ messages in thread
From: Qing Zhao @ 2023-01-31 14:11 UTC (permalink / raw)
  To: rguenther; +Cc: gcc-patches, siddhesh, keescook, Qing Zhao

Update documentation to clarify a GCC extension on structure with
flexible array member being nested in another structure.

gcc/ChangeLog:

	* doc/extend.texi: Document GCC extension on a structure containing
	a flexible array member to be a member of another structure.
---
 gcc/doc/extend.texi | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 4a89a3eae7c..54e4baf49a9 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -1748,7 +1748,40 @@ Flexible array members may only appear as the last member of a
 A structure containing a flexible array member, or a union containing
 such a structure (possibly recursively), may not be a member of a
 structure or an element of an array.  (However, these uses are
-permitted by GCC as extensions.)
+permitted by GCC as extensions, see details below.)
+@end itemize
+
+GCC extension accepts a structure containing a flexible array member, or
+a union containing such a structure (possibly recursively) to be a member
+of a structure.
+
+There are two situations:
+
+@itemize @bullet
+@item
+The structure with a flexible array member is the last field of another
+structure, for example:
+
+@smallexample
+struct flex  @{ int length; char data[]; @};
+
+struct out_flex @{ int m; struct flex flex_data; @};
+@end smallexample
+
+In the above, @code{flex_data.data[]} is considered as a flexible array too.
+
+@item
+The structure with a flexible array member is the middle field of another
+structure, for example:
+
+@smallexample
+struct flex  @{ int length; char data[]; @};
+
+struct mid_flex @{ int m; struct flex flex_data; int n; @};
+@end smallexample
+
+In the above, @code{flex_data.data[]} is allowed to be extended flexibly to
+the padding. E.g, up to 4 elements.
 @end itemize
 
 Non-empty initialization of zero-length
-- 
2.31.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-01-31 14:11 ` [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832] Qing Zhao
@ 2023-02-01 11:41   ` Richard Biener
  2023-02-01 14:19     ` Qing Zhao
  2023-02-01 16:48   ` Siddhesh Poyarekar
  1 sibling, 1 reply; 45+ messages in thread
From: Richard Biener @ 2023-02-01 11:41 UTC (permalink / raw)
  To: Qing Zhao; +Cc: gcc-patches, siddhesh, keescook

On Tue, 31 Jan 2023, Qing Zhao wrote:

> GCC extension accepts the case when a struct with a flexible array member
> is embedded into another struct (possibly recursively).
> __builtin_object_size should treat such struct as flexible size per
> -fstrict-flex-arrays.
> 
> 	PR tree-optimization/101832
> 
> gcc/ChangeLog:
> 
> 	PR tree-optimization/101832
> 	* tree-object-size.cc (flexible_size_type_p): New function.
> 	(addr_object_size): Handle structure/union type when it has
> 	flexible size.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR tree-optimization/101832
> 	* gcc.dg/builtin-object-size-pr101832-2.c: New test.
> 	* gcc.dg/builtin-object-size-pr101832-3.c: New test.
> 	* gcc.dg/builtin-object-size-pr101832-4.c: New test.
> 	* gcc.dg/builtin-object-size-pr101832.c: New test.
> ---
>  .../gcc.dg/builtin-object-size-pr101832-2.c   | 135 ++++++++++++++++++
>  .../gcc.dg/builtin-object-size-pr101832-3.c   | 135 ++++++++++++++++++
>  .../gcc.dg/builtin-object-size-pr101832-4.c   | 135 ++++++++++++++++++
>  .../gcc.dg/builtin-object-size-pr101832.c     | 119 +++++++++++++++
>  gcc/tree-object-size.cc                       | 115 +++++++++++----
>  5 files changed, 611 insertions(+), 28 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
>  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
>  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
>  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
> 
> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
> new file mode 100644
> index 00000000000..f38babc5415
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
> @@ -0,0 +1,135 @@
> +/* PR 101832: 
> +   GCC extension accepts the case when a struct with a flexible array member
> +   is embedded into another struct (possibly recursively).
> +   __builtin_object_size will treat such struct as flexible size per
> +   -fstrict-flex-arrays.  */ 
> +/* { dg-do run } */
> +/* { dg-options "-O2 -fstrict-flex-arrays=1" } */
> +
> +#include <stdio.h>
> +
> +unsigned n_fails = 0;
> +
> +#define expect(p, _v) do { \
> +  size_t v = _v; \
> +  if (p == v) \
> +    printf("ok:  %s == %zd\n", #p, p); \
> +  else {\
> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> +    n_fails++; \
> +  } \
> +} while (0);
> +
> +struct A {
> +  int n;
> +  char data[];/* Content following header */
> +};
> +
> +struct B {
> +  int m;
> +  struct A a;
> +};
> +
> +struct C {
> +  int q;
> +  struct B b;
> +};
> +
> +struct A0 {
> +  int n;
> +  char data[0];/* Content following header */
> +};
> +
> +struct B0 {
> +  int m;
> +  struct A0 a;
> +};
> +
> +struct C0 {
> +  int q;
> +  struct B0 b;
> +};
> +
> +struct A1 {
> +  int n;
> +  char data[1];/* Content following header */
> +};
> +
> +struct B1 {
> +  int m;
> +  struct A1 a;
> +};
> +
> +struct C1 {
> +  int q;
> +  struct B1 b;
> +};
> +
> +struct An {
> +  int n;
> +  char data[8];/* Content following header */
> +};
> +
> +struct Bn {
> +  int m;
> +  struct An a;
> +};
> +
> +struct Cn {
> +  int q;
> +  struct Bn b;
> +};
> +
> +volatile void *magic1, *magic2;
> +
> +int main(int argc, char *argv[])
> +{
> +    struct B *outer;
> +    struct C *outest;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer = (void *)magic1;
> +    outest = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer->a, 1), -1);
> +    expect(__builtin_object_size(&outest->b, 1), -1);
> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
> +
> +    struct B0 *outer0;
> +    struct C0 *outest0;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer0 = (void *)magic1;
> +    outest0 = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer0->a, 1), -1);
> +    expect(__builtin_object_size(&outest0->b, 1), -1);
> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
> +
> +    struct B1 *outer1;
> +    struct C1 *outest1;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer1 = (void *)magic1;
> +    outest1 = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer1->a, 1), -1);
> +    expect(__builtin_object_size(&outest1->b, 1), -1);
> +    expect(__builtin_object_size(&outest1->b.a, 1), -1);
> +
> +    struct Bn *outern;
> +    struct Cn *outestn;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outern = (void *)magic1;
> +    outestn = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
> +
> +    if (n_fails > 0)
> +      __builtin_abort ();
> +
> +    return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
> new file mode 100644
> index 00000000000..aaae99b8d67
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
> @@ -0,0 +1,135 @@
> +/* PR 101832: 
> +   GCC extension accepts the case when a struct with a flexible array member
> +   is embedded into another struct (possibly recursively).
> +   __builtin_object_size will treat such struct as flexible size per
> +   -fstrict-flex-arrays.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -fstrict-flex-arrays=2" } */
> +
> +#include <stdio.h>
> +
> +unsigned n_fails = 0;
> +
> +#define expect(p, _v) do { \
> +  size_t v = _v; \
> +  if (p == v) \
> +    printf("ok:  %s == %zd\n", #p, p); \
> +  else {\
> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> +    n_fails++; \
> +  } \
> +} while (0);
> +
> +struct A {
> +  int n;
> +  char data[];/* Content following header */
> +};
> +
> +struct B {
> +  int m;
> +  struct A a;
> +};
> +
> +struct C {
> +  int q;
> +  struct B b;
> +};
> +
> +struct A0 {
> +  int n;
> +  char data[0];/* Content following header */
> +};
> +
> +struct B0 {
> +  int m;
> +  struct A0 a;
> +};
> +
> +struct C0 {
> +  int q;
> +  struct B0 b;
> +};
> +
> +struct A1 {
> +  int n;
> +  char data[1];/* Content following header */
> +};
> +
> +struct B1 {
> +  int m;
> +  struct A1 a;
> +};
> +
> +struct C1 {
> +  int q;
> +  struct B1 b;
> +};
> +
> +struct An {
> +  int n;
> +  char data[8];/* Content following header */
> +};
> +
> +struct Bn {
> +  int m;
> +  struct An a;
> +};
> +
> +struct Cn {
> +  int q;
> +  struct Bn b;
> +};
> +
> +volatile void *magic1, *magic2;
> +
> +int main(int argc, char *argv[])
> +{
> +    struct B *outer;
> +    struct C *outest;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer = (void *)magic1;
> +    outest = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer->a, 1), -1);
> +    expect(__builtin_object_size(&outest->b, 1), -1);
> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
> +
> +    struct B0 *outer0;
> +    struct C0 *outest0;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer0 = (void *)magic1;
> +    outest0 = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer0->a, 1), -1);
> +    expect(__builtin_object_size(&outest0->b, 1), -1);
> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
> +
> +    struct B1 *outer1;
> +    struct C1 *outest1;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer1 = (void *)magic1;
> +    outest1 = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
> +    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
> +    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
> +
> +    struct Bn *outern;
> +    struct Cn *outestn;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outern = (void *)magic1;
> +    outestn = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
> +
> +    if (n_fails > 0)
> +      __builtin_abort ();
> +
> +    return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
> new file mode 100644
> index 00000000000..424264e2acd
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
> @@ -0,0 +1,135 @@
> +/* PR 101832: 
> +   GCC extension accepts the case when a struct with a flexible array member
> +   is embedded into another struct (possibly recursively).
> +   __builtin_object_size will treat such struct as flexible size per
> +   -fstrict-flex-arrays.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -fstrict-flex-arrays=3" } */
> +
> +#include <stdio.h>
> +
> +unsigned n_fails = 0;
> +
> +#define expect(p, _v) do { \
> +  size_t v = _v; \
> +  if (p == v) \
> +    printf("ok:  %s == %zd\n", #p, p); \
> +  else {\
> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> +    n_fails++; \
> +  } \
> +} while (0);
> +
> +struct A {
> +  int n;
> +  char data[];/* Content following header */
> +};
> +
> +struct B {
> +  int m;
> +  struct A a;
> +};
> +
> +struct C {
> +  int q;
> +  struct B b;
> +};
> +
> +struct A0 {
> +  int n;
> +  char data[0];/* Content following header */
> +};
> +
> +struct B0 {
> +  int m;
> +  struct A0 a;
> +};
> +
> +struct C0 {
> +  int q;
> +  struct B0 b;
> +};
> +
> +struct A1 {
> +  int n;
> +  char data[1];/* Content following header */
> +};
> +
> +struct B1 {
> +  int m;
> +  struct A1 a;
> +};
> +
> +struct C1 {
> +  int q;
> +  struct B1 b;
> +};
> +
> +struct An {
> +  int n;
> +  char data[8];/* Content following header */
> +};
> +
> +struct Bn {
> +  int m;
> +  struct An a;
> +};
> +
> +struct Cn {
> +  int q;
> +  struct Bn b;
> +};
> +
> +volatile void *magic1, *magic2;
> +
> +int main(int argc, char *argv[])
> +{
> +    struct B *outer;
> +    struct C *outest;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer = (void *)magic1;
> +    outest = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer->a, 1), -1);
> +    expect(__builtin_object_size(&outest->b, 1), -1);
> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
> +
> +    struct B0 *outer0;
> +    struct C0 *outest0;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer0 = (void *)magic1;
> +    outest0 = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer0->a, 1), sizeof(outer0->a));
> +    expect(__builtin_object_size(&outest0->b, 1), sizeof(outest0->b));
> +    expect(__builtin_object_size(&outest0->b.a, 1), sizeof(outest0->b.a));
> +
> +    struct B1 *outer1;
> +    struct C1 *outest1;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer1 = (void *)magic1;
> +    outest1 = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
> +    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
> +    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
> +
> +    struct Bn *outern;
> +    struct Cn *outestn;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outern = (void *)magic1;
> +    outestn = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
> +
> +    if (n_fails > 0)
> +      __builtin_abort ();
> +
> +    return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
> new file mode 100644
> index 00000000000..8ed6980edf0
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
> @@ -0,0 +1,119 @@
> +/* PR 101832: 
> +   GCC extension accepts the case when a struct with a flexible array member
> +   is embedded into another struct (possibly recursively).
> +   __builtin_object_size will treat such struct as flexible size per
> +   -fstrict-flex-arrays.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2" } */
> +
> +#include <stdio.h>
> +
> +unsigned n_fails = 0;
> +
> +#define expect(p, _v) do { \
> +  size_t v = _v; \
> +  if (p == v) \
> +    printf("ok:  %s == %zd\n", #p, p); \
> +  else {\
> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> +    n_fails++; \
> +  } \
> +} while (0);
> +
> +struct A {
> +  int n;
> +  char data[];/* Content following header */
> +};
> +
> +struct B {
> +  int m;
> +  struct A a;
> +};
> +
> +struct C {
> +  int q;
> +  struct B b;
> +};
> +
> +struct A0 {
> +  int n;
> +  char data[0];/* Content following header */
> +};
> +
> +struct B0 {
> +  int m;
> +  struct A0 a;
> +};
> +
> +struct C0 {
> +  int q;
> +  struct B0 b;
> +};
> +
> +struct A1 {
> +  int n;
> +  char data[1];/* Content following header */
> +};
> +
> +struct B1 {
> +  int m;
> +  struct A1 a;
> +};
> +
> +struct C1 {
> +  int q;
> +  struct B1 b;
> +};
> +
> +struct An {
> +  int n;
> +  char data[8];/* Content following header */
> +};
> +
> +struct Bn {
> +  int m;
> +  struct An a;
> +};
> +
> +struct Cn {
> +  int q;
> +  struct Bn b;
> +};
> +
> +volatile void *magic1, *magic2;
> +
> +int main(int argc, char *argv[])
> +{
> +    struct B *outer = (void *)magic1;
> +    struct C *outest = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer->a, 1), -1);
> +    expect(__builtin_object_size(&outest->b, 1), -1);
> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
> +
> +    struct B0 *outer0 = (void *)magic1;
> +    struct C0 *outest0 = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer0->a, 1), -1);
> +    expect(__builtin_object_size(&outest0->b, 1), -1);
> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
> +
> +    struct B1 *outer1 = (void *)magic1;
> +    struct C1 *outest1 = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer1->a, 1), -1);
> +    expect(__builtin_object_size(&outest1->b, 1), -1);
> +    expect(__builtin_object_size(&outest1->b.a, 1), -1);
> +
> +    struct Bn *outern = (void *)magic1;
> +    struct Cn *outestn = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outern->a, 1), -1);
> +    expect(__builtin_object_size(&outestn->b, 1), -1);
> +    expect(__builtin_object_size(&outestn->b.a, 1), -1);
> +
> +    if (n_fails > 0)
> +      __builtin_abort ();
> +
> +    return 0;
> +}
> diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
> index 9a936a91983..56b78ca2a8c 100644
> --- a/gcc/tree-object-size.cc
> +++ b/gcc/tree-object-size.cc
> @@ -500,6 +500,42 @@ decl_init_size (tree decl, bool min)
>    return size;
>  }
>  
> +/* Determine whether TYPE is a structure with a flexible array member
> +   per -fstrict-flex-array or a union containing such a structure
> +   (possibly recursively).  */
> +static bool
> +flexible_size_type_p (const_tree type)
> +{
> +  tree x = NULL_TREE;
> +  tree last = NULL_TREE;
> +  switch (TREE_CODE (type))
> +    {
> +    case RECORD_TYPE:
> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
> +	if (TREE_CODE (x) == FIELD_DECL)
> +	  last = x;
> +      if (last == NULL_TREE)
> +	return false;
> +      if (TREE_CODE (TREE_TYPE (last)) == ARRAY_TYPE
> +	  && !DECL_NOT_FLEXARRAY (last))
> +	return true;
> +      else if (TREE_CODE (TREE_TYPE (last)) == RECORD_TYPE
> +	       || TREE_CODE (TREE_TYPE (last)) == UNION_TYPE)
> +	return flexible_size_type_p (TREE_TYPE (last));

For types with many members this can become quite slow (IIRC we had
bugs about similar walks of all fields in types), and this function
looks like it's invoked multiple times on the same type per TU.

In principle the property is fixed at the time we lay out a record
type, so we might want to compute it at that time and record the
result.

> +      return false;
> +    case UNION_TYPE:
> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
> +	{
> +	  if (TREE_CODE (x) == FIELD_DECL
> +	      && flexible_array_type_p (TREE_TYPE (x)))
> +	    return true;
> +	}
> +      return false;
> +    default:
> +      return false;
> +  }
> +}
> +
>  /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
>     OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
>     If unknown, return size_unknown (object_size_type).  */
> @@ -633,45 +669,68 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
>  		    v = NULL_TREE;
>  		    break;
>  		  case COMPONENT_REF:
> -		    if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
> +		    /* When the ref is not to an array, a record or a union, it
> +		       will not have flexible size, compute the object size
> +		       directly.  */
> +		    if ((TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
> +			&& (TREE_CODE (TREE_TYPE (v)) != RECORD_TYPE)
> +			&& (TREE_CODE (TREE_TYPE (v)) != UNION_TYPE))
>  		      {
>  			v = NULL_TREE;
>  			break;
>  		      }
> -		    is_flexible_array_mem_ref = array_ref_flexible_size_p (v);
> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> -			  != UNION_TYPE
> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> -			  != QUAL_UNION_TYPE)
> -			break;
> -		      else
> -			v = TREE_OPERAND (v, 0);
> -		    if (TREE_CODE (v) == COMPONENT_REF
> -			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> -			   == RECORD_TYPE)
> +		    /* if the record or union does not have flexible size
> +		       compute the object size directly.  */
> +		    if (TREE_CODE (TREE_TYPE (v)) == RECORD_TYPE
> +			|| TREE_CODE (TREE_TYPE (v)) == UNION_TYPE)
>  		      {
> -			/* compute object size only if v is not a
> -			   flexible array member.  */
> -			if (!is_flexible_array_mem_ref)
> +			if (!flexible_size_type_p (TREE_TYPE (v)))
>  			  {
>  			    v = NULL_TREE;
>  			    break;
>  			  }
> -			v = TREE_OPERAND (v, 0);
> +			else
> +			  v = TREE_OPERAND (v, 0);
>  		      }
> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> -			  != UNION_TYPE
> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> -			  != QUAL_UNION_TYPE)
> -			break;
> -		      else
> -			v = TREE_OPERAND (v, 0);
> -		    if (v != pt_var)
> -		      v = NULL_TREE;
>  		    else
> -		      v = pt_var;
> +		      {
> +			/* Now the ref is to an array type.  */
> +			is_flexible_array_mem_ref
> +			  = array_ref_flexible_size_p (v);
> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> +			if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> +			      != UNION_TYPE
> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> +				 != QUAL_UNION_TYPE)
> +			  break;
> +			else
> +			  v = TREE_OPERAND (v, 0);
> +			if (TREE_CODE (v) == COMPONENT_REF
> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> +				 == RECORD_TYPE)
> +			  {
> +			    /* compute object size only if v is not a
> +			       flexible array member.  */
> +			    if (!is_flexible_array_mem_ref)
> +			      {
> +				v = NULL_TREE;
> +				break;
> +			      }
> +			    v = TREE_OPERAND (v, 0);
> +			  }
> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> +			  if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> +				!= UNION_TYPE
> +			      && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> +				   != QUAL_UNION_TYPE)
> +			    break;
> +			  else
> +			    v = TREE_OPERAND (v, 0);
> +			if (v != pt_var)
> +			  v = NULL_TREE;
> +			else
> +			  v = pt_var;
> +		      }
>  		    break;
>  		  default:
>  		    v = pt_var;
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
HRB 36809 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-01 11:41   ` Richard Biener
@ 2023-02-01 14:19     ` Qing Zhao
  2023-02-02  8:07       ` Richard Biener
  0 siblings, 1 reply; 45+ messages in thread
From: Qing Zhao @ 2023-02-01 14:19 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches, siddhesh, keescook



> On Feb 1, 2023, at 6:41 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Tue, 31 Jan 2023, Qing Zhao wrote:
> 
>> GCC extension accepts the case when a struct with a flexible array member
>> is embedded into another struct (possibly recursively).
>> __builtin_object_size should treat such struct as flexible size per
>> -fstrict-flex-arrays.
>> 
>> 	PR tree-optimization/101832
>> 
>> gcc/ChangeLog:
>> 
>> 	PR tree-optimization/101832
>> 	* tree-object-size.cc (flexible_size_type_p): New function.
>> 	(addr_object_size): Handle structure/union type when it has
>> 	flexible size.
>> 
>> gcc/testsuite/ChangeLog:
>> 
>> 	PR tree-optimization/101832
>> 	* gcc.dg/builtin-object-size-pr101832-2.c: New test.
>> 	* gcc.dg/builtin-object-size-pr101832-3.c: New test.
>> 	* gcc.dg/builtin-object-size-pr101832-4.c: New test.
>> 	* gcc.dg/builtin-object-size-pr101832.c: New test.
>> ---
>> .../gcc.dg/builtin-object-size-pr101832-2.c   | 135 ++++++++++++++++++
>> .../gcc.dg/builtin-object-size-pr101832-3.c   | 135 ++++++++++++++++++
>> .../gcc.dg/builtin-object-size-pr101832-4.c   | 135 ++++++++++++++++++
>> .../gcc.dg/builtin-object-size-pr101832.c     | 119 +++++++++++++++
>> gcc/tree-object-size.cc                       | 115 +++++++++++----
>> 5 files changed, 611 insertions(+), 28 deletions(-)
>> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
>> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
>> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
>> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
>> 
>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
>> new file mode 100644
>> index 00000000000..f38babc5415
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
>> @@ -0,0 +1,135 @@
>> +/* PR 101832: 
>> +   GCC extension accepts the case when a struct with a flexible array member
>> +   is embedded into another struct (possibly recursively).
>> +   __builtin_object_size will treat such struct as flexible size per
>> +   -fstrict-flex-arrays.  */ 
>> +/* { dg-do run } */
>> +/* { dg-options "-O2 -fstrict-flex-arrays=1" } */
>> +
>> +#include <stdio.h>
>> +
>> +unsigned n_fails = 0;
>> +
>> +#define expect(p, _v) do { \
>> +  size_t v = _v; \
>> +  if (p == v) \
>> +    printf("ok:  %s == %zd\n", #p, p); \
>> +  else {\
>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
>> +    n_fails++; \
>> +  } \
>> +} while (0);
>> +
>> +struct A {
>> +  int n;
>> +  char data[];/* Content following header */
>> +};
>> +
>> +struct B {
>> +  int m;
>> +  struct A a;
>> +};
>> +
>> +struct C {
>> +  int q;
>> +  struct B b;
>> +};
>> +
>> +struct A0 {
>> +  int n;
>> +  char data[0];/* Content following header */
>> +};
>> +
>> +struct B0 {
>> +  int m;
>> +  struct A0 a;
>> +};
>> +
>> +struct C0 {
>> +  int q;
>> +  struct B0 b;
>> +};
>> +
>> +struct A1 {
>> +  int n;
>> +  char data[1];/* Content following header */
>> +};
>> +
>> +struct B1 {
>> +  int m;
>> +  struct A1 a;
>> +};
>> +
>> +struct C1 {
>> +  int q;
>> +  struct B1 b;
>> +};
>> +
>> +struct An {
>> +  int n;
>> +  char data[8];/* Content following header */
>> +};
>> +
>> +struct Bn {
>> +  int m;
>> +  struct An a;
>> +};
>> +
>> +struct Cn {
>> +  int q;
>> +  struct Bn b;
>> +};
>> +
>> +volatile void *magic1, *magic2;
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    struct B *outer;
>> +    struct C *outest;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer = (void *)magic1;
>> +    outest = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer->a, 1), -1);
>> +    expect(__builtin_object_size(&outest->b, 1), -1);
>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
>> +
>> +    struct B0 *outer0;
>> +    struct C0 *outest0;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer0 = (void *)magic1;
>> +    outest0 = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer0->a, 1), -1);
>> +    expect(__builtin_object_size(&outest0->b, 1), -1);
>> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
>> +
>> +    struct B1 *outer1;
>> +    struct C1 *outest1;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer1 = (void *)magic1;
>> +    outest1 = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer1->a, 1), -1);
>> +    expect(__builtin_object_size(&outest1->b, 1), -1);
>> +    expect(__builtin_object_size(&outest1->b.a, 1), -1);
>> +
>> +    struct Bn *outern;
>> +    struct Cn *outestn;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outern = (void *)magic1;
>> +    outestn = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
>> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
>> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
>> +
>> +    if (n_fails > 0)
>> +      __builtin_abort ();
>> +
>> +    return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
>> new file mode 100644
>> index 00000000000..aaae99b8d67
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
>> @@ -0,0 +1,135 @@
>> +/* PR 101832: 
>> +   GCC extension accepts the case when a struct with a flexible array member
>> +   is embedded into another struct (possibly recursively).
>> +   __builtin_object_size will treat such struct as flexible size per
>> +   -fstrict-flex-arrays.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2 -fstrict-flex-arrays=2" } */
>> +
>> +#include <stdio.h>
>> +
>> +unsigned n_fails = 0;
>> +
>> +#define expect(p, _v) do { \
>> +  size_t v = _v; \
>> +  if (p == v) \
>> +    printf("ok:  %s == %zd\n", #p, p); \
>> +  else {\
>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
>> +    n_fails++; \
>> +  } \
>> +} while (0);
>> +
>> +struct A {
>> +  int n;
>> +  char data[];/* Content following header */
>> +};
>> +
>> +struct B {
>> +  int m;
>> +  struct A a;
>> +};
>> +
>> +struct C {
>> +  int q;
>> +  struct B b;
>> +};
>> +
>> +struct A0 {
>> +  int n;
>> +  char data[0];/* Content following header */
>> +};
>> +
>> +struct B0 {
>> +  int m;
>> +  struct A0 a;
>> +};
>> +
>> +struct C0 {
>> +  int q;
>> +  struct B0 b;
>> +};
>> +
>> +struct A1 {
>> +  int n;
>> +  char data[1];/* Content following header */
>> +};
>> +
>> +struct B1 {
>> +  int m;
>> +  struct A1 a;
>> +};
>> +
>> +struct C1 {
>> +  int q;
>> +  struct B1 b;
>> +};
>> +
>> +struct An {
>> +  int n;
>> +  char data[8];/* Content following header */
>> +};
>> +
>> +struct Bn {
>> +  int m;
>> +  struct An a;
>> +};
>> +
>> +struct Cn {
>> +  int q;
>> +  struct Bn b;
>> +};
>> +
>> +volatile void *magic1, *magic2;
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    struct B *outer;
>> +    struct C *outest;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer = (void *)magic1;
>> +    outest = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer->a, 1), -1);
>> +    expect(__builtin_object_size(&outest->b, 1), -1);
>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
>> +
>> +    struct B0 *outer0;
>> +    struct C0 *outest0;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer0 = (void *)magic1;
>> +    outest0 = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer0->a, 1), -1);
>> +    expect(__builtin_object_size(&outest0->b, 1), -1);
>> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
>> +
>> +    struct B1 *outer1;
>> +    struct C1 *outest1;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer1 = (void *)magic1;
>> +    outest1 = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
>> +    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
>> +    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
>> +
>> +    struct Bn *outern;
>> +    struct Cn *outestn;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outern = (void *)magic1;
>> +    outestn = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
>> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
>> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
>> +
>> +    if (n_fails > 0)
>> +      __builtin_abort ();
>> +
>> +    return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
>> new file mode 100644
>> index 00000000000..424264e2acd
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
>> @@ -0,0 +1,135 @@
>> +/* PR 101832: 
>> +   GCC extension accepts the case when a struct with a flexible array member
>> +   is embedded into another struct (possibly recursively).
>> +   __builtin_object_size will treat such struct as flexible size per
>> +   -fstrict-flex-arrays.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2 -fstrict-flex-arrays=3" } */
>> +
>> +#include <stdio.h>
>> +
>> +unsigned n_fails = 0;
>> +
>> +#define expect(p, _v) do { \
>> +  size_t v = _v; \
>> +  if (p == v) \
>> +    printf("ok:  %s == %zd\n", #p, p); \
>> +  else {\
>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
>> +    n_fails++; \
>> +  } \
>> +} while (0);
>> +
>> +struct A {
>> +  int n;
>> +  char data[];/* Content following header */
>> +};
>> +
>> +struct B {
>> +  int m;
>> +  struct A a;
>> +};
>> +
>> +struct C {
>> +  int q;
>> +  struct B b;
>> +};
>> +
>> +struct A0 {
>> +  int n;
>> +  char data[0];/* Content following header */
>> +};
>> +
>> +struct B0 {
>> +  int m;
>> +  struct A0 a;
>> +};
>> +
>> +struct C0 {
>> +  int q;
>> +  struct B0 b;
>> +};
>> +
>> +struct A1 {
>> +  int n;
>> +  char data[1];/* Content following header */
>> +};
>> +
>> +struct B1 {
>> +  int m;
>> +  struct A1 a;
>> +};
>> +
>> +struct C1 {
>> +  int q;
>> +  struct B1 b;
>> +};
>> +
>> +struct An {
>> +  int n;
>> +  char data[8];/* Content following header */
>> +};
>> +
>> +struct Bn {
>> +  int m;
>> +  struct An a;
>> +};
>> +
>> +struct Cn {
>> +  int q;
>> +  struct Bn b;
>> +};
>> +
>> +volatile void *magic1, *magic2;
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    struct B *outer;
>> +    struct C *outest;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer = (void *)magic1;
>> +    outest = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer->a, 1), -1);
>> +    expect(__builtin_object_size(&outest->b, 1), -1);
>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
>> +
>> +    struct B0 *outer0;
>> +    struct C0 *outest0;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer0 = (void *)magic1;
>> +    outest0 = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer0->a, 1), sizeof(outer0->a));
>> +    expect(__builtin_object_size(&outest0->b, 1), sizeof(outest0->b));
>> +    expect(__builtin_object_size(&outest0->b.a, 1), sizeof(outest0->b.a));
>> +
>> +    struct B1 *outer1;
>> +    struct C1 *outest1;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer1 = (void *)magic1;
>> +    outest1 = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
>> +    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
>> +    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
>> +
>> +    struct Bn *outern;
>> +    struct Cn *outestn;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outern = (void *)magic1;
>> +    outestn = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
>> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
>> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
>> +
>> +    if (n_fails > 0)
>> +      __builtin_abort ();
>> +
>> +    return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
>> new file mode 100644
>> index 00000000000..8ed6980edf0
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
>> @@ -0,0 +1,119 @@
>> +/* PR 101832: 
>> +   GCC extension accepts the case when a struct with a flexible array member
>> +   is embedded into another struct (possibly recursively).
>> +   __builtin_object_size will treat such struct as flexible size per
>> +   -fstrict-flex-arrays.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2" } */
>> +
>> +#include <stdio.h>
>> +
>> +unsigned n_fails = 0;
>> +
>> +#define expect(p, _v) do { \
>> +  size_t v = _v; \
>> +  if (p == v) \
>> +    printf("ok:  %s == %zd\n", #p, p); \
>> +  else {\
>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
>> +    n_fails++; \
>> +  } \
>> +} while (0);
>> +
>> +struct A {
>> +  int n;
>> +  char data[];/* Content following header */
>> +};
>> +
>> +struct B {
>> +  int m;
>> +  struct A a;
>> +};
>> +
>> +struct C {
>> +  int q;
>> +  struct B b;
>> +};
>> +
>> +struct A0 {
>> +  int n;
>> +  char data[0];/* Content following header */
>> +};
>> +
>> +struct B0 {
>> +  int m;
>> +  struct A0 a;
>> +};
>> +
>> +struct C0 {
>> +  int q;
>> +  struct B0 b;
>> +};
>> +
>> +struct A1 {
>> +  int n;
>> +  char data[1];/* Content following header */
>> +};
>> +
>> +struct B1 {
>> +  int m;
>> +  struct A1 a;
>> +};
>> +
>> +struct C1 {
>> +  int q;
>> +  struct B1 b;
>> +};
>> +
>> +struct An {
>> +  int n;
>> +  char data[8];/* Content following header */
>> +};
>> +
>> +struct Bn {
>> +  int m;
>> +  struct An a;
>> +};
>> +
>> +struct Cn {
>> +  int q;
>> +  struct Bn b;
>> +};
>> +
>> +volatile void *magic1, *magic2;
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    struct B *outer = (void *)magic1;
>> +    struct C *outest = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer->a, 1), -1);
>> +    expect(__builtin_object_size(&outest->b, 1), -1);
>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
>> +
>> +    struct B0 *outer0 = (void *)magic1;
>> +    struct C0 *outest0 = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer0->a, 1), -1);
>> +    expect(__builtin_object_size(&outest0->b, 1), -1);
>> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
>> +
>> +    struct B1 *outer1 = (void *)magic1;
>> +    struct C1 *outest1 = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer1->a, 1), -1);
>> +    expect(__builtin_object_size(&outest1->b, 1), -1);
>> +    expect(__builtin_object_size(&outest1->b.a, 1), -1);
>> +
>> +    struct Bn *outern = (void *)magic1;
>> +    struct Cn *outestn = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outern->a, 1), -1);
>> +    expect(__builtin_object_size(&outestn->b, 1), -1);
>> +    expect(__builtin_object_size(&outestn->b.a, 1), -1);
>> +
>> +    if (n_fails > 0)
>> +      __builtin_abort ();
>> +
>> +    return 0;
>> +}
>> diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
>> index 9a936a91983..56b78ca2a8c 100644
>> --- a/gcc/tree-object-size.cc
>> +++ b/gcc/tree-object-size.cc
>> @@ -500,6 +500,42 @@ decl_init_size (tree decl, bool min)
>>   return size;
>> }
>> 
>> +/* Determine whether TYPE is a structure with a flexible array member
>> +   per -fstrict-flex-array or a union containing such a structure
>> +   (possibly recursively).  */
>> +static bool
>> +flexible_size_type_p (const_tree type)
>> +{
>> +  tree x = NULL_TREE;
>> +  tree last = NULL_TREE;
>> +  switch (TREE_CODE (type))
>> +    {
>> +    case RECORD_TYPE:
>> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
>> +	if (TREE_CODE (x) == FIELD_DECL)
>> +	  last = x;
>> +      if (last == NULL_TREE)
>> +	return false;
>> +      if (TREE_CODE (TREE_TYPE (last)) == ARRAY_TYPE
>> +	  && !DECL_NOT_FLEXARRAY (last))
>> +	return true;
>> +      else if (TREE_CODE (TREE_TYPE (last)) == RECORD_TYPE
>> +	       || TREE_CODE (TREE_TYPE (last)) == UNION_TYPE)
>> +	return flexible_size_type_p (TREE_TYPE (last));
> 
> For types with many members this can become quite slow (IIRC we had
> bugs about similar walks of all fields in types), and this function
> looks like it's invoked multiple times on the same type per TU.
> 
> In principle the property is fixed at the time we lay out a record
> type, so we might want to compute it at that time and record the
> result.

You mean in FE? 

Yes, that’s better and cleaner. 

I will add one more field in the TYPE structure to record this information and check this field during middle end.

I had the same thought in the beginning, but not sure whether adding a new field in IR is necessary or not, other places in middle end might not use this new field. 

thanks.

Qing

> 
>> +      return false;
>> +    case UNION_TYPE:
>> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
>> +	{
>> +	  if (TREE_CODE (x) == FIELD_DECL
>> +	      && flexible_array_type_p (TREE_TYPE (x)))
>> +	    return true;
>> +	}
>> +      return false;
>> +    default:
>> +      return false;
>> +  }
>> +}
>> +
>> /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
>>    OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
>>    If unknown, return size_unknown (object_size_type).  */
>> @@ -633,45 +669,68 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
>> 		    v = NULL_TREE;
>> 		    break;
>> 		  case COMPONENT_REF:
>> -		    if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
>> +		    /* When the ref is not to an array, a record or a union, it
>> +		       will not have flexible size, compute the object size
>> +		       directly.  */
>> +		    if ((TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
>> +			&& (TREE_CODE (TREE_TYPE (v)) != RECORD_TYPE)
>> +			&& (TREE_CODE (TREE_TYPE (v)) != UNION_TYPE))
>> 		      {
>> 			v = NULL_TREE;
>> 			break;
>> 		      }
>> -		    is_flexible_array_mem_ref = array_ref_flexible_size_p (v);
>> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> -			  != UNION_TYPE
>> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> -			  != QUAL_UNION_TYPE)
>> -			break;
>> -		      else
>> -			v = TREE_OPERAND (v, 0);
>> -		    if (TREE_CODE (v) == COMPONENT_REF
>> -			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> -			   == RECORD_TYPE)
>> +		    /* if the record or union does not have flexible size
>> +		       compute the object size directly.  */
>> +		    if (TREE_CODE (TREE_TYPE (v)) == RECORD_TYPE
>> +			|| TREE_CODE (TREE_TYPE (v)) == UNION_TYPE)
>> 		      {
>> -			/* compute object size only if v is not a
>> -			   flexible array member.  */
>> -			if (!is_flexible_array_mem_ref)
>> +			if (!flexible_size_type_p (TREE_TYPE (v)))
>> 			  {
>> 			    v = NULL_TREE;
>> 			    break;
>> 			  }
>> -			v = TREE_OPERAND (v, 0);
>> +			else
>> +			  v = TREE_OPERAND (v, 0);
>> 		      }
>> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> -			  != UNION_TYPE
>> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> -			  != QUAL_UNION_TYPE)
>> -			break;
>> -		      else
>> -			v = TREE_OPERAND (v, 0);
>> -		    if (v != pt_var)
>> -		      v = NULL_TREE;
>> 		    else
>> -		      v = pt_var;
>> +		      {
>> +			/* Now the ref is to an array type.  */
>> +			is_flexible_array_mem_ref
>> +			  = array_ref_flexible_size_p (v);
>> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>> +			if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> +			      != UNION_TYPE
>> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> +				 != QUAL_UNION_TYPE)
>> +			  break;
>> +			else
>> +			  v = TREE_OPERAND (v, 0);
>> +			if (TREE_CODE (v) == COMPONENT_REF
>> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> +				 == RECORD_TYPE)
>> +			  {
>> +			    /* compute object size only if v is not a
>> +			       flexible array member.  */
>> +			    if (!is_flexible_array_mem_ref)
>> +			      {
>> +				v = NULL_TREE;
>> +				break;
>> +			      }
>> +			    v = TREE_OPERAND (v, 0);
>> +			  }
>> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>> +			  if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> +				!= UNION_TYPE
>> +			      && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> +				   != QUAL_UNION_TYPE)
>> +			    break;
>> +			  else
>> +			    v = TREE_OPERAND (v, 0);
>> +			if (v != pt_var)
>> +			  v = NULL_TREE;
>> +			else
>> +			  v = pt_var;
>> +		      }
>> 		    break;
>> 		  default:
>> 		    v = pt_var;
>> 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
> Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
> HRB 36809 (AG Nuernberg)


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-01-31 14:11 ` [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832] Qing Zhao
  2023-02-01 11:41   ` Richard Biener
@ 2023-02-01 16:48   ` Siddhesh Poyarekar
  2023-02-01 18:20     ` Qing Zhao
  1 sibling, 1 reply; 45+ messages in thread
From: Siddhesh Poyarekar @ 2023-02-01 16:48 UTC (permalink / raw)
  To: Qing Zhao, rguenther; +Cc: gcc-patches, keescook

On 2023-01-31 09:11, Qing Zhao wrote:
> GCC extension accepts the case when a struct with a flexible array member
> is embedded into another struct (possibly recursively).
> __builtin_object_size should treat such struct as flexible size per
> -fstrict-flex-arrays.
> 
> 	PR tree-optimization/101832
> 
> gcc/ChangeLog:
> 
> 	PR tree-optimization/101832
> 	* tree-object-size.cc (flexible_size_type_p): New function.
> 	(addr_object_size): Handle structure/union type when it has
> 	flexible size.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR tree-optimization/101832
> 	* gcc.dg/builtin-object-size-pr101832-2.c: New test.
> 	* gcc.dg/builtin-object-size-pr101832-3.c: New test.
> 	* gcc.dg/builtin-object-size-pr101832-4.c: New test.
> 	* gcc.dg/builtin-object-size-pr101832.c: New test.
> ---
>   .../gcc.dg/builtin-object-size-pr101832-2.c   | 135 ++++++++++++++++++
>   .../gcc.dg/builtin-object-size-pr101832-3.c   | 135 ++++++++++++++++++
>   .../gcc.dg/builtin-object-size-pr101832-4.c   | 135 ++++++++++++++++++
>   .../gcc.dg/builtin-object-size-pr101832.c     | 119 +++++++++++++++
>   gcc/tree-object-size.cc                       | 115 +++++++++++----
>   5 files changed, 611 insertions(+), 28 deletions(-)
>   create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
>   create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
>   create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
>   create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
> 
> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
> new file mode 100644
> index 00000000000..f38babc5415
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
> @@ -0,0 +1,135 @@
> +/* PR 101832:
> +   GCC extension accepts the case when a struct with a flexible array member
> +   is embedded into another struct (possibly recursively).
> +   __builtin_object_size will treat such struct as flexible size per
> +   -fstrict-flex-arrays.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -fstrict-flex-arrays=1" } */
> +
> +#include <stdio.h>
> +
> +unsigned n_fails = 0;
> +
> +#define expect(p, _v) do { \
> +  size_t v = _v; \
> +  if (p == v) \
> +    printf("ok:  %s == %zd\n", #p, p); \
> +  else {\
> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> +    n_fails++; \

I just pushed my testsuite fix, so you could use the macros in 
gcc.dg/builtin-object-size-common.h instead of accounting this yourself.

Also if you use __builtin_printf, you won't have to include stdio.h.

Thanks,
Sid

> +  } \
> +} while (0);
> +
> +struct A {
> +  int n;
> +  char data[];/* Content following header */
> +};
> +
> +struct B {
> +  int m;
> +  struct A a;
> +};
> +
> +struct C {
> +  int q;
> +  struct B b;
> +};
> +
> +struct A0 {
> +  int n;
> +  char data[0];/* Content following header */
> +};
> +
> +struct B0 {
> +  int m;
> +  struct A0 a;
> +};
> +
> +struct C0 {
> +  int q;
> +  struct B0 b;
> +};
> +
> +struct A1 {
> +  int n;
> +  char data[1];/* Content following header */
> +};
> +
> +struct B1 {
> +  int m;
> +  struct A1 a;
> +};
> +
> +struct C1 {
> +  int q;
> +  struct B1 b;
> +};
> +
> +struct An {
> +  int n;
> +  char data[8];/* Content following header */
> +};
> +
> +struct Bn {
> +  int m;
> +  struct An a;
> +};
> +
> +struct Cn {
> +  int q;
> +  struct Bn b;
> +};
> +
> +volatile void *magic1, *magic2;
> +
> +int main(int argc, char *argv[])
> +{
> +    struct B *outer;
> +    struct C *outest;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer = (void *)magic1;
> +    outest = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer->a, 1), -1);
> +    expect(__builtin_object_size(&outest->b, 1), -1);
> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
> +
> +    struct B0 *outer0;
> +    struct C0 *outest0;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer0 = (void *)magic1;
> +    outest0 = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer0->a, 1), -1);
> +    expect(__builtin_object_size(&outest0->b, 1), -1);
> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
> +
> +    struct B1 *outer1;
> +    struct C1 *outest1;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer1 = (void *)magic1;
> +    outest1 = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer1->a, 1), -1);
> +    expect(__builtin_object_size(&outest1->b, 1), -1);
> +    expect(__builtin_object_size(&outest1->b.a, 1), -1);
> +
> +    struct Bn *outern;
> +    struct Cn *outestn;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outern = (void *)magic1;
> +    outestn = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
> +
> +    if (n_fails > 0)
> +      __builtin_abort ();
> +
> +    return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
> new file mode 100644
> index 00000000000..aaae99b8d67
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
> @@ -0,0 +1,135 @@
> +/* PR 101832:
> +   GCC extension accepts the case when a struct with a flexible array member
> +   is embedded into another struct (possibly recursively).
> +   __builtin_object_size will treat such struct as flexible size per
> +   -fstrict-flex-arrays.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -fstrict-flex-arrays=2" } */
> +
> +#include <stdio.h>
> +
> +unsigned n_fails = 0;
> +
> +#define expect(p, _v) do { \
> +  size_t v = _v; \
> +  if (p == v) \
> +    printf("ok:  %s == %zd\n", #p, p); \
> +  else {\
> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> +    n_fails++; \
> +  } \
> +} while (0);
> +
> +struct A {
> +  int n;
> +  char data[];/* Content following header */
> +};
> +
> +struct B {
> +  int m;
> +  struct A a;
> +};
> +
> +struct C {
> +  int q;
> +  struct B b;
> +};
> +
> +struct A0 {
> +  int n;
> +  char data[0];/* Content following header */
> +};
> +
> +struct B0 {
> +  int m;
> +  struct A0 a;
> +};
> +
> +struct C0 {
> +  int q;
> +  struct B0 b;
> +};
> +
> +struct A1 {
> +  int n;
> +  char data[1];/* Content following header */
> +};
> +
> +struct B1 {
> +  int m;
> +  struct A1 a;
> +};
> +
> +struct C1 {
> +  int q;
> +  struct B1 b;
> +};
> +
> +struct An {
> +  int n;
> +  char data[8];/* Content following header */
> +};
> +
> +struct Bn {
> +  int m;
> +  struct An a;
> +};
> +
> +struct Cn {
> +  int q;
> +  struct Bn b;
> +};
> +
> +volatile void *magic1, *magic2;
> +
> +int main(int argc, char *argv[])
> +{
> +    struct B *outer;
> +    struct C *outest;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer = (void *)magic1;
> +    outest = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer->a, 1), -1);
> +    expect(__builtin_object_size(&outest->b, 1), -1);
> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
> +
> +    struct B0 *outer0;
> +    struct C0 *outest0;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer0 = (void *)magic1;
> +    outest0 = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer0->a, 1), -1);
> +    expect(__builtin_object_size(&outest0->b, 1), -1);
> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
> +
> +    struct B1 *outer1;
> +    struct C1 *outest1;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer1 = (void *)magic1;
> +    outest1 = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
> +    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
> +    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
> +
> +    struct Bn *outern;
> +    struct Cn *outestn;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outern = (void *)magic1;
> +    outestn = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
> +
> +    if (n_fails > 0)
> +      __builtin_abort ();
> +
> +    return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
> new file mode 100644
> index 00000000000..424264e2acd
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
> @@ -0,0 +1,135 @@
> +/* PR 101832:
> +   GCC extension accepts the case when a struct with a flexible array member
> +   is embedded into another struct (possibly recursively).
> +   __builtin_object_size will treat such struct as flexible size per
> +   -fstrict-flex-arrays.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -fstrict-flex-arrays=3" } */
> +
> +#include <stdio.h>
> +
> +unsigned n_fails = 0;
> +
> +#define expect(p, _v) do { \
> +  size_t v = _v; \
> +  if (p == v) \
> +    printf("ok:  %s == %zd\n", #p, p); \
> +  else {\
> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> +    n_fails++; \
> +  } \
> +} while (0);
> +
> +struct A {
> +  int n;
> +  char data[];/* Content following header */
> +};
> +
> +struct B {
> +  int m;
> +  struct A a;
> +};
> +
> +struct C {
> +  int q;
> +  struct B b;
> +};
> +
> +struct A0 {
> +  int n;
> +  char data[0];/* Content following header */
> +};
> +
> +struct B0 {
> +  int m;
> +  struct A0 a;
> +};
> +
> +struct C0 {
> +  int q;
> +  struct B0 b;
> +};
> +
> +struct A1 {
> +  int n;
> +  char data[1];/* Content following header */
> +};
> +
> +struct B1 {
> +  int m;
> +  struct A1 a;
> +};
> +
> +struct C1 {
> +  int q;
> +  struct B1 b;
> +};
> +
> +struct An {
> +  int n;
> +  char data[8];/* Content following header */
> +};
> +
> +struct Bn {
> +  int m;
> +  struct An a;
> +};
> +
> +struct Cn {
> +  int q;
> +  struct Bn b;
> +};
> +
> +volatile void *magic1, *magic2;
> +
> +int main(int argc, char *argv[])
> +{
> +    struct B *outer;
> +    struct C *outest;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer = (void *)magic1;
> +    outest = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer->a, 1), -1);
> +    expect(__builtin_object_size(&outest->b, 1), -1);
> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
> +
> +    struct B0 *outer0;
> +    struct C0 *outest0;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer0 = (void *)magic1;
> +    outest0 = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer0->a, 1), sizeof(outer0->a));
> +    expect(__builtin_object_size(&outest0->b, 1), sizeof(outest0->b));
> +    expect(__builtin_object_size(&outest0->b.a, 1), sizeof(outest0->b.a));
> +
> +    struct B1 *outer1;
> +    struct C1 *outest1;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outer1 = (void *)magic1;
> +    outest1 = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
> +    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
> +    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
> +
> +    struct Bn *outern;
> +    struct Cn *outestn;
> +
> +    /* Make sure optimization can't find some other object size. */
> +    outern = (void *)magic1;
> +    outestn = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
> +
> +    if (n_fails > 0)
> +      __builtin_abort ();
> +
> +    return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
> new file mode 100644
> index 00000000000..8ed6980edf0
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
> @@ -0,0 +1,119 @@
> +/* PR 101832:
> +   GCC extension accepts the case when a struct with a flexible array member
> +   is embedded into another struct (possibly recursively).
> +   __builtin_object_size will treat such struct as flexible size per
> +   -fstrict-flex-arrays.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2" } */
> +
> +#include <stdio.h>
> +
> +unsigned n_fails = 0;
> +
> +#define expect(p, _v) do { \
> +  size_t v = _v; \
> +  if (p == v) \
> +    printf("ok:  %s == %zd\n", #p, p); \
> +  else {\
> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> +    n_fails++; \
> +  } \
> +} while (0);
> +
> +struct A {
> +  int n;
> +  char data[];/* Content following header */
> +};
> +
> +struct B {
> +  int m;
> +  struct A a;
> +};
> +
> +struct C {
> +  int q;
> +  struct B b;
> +};
> +
> +struct A0 {
> +  int n;
> +  char data[0];/* Content following header */
> +};
> +
> +struct B0 {
> +  int m;
> +  struct A0 a;
> +};
> +
> +struct C0 {
> +  int q;
> +  struct B0 b;
> +};
> +
> +struct A1 {
> +  int n;
> +  char data[1];/* Content following header */
> +};
> +
> +struct B1 {
> +  int m;
> +  struct A1 a;
> +};
> +
> +struct C1 {
> +  int q;
> +  struct B1 b;
> +};
> +
> +struct An {
> +  int n;
> +  char data[8];/* Content following header */
> +};
> +
> +struct Bn {
> +  int m;
> +  struct An a;
> +};
> +
> +struct Cn {
> +  int q;
> +  struct Bn b;
> +};
> +
> +volatile void *magic1, *magic2;
> +
> +int main(int argc, char *argv[])
> +{
> +    struct B *outer = (void *)magic1;
> +    struct C *outest = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer->a, 1), -1);
> +    expect(__builtin_object_size(&outest->b, 1), -1);
> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
> +
> +    struct B0 *outer0 = (void *)magic1;
> +    struct C0 *outest0 = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer0->a, 1), -1);
> +    expect(__builtin_object_size(&outest0->b, 1), -1);
> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
> +
> +    struct B1 *outer1 = (void *)magic1;
> +    struct C1 *outest1 = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outer1->a, 1), -1);
> +    expect(__builtin_object_size(&outest1->b, 1), -1);
> +    expect(__builtin_object_size(&outest1->b.a, 1), -1);
> +
> +    struct Bn *outern = (void *)magic1;
> +    struct Cn *outestn = (void *)magic2;
> +
> +    expect(__builtin_object_size(&outern->a, 1), -1);
> +    expect(__builtin_object_size(&outestn->b, 1), -1);
> +    expect(__builtin_object_size(&outestn->b.a, 1), -1);
> +
> +    if (n_fails > 0)
> +      __builtin_abort ();
> +
> +    return 0;
> +}
> diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
> index 9a936a91983..56b78ca2a8c 100644
> --- a/gcc/tree-object-size.cc
> +++ b/gcc/tree-object-size.cc
> @@ -500,6 +500,42 @@ decl_init_size (tree decl, bool min)
>     return size;
>   }
>   
> +/* Determine whether TYPE is a structure with a flexible array member
> +   per -fstrict-flex-array or a union containing such a structure
> +   (possibly recursively).  */
> +static bool
> +flexible_size_type_p (const_tree type)
> +{
> +  tree x = NULL_TREE;
> +  tree last = NULL_TREE;
> +  switch (TREE_CODE (type))
> +    {
> +    case RECORD_TYPE:
> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
> +	if (TREE_CODE (x) == FIELD_DECL)
> +	  last = x;
> +      if (last == NULL_TREE)
> +	return false;
> +      if (TREE_CODE (TREE_TYPE (last)) == ARRAY_TYPE
> +	  && !DECL_NOT_FLEXARRAY (last))
> +	return true;
> +      else if (TREE_CODE (TREE_TYPE (last)) == RECORD_TYPE
> +	       || TREE_CODE (TREE_TYPE (last)) == UNION_TYPE)
> +	return flexible_size_type_p (TREE_TYPE (last));
> +      return false;
> +    case UNION_TYPE:
> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
> +	{
> +	  if (TREE_CODE (x) == FIELD_DECL
> +	      && flexible_array_type_p (TREE_TYPE (x)))
> +	    return true;
> +	}
> +      return false;
> +    default:
> +      return false;
> +  }
> +}
> +
>   /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
>      OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
>      If unknown, return size_unknown (object_size_type).  */
> @@ -633,45 +669,68 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
>   		    v = NULL_TREE;
>   		    break;
>   		  case COMPONENT_REF:
> -		    if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
> +		    /* When the ref is not to an array, a record or a union, it
> +		       will not have flexible size, compute the object size
> +		       directly.  */
> +		    if ((TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
> +			&& (TREE_CODE (TREE_TYPE (v)) != RECORD_TYPE)
> +			&& (TREE_CODE (TREE_TYPE (v)) != UNION_TYPE))
>   		      {
>   			v = NULL_TREE;
>   			break;
>   		      }
> -		    is_flexible_array_mem_ref = array_ref_flexible_size_p (v);
> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> -			  != UNION_TYPE
> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> -			  != QUAL_UNION_TYPE)
> -			break;
> -		      else
> -			v = TREE_OPERAND (v, 0);
> -		    if (TREE_CODE (v) == COMPONENT_REF
> -			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> -			   == RECORD_TYPE)
> +		    /* if the record or union does not have flexible size
> +		       compute the object size directly.  */
> +		    if (TREE_CODE (TREE_TYPE (v)) == RECORD_TYPE
> +			|| TREE_CODE (TREE_TYPE (v)) == UNION_TYPE)
>   		      {
> -			/* compute object size only if v is not a
> -			   flexible array member.  */
> -			if (!is_flexible_array_mem_ref)
> +			if (!flexible_size_type_p (TREE_TYPE (v)))
>   			  {
>   			    v = NULL_TREE;
>   			    break;
>   			  }
> -			v = TREE_OPERAND (v, 0);
> +			else
> +			  v = TREE_OPERAND (v, 0);
>   		      }
> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> -			  != UNION_TYPE
> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> -			  != QUAL_UNION_TYPE)
> -			break;
> -		      else
> -			v = TREE_OPERAND (v, 0);
> -		    if (v != pt_var)
> -		      v = NULL_TREE;
>   		    else
> -		      v = pt_var;
> +		      {
> +			/* Now the ref is to an array type.  */
> +			is_flexible_array_mem_ref
> +			  = array_ref_flexible_size_p (v);
> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> +			if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> +			      != UNION_TYPE
> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> +				 != QUAL_UNION_TYPE)
> +			  break;
> +			else
> +			  v = TREE_OPERAND (v, 0);
> +			if (TREE_CODE (v) == COMPONENT_REF
> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> +				 == RECORD_TYPE)
> +			  {
> +			    /* compute object size only if v is not a
> +			       flexible array member.  */
> +			    if (!is_flexible_array_mem_ref)
> +			      {
> +				v = NULL_TREE;
> +				break;
> +			      }
> +			    v = TREE_OPERAND (v, 0);
> +			  }
> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> +			  if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> +				!= UNION_TYPE
> +			      && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> +				   != QUAL_UNION_TYPE)
> +			    break;
> +			  else
> +			    v = TREE_OPERAND (v, 0);
> +			if (v != pt_var)
> +			  v = NULL_TREE;
> +			else
> +			  v = pt_var;
> +		      }
>   		    break;
>   		  default:
>   		    v = pt_var;

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/2] Documentation Update.
  2023-01-31 14:11 ` [PATCH 2/2] Documentation Update Qing Zhao
@ 2023-02-01 16:55   ` Siddhesh Poyarekar
  2023-02-01 18:24     ` Qing Zhao
  0 siblings, 1 reply; 45+ messages in thread
From: Siddhesh Poyarekar @ 2023-02-01 16:55 UTC (permalink / raw)
  To: Qing Zhao, rguenther; +Cc: gcc-patches, keescook

On 2023-01-31 09:11, Qing Zhao wrote:
> Update documentation to clarify a GCC extension on structure with
> flexible array member being nested in another structure.
> 
> gcc/ChangeLog:
> 
> 	* doc/extend.texi: Document GCC extension on a structure containing
> 	a flexible array member to be a member of another structure.

Should this resolve pr#77650 since the proposed action there appears to 
be to document these semantics?

Thanks,
Sid

> ---
>   gcc/doc/extend.texi | 35 ++++++++++++++++++++++++++++++++++-
>   1 file changed, 34 insertions(+), 1 deletion(-)
> 
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index 4a89a3eae7c..54e4baf49a9 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -1748,7 +1748,40 @@ Flexible array members may only appear as the last member of a
>   A structure containing a flexible array member, or a union containing
>   such a structure (possibly recursively), may not be a member of a
>   structure or an element of an array.  (However, these uses are
> -permitted by GCC as extensions.)
> +permitted by GCC as extensions, see details below.)
> +@end itemize
> +
> +GCC extension accepts a structure containing a flexible array member, or
> +a union containing such a structure (possibly recursively) to be a member
> +of a structure.
> +
> +There are two situations:
> +
> +@itemize @bullet
> +@item
> +The structure with a flexible array member is the last field of another
> +structure, for example:
> +
> +@smallexample
> +struct flex  @{ int length; char data[]; @};
> +
> +struct out_flex @{ int m; struct flex flex_data; @};
> +@end smallexample
> +
> +In the above, @code{flex_data.data[]} is considered as a flexible array too.
> +
> +@item
> +The structure with a flexible array member is the middle field of another
> +structure, for example:
> +
> +@smallexample
> +struct flex  @{ int length; char data[]; @};
> +
> +struct mid_flex @{ int m; struct flex flex_data; int n; @};
> +@end smallexample
> +
> +In the above, @code{flex_data.data[]} is allowed to be extended flexibly to
> +the padding. E.g, up to 4 elements.
>   @end itemize
>   
>   Non-empty initialization of zero-length

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-01 16:48   ` Siddhesh Poyarekar
@ 2023-02-01 18:20     ` Qing Zhao
  0 siblings, 0 replies; 45+ messages in thread
From: Qing Zhao @ 2023-02-01 18:20 UTC (permalink / raw)
  To: Siddhesh Poyarekar; +Cc: rguenther, gcc-patches, keescook

Siddhesh,

Thanks. I will update the testing case per your change.

Qing

> On Feb 1, 2023, at 11:48 AM, Siddhesh Poyarekar <siddhesh@gotplt.org> wrote:
> 
> On 2023-01-31 09:11, Qing Zhao wrote:
>> GCC extension accepts the case when a struct with a flexible array member
>> is embedded into another struct (possibly recursively).
>> __builtin_object_size should treat such struct as flexible size per
>> -fstrict-flex-arrays.
>> 	PR tree-optimization/101832
>> gcc/ChangeLog:
>> 	PR tree-optimization/101832
>> 	* tree-object-size.cc (flexible_size_type_p): New function.
>> 	(addr_object_size): Handle structure/union type when it has
>> 	flexible size.
>> gcc/testsuite/ChangeLog:
>> 	PR tree-optimization/101832
>> 	* gcc.dg/builtin-object-size-pr101832-2.c: New test.
>> 	* gcc.dg/builtin-object-size-pr101832-3.c: New test.
>> 	* gcc.dg/builtin-object-size-pr101832-4.c: New test.
>> 	* gcc.dg/builtin-object-size-pr101832.c: New test.
>> ---
>>  .../gcc.dg/builtin-object-size-pr101832-2.c   | 135 ++++++++++++++++++
>>  .../gcc.dg/builtin-object-size-pr101832-3.c   | 135 ++++++++++++++++++
>>  .../gcc.dg/builtin-object-size-pr101832-4.c   | 135 ++++++++++++++++++
>>  .../gcc.dg/builtin-object-size-pr101832.c     | 119 +++++++++++++++
>>  gcc/tree-object-size.cc                       | 115 +++++++++++----
>>  5 files changed, 611 insertions(+), 28 deletions(-)
>>  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
>>  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
>>  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
>>  create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
>> new file mode 100644
>> index 00000000000..f38babc5415
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
>> @@ -0,0 +1,135 @@
>> +/* PR 101832:
>> +   GCC extension accepts the case when a struct with a flexible array member
>> +   is embedded into another struct (possibly recursively).
>> +   __builtin_object_size will treat such struct as flexible size per
>> +   -fstrict-flex-arrays.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2 -fstrict-flex-arrays=1" } */
>> +
>> +#include <stdio.h>
>> +
>> +unsigned n_fails = 0;
>> +
>> +#define expect(p, _v) do { \
>> +  size_t v = _v; \
>> +  if (p == v) \
>> +    printf("ok:  %s == %zd\n", #p, p); \
>> +  else {\
>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
>> +    n_fails++; \
> 
> I just pushed my testsuite fix, so you could use the macros in gcc.dg/builtin-object-size-common.h instead of accounting this yourself.
> 
> Also if you use __builtin_printf, you won't have to include stdio.h.
> 
> Thanks,
> Sid
> 
>> +  } \
>> +} while (0);
>> +
>> +struct A {
>> +  int n;
>> +  char data[];/* Content following header */
>> +};
>> +
>> +struct B {
>> +  int m;
>> +  struct A a;
>> +};
>> +
>> +struct C {
>> +  int q;
>> +  struct B b;
>> +};
>> +
>> +struct A0 {
>> +  int n;
>> +  char data[0];/* Content following header */
>> +};
>> +
>> +struct B0 {
>> +  int m;
>> +  struct A0 a;
>> +};
>> +
>> +struct C0 {
>> +  int q;
>> +  struct B0 b;
>> +};
>> +
>> +struct A1 {
>> +  int n;
>> +  char data[1];/* Content following header */
>> +};
>> +
>> +struct B1 {
>> +  int m;
>> +  struct A1 a;
>> +};
>> +
>> +struct C1 {
>> +  int q;
>> +  struct B1 b;
>> +};
>> +
>> +struct An {
>> +  int n;
>> +  char data[8];/* Content following header */
>> +};
>> +
>> +struct Bn {
>> +  int m;
>> +  struct An a;
>> +};
>> +
>> +struct Cn {
>> +  int q;
>> +  struct Bn b;
>> +};
>> +
>> +volatile void *magic1, *magic2;
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    struct B *outer;
>> +    struct C *outest;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer = (void *)magic1;
>> +    outest = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer->a, 1), -1);
>> +    expect(__builtin_object_size(&outest->b, 1), -1);
>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
>> +
>> +    struct B0 *outer0;
>> +    struct C0 *outest0;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer0 = (void *)magic1;
>> +    outest0 = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer0->a, 1), -1);
>> +    expect(__builtin_object_size(&outest0->b, 1), -1);
>> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
>> +
>> +    struct B1 *outer1;
>> +    struct C1 *outest1;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer1 = (void *)magic1;
>> +    outest1 = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer1->a, 1), -1);
>> +    expect(__builtin_object_size(&outest1->b, 1), -1);
>> +    expect(__builtin_object_size(&outest1->b.a, 1), -1);
>> +
>> +    struct Bn *outern;
>> +    struct Cn *outestn;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outern = (void *)magic1;
>> +    outestn = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
>> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
>> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
>> +
>> +    if (n_fails > 0)
>> +      __builtin_abort ();
>> +
>> +    return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
>> new file mode 100644
>> index 00000000000..aaae99b8d67
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
>> @@ -0,0 +1,135 @@
>> +/* PR 101832:
>> +   GCC extension accepts the case when a struct with a flexible array member
>> +   is embedded into another struct (possibly recursively).
>> +   __builtin_object_size will treat such struct as flexible size per
>> +   -fstrict-flex-arrays.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2 -fstrict-flex-arrays=2" } */
>> +
>> +#include <stdio.h>
>> +
>> +unsigned n_fails = 0;
>> +
>> +#define expect(p, _v) do { \
>> +  size_t v = _v; \
>> +  if (p == v) \
>> +    printf("ok:  %s == %zd\n", #p, p); \
>> +  else {\
>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
>> +    n_fails++; \
>> +  } \
>> +} while (0);
>> +
>> +struct A {
>> +  int n;
>> +  char data[];/* Content following header */
>> +};
>> +
>> +struct B {
>> +  int m;
>> +  struct A a;
>> +};
>> +
>> +struct C {
>> +  int q;
>> +  struct B b;
>> +};
>> +
>> +struct A0 {
>> +  int n;
>> +  char data[0];/* Content following header */
>> +};
>> +
>> +struct B0 {
>> +  int m;
>> +  struct A0 a;
>> +};
>> +
>> +struct C0 {
>> +  int q;
>> +  struct B0 b;
>> +};
>> +
>> +struct A1 {
>> +  int n;
>> +  char data[1];/* Content following header */
>> +};
>> +
>> +struct B1 {
>> +  int m;
>> +  struct A1 a;
>> +};
>> +
>> +struct C1 {
>> +  int q;
>> +  struct B1 b;
>> +};
>> +
>> +struct An {
>> +  int n;
>> +  char data[8];/* Content following header */
>> +};
>> +
>> +struct Bn {
>> +  int m;
>> +  struct An a;
>> +};
>> +
>> +struct Cn {
>> +  int q;
>> +  struct Bn b;
>> +};
>> +
>> +volatile void *magic1, *magic2;
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    struct B *outer;
>> +    struct C *outest;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer = (void *)magic1;
>> +    outest = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer->a, 1), -1);
>> +    expect(__builtin_object_size(&outest->b, 1), -1);
>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
>> +
>> +    struct B0 *outer0;
>> +    struct C0 *outest0;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer0 = (void *)magic1;
>> +    outest0 = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer0->a, 1), -1);
>> +    expect(__builtin_object_size(&outest0->b, 1), -1);
>> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
>> +
>> +    struct B1 *outer1;
>> +    struct C1 *outest1;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer1 = (void *)magic1;
>> +    outest1 = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
>> +    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
>> +    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
>> +
>> +    struct Bn *outern;
>> +    struct Cn *outestn;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outern = (void *)magic1;
>> +    outestn = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
>> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
>> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
>> +
>> +    if (n_fails > 0)
>> +      __builtin_abort ();
>> +
>> +    return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
>> new file mode 100644
>> index 00000000000..424264e2acd
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
>> @@ -0,0 +1,135 @@
>> +/* PR 101832:
>> +   GCC extension accepts the case when a struct with a flexible array member
>> +   is embedded into another struct (possibly recursively).
>> +   __builtin_object_size will treat such struct as flexible size per
>> +   -fstrict-flex-arrays.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2 -fstrict-flex-arrays=3" } */
>> +
>> +#include <stdio.h>
>> +
>> +unsigned n_fails = 0;
>> +
>> +#define expect(p, _v) do { \
>> +  size_t v = _v; \
>> +  if (p == v) \
>> +    printf("ok:  %s == %zd\n", #p, p); \
>> +  else {\
>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
>> +    n_fails++; \
>> +  } \
>> +} while (0);
>> +
>> +struct A {
>> +  int n;
>> +  char data[];/* Content following header */
>> +};
>> +
>> +struct B {
>> +  int m;
>> +  struct A a;
>> +};
>> +
>> +struct C {
>> +  int q;
>> +  struct B b;
>> +};
>> +
>> +struct A0 {
>> +  int n;
>> +  char data[0];/* Content following header */
>> +};
>> +
>> +struct B0 {
>> +  int m;
>> +  struct A0 a;
>> +};
>> +
>> +struct C0 {
>> +  int q;
>> +  struct B0 b;
>> +};
>> +
>> +struct A1 {
>> +  int n;
>> +  char data[1];/* Content following header */
>> +};
>> +
>> +struct B1 {
>> +  int m;
>> +  struct A1 a;
>> +};
>> +
>> +struct C1 {
>> +  int q;
>> +  struct B1 b;
>> +};
>> +
>> +struct An {
>> +  int n;
>> +  char data[8];/* Content following header */
>> +};
>> +
>> +struct Bn {
>> +  int m;
>> +  struct An a;
>> +};
>> +
>> +struct Cn {
>> +  int q;
>> +  struct Bn b;
>> +};
>> +
>> +volatile void *magic1, *magic2;
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    struct B *outer;
>> +    struct C *outest;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer = (void *)magic1;
>> +    outest = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer->a, 1), -1);
>> +    expect(__builtin_object_size(&outest->b, 1), -1);
>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
>> +
>> +    struct B0 *outer0;
>> +    struct C0 *outest0;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer0 = (void *)magic1;
>> +    outest0 = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer0->a, 1), sizeof(outer0->a));
>> +    expect(__builtin_object_size(&outest0->b, 1), sizeof(outest0->b));
>> +    expect(__builtin_object_size(&outest0->b.a, 1), sizeof(outest0->b.a));
>> +
>> +    struct B1 *outer1;
>> +    struct C1 *outest1;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outer1 = (void *)magic1;
>> +    outest1 = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
>> +    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
>> +    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
>> +
>> +    struct Bn *outern;
>> +    struct Cn *outestn;
>> +
>> +    /* Make sure optimization can't find some other object size. */
>> +    outern = (void *)magic1;
>> +    outestn = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
>> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
>> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
>> +
>> +    if (n_fails > 0)
>> +      __builtin_abort ();
>> +
>> +    return 0;
>> +}
>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
>> new file mode 100644
>> index 00000000000..8ed6980edf0
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
>> @@ -0,0 +1,119 @@
>> +/* PR 101832:
>> +   GCC extension accepts the case when a struct with a flexible array member
>> +   is embedded into another struct (possibly recursively).
>> +   __builtin_object_size will treat such struct as flexible size per
>> +   -fstrict-flex-arrays.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2" } */
>> +
>> +#include <stdio.h>
>> +
>> +unsigned n_fails = 0;
>> +
>> +#define expect(p, _v) do { \
>> +  size_t v = _v; \
>> +  if (p == v) \
>> +    printf("ok:  %s == %zd\n", #p, p); \
>> +  else {\
>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
>> +    n_fails++; \
>> +  } \
>> +} while (0);
>> +
>> +struct A {
>> +  int n;
>> +  char data[];/* Content following header */
>> +};
>> +
>> +struct B {
>> +  int m;
>> +  struct A a;
>> +};
>> +
>> +struct C {
>> +  int q;
>> +  struct B b;
>> +};
>> +
>> +struct A0 {
>> +  int n;
>> +  char data[0];/* Content following header */
>> +};
>> +
>> +struct B0 {
>> +  int m;
>> +  struct A0 a;
>> +};
>> +
>> +struct C0 {
>> +  int q;
>> +  struct B0 b;
>> +};
>> +
>> +struct A1 {
>> +  int n;
>> +  char data[1];/* Content following header */
>> +};
>> +
>> +struct B1 {
>> +  int m;
>> +  struct A1 a;
>> +};
>> +
>> +struct C1 {
>> +  int q;
>> +  struct B1 b;
>> +};
>> +
>> +struct An {
>> +  int n;
>> +  char data[8];/* Content following header */
>> +};
>> +
>> +struct Bn {
>> +  int m;
>> +  struct An a;
>> +};
>> +
>> +struct Cn {
>> +  int q;
>> +  struct Bn b;
>> +};
>> +
>> +volatile void *magic1, *magic2;
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    struct B *outer = (void *)magic1;
>> +    struct C *outest = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer->a, 1), -1);
>> +    expect(__builtin_object_size(&outest->b, 1), -1);
>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
>> +
>> +    struct B0 *outer0 = (void *)magic1;
>> +    struct C0 *outest0 = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer0->a, 1), -1);
>> +    expect(__builtin_object_size(&outest0->b, 1), -1);
>> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
>> +
>> +    struct B1 *outer1 = (void *)magic1;
>> +    struct C1 *outest1 = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outer1->a, 1), -1);
>> +    expect(__builtin_object_size(&outest1->b, 1), -1);
>> +    expect(__builtin_object_size(&outest1->b.a, 1), -1);
>> +
>> +    struct Bn *outern = (void *)magic1;
>> +    struct Cn *outestn = (void *)magic2;
>> +
>> +    expect(__builtin_object_size(&outern->a, 1), -1);
>> +    expect(__builtin_object_size(&outestn->b, 1), -1);
>> +    expect(__builtin_object_size(&outestn->b.a, 1), -1);
>> +
>> +    if (n_fails > 0)
>> +      __builtin_abort ();
>> +
>> +    return 0;
>> +}
>> diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
>> index 9a936a91983..56b78ca2a8c 100644
>> --- a/gcc/tree-object-size.cc
>> +++ b/gcc/tree-object-size.cc
>> @@ -500,6 +500,42 @@ decl_init_size (tree decl, bool min)
>>    return size;
>>  }
>>  +/* Determine whether TYPE is a structure with a flexible array member
>> +   per -fstrict-flex-array or a union containing such a structure
>> +   (possibly recursively).  */
>> +static bool
>> +flexible_size_type_p (const_tree type)
>> +{
>> +  tree x = NULL_TREE;
>> +  tree last = NULL_TREE;
>> +  switch (TREE_CODE (type))
>> +    {
>> +    case RECORD_TYPE:
>> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
>> +	if (TREE_CODE (x) == FIELD_DECL)
>> +	  last = x;
>> +      if (last == NULL_TREE)
>> +	return false;
>> +      if (TREE_CODE (TREE_TYPE (last)) == ARRAY_TYPE
>> +	  && !DECL_NOT_FLEXARRAY (last))
>> +	return true;
>> +      else if (TREE_CODE (TREE_TYPE (last)) == RECORD_TYPE
>> +	       || TREE_CODE (TREE_TYPE (last)) == UNION_TYPE)
>> +	return flexible_size_type_p (TREE_TYPE (last));
>> +      return false;
>> +    case UNION_TYPE:
>> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
>> +	{
>> +	  if (TREE_CODE (x) == FIELD_DECL
>> +	      && flexible_array_type_p (TREE_TYPE (x)))
>> +	    return true;
>> +	}
>> +      return false;
>> +    default:
>> +      return false;
>> +  }
>> +}
>> +
>>  /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
>>     OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
>>     If unknown, return size_unknown (object_size_type).  */
>> @@ -633,45 +669,68 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
>>  		    v = NULL_TREE;
>>  		    break;
>>  		  case COMPONENT_REF:
>> -		    if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
>> +		    /* When the ref is not to an array, a record or a union, it
>> +		       will not have flexible size, compute the object size
>> +		       directly.  */
>> +		    if ((TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
>> +			&& (TREE_CODE (TREE_TYPE (v)) != RECORD_TYPE)
>> +			&& (TREE_CODE (TREE_TYPE (v)) != UNION_TYPE))
>>  		      {
>>  			v = NULL_TREE;
>>  			break;
>>  		      }
>> -		    is_flexible_array_mem_ref = array_ref_flexible_size_p (v);
>> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> -			  != UNION_TYPE
>> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> -			  != QUAL_UNION_TYPE)
>> -			break;
>> -		      else
>> -			v = TREE_OPERAND (v, 0);
>> -		    if (TREE_CODE (v) == COMPONENT_REF
>> -			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> -			   == RECORD_TYPE)
>> +		    /* if the record or union does not have flexible size
>> +		       compute the object size directly.  */
>> +		    if (TREE_CODE (TREE_TYPE (v)) == RECORD_TYPE
>> +			|| TREE_CODE (TREE_TYPE (v)) == UNION_TYPE)
>>  		      {
>> -			/* compute object size only if v is not a
>> -			   flexible array member.  */
>> -			if (!is_flexible_array_mem_ref)
>> +			if (!flexible_size_type_p (TREE_TYPE (v)))
>>  			  {
>>  			    v = NULL_TREE;
>>  			    break;
>>  			  }
>> -			v = TREE_OPERAND (v, 0);
>> +			else
>> +			  v = TREE_OPERAND (v, 0);
>>  		      }
>> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> -			  != UNION_TYPE
>> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> -			  != QUAL_UNION_TYPE)
>> -			break;
>> -		      else
>> -			v = TREE_OPERAND (v, 0);
>> -		    if (v != pt_var)
>> -		      v = NULL_TREE;
>>  		    else
>> -		      v = pt_var;
>> +		      {
>> +			/* Now the ref is to an array type.  */
>> +			is_flexible_array_mem_ref
>> +			  = array_ref_flexible_size_p (v);
>> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>> +			if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> +			      != UNION_TYPE
>> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> +				 != QUAL_UNION_TYPE)
>> +			  break;
>> +			else
>> +			  v = TREE_OPERAND (v, 0);
>> +			if (TREE_CODE (v) == COMPONENT_REF
>> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> +				 == RECORD_TYPE)
>> +			  {
>> +			    /* compute object size only if v is not a
>> +			       flexible array member.  */
>> +			    if (!is_flexible_array_mem_ref)
>> +			      {
>> +				v = NULL_TREE;
>> +				break;
>> +			      }
>> +			    v = TREE_OPERAND (v, 0);
>> +			  }
>> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>> +			  if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> +				!= UNION_TYPE
>> +			      && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>> +				   != QUAL_UNION_TYPE)
>> +			    break;
>> +			  else
>> +			    v = TREE_OPERAND (v, 0);
>> +			if (v != pt_var)
>> +			  v = NULL_TREE;
>> +			else
>> +			  v = pt_var;
>> +		      }
>>  		    break;
>>  		  default:
>>  		    v = pt_var;


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/2] Documentation Update.
  2023-02-01 16:55   ` Siddhesh Poyarekar
@ 2023-02-01 18:24     ` Qing Zhao
  2023-02-01 18:57       ` Siddhesh Poyarekar
  0 siblings, 1 reply; 45+ messages in thread
From: Qing Zhao @ 2023-02-01 18:24 UTC (permalink / raw)
  To: Siddhesh Poyarekar; +Cc: Richard Biener, gcc Patches, keescook



> On Feb 1, 2023, at 11:55 AM, Siddhesh Poyarekar <siddhesh@gotplt.org> wrote:
> 
> On 2023-01-31 09:11, Qing Zhao wrote:
>> Update documentation to clarify a GCC extension on structure with
>> flexible array member being nested in another structure.
>> gcc/ChangeLog:
>> 	* doc/extend.texi: Document GCC extension on a structure containing
>> 	a flexible array member to be a member of another structure.
> 
> Should this resolve pr#77650 since the proposed action there appears to be to document these semantics?

My understanding of pr77650 is specifically for documentation on the following case:

The structure with a flexible array member is the middle field of another structure.

Which I added in the documentation as the 2nd situation.  
However, I am still not very comfortable on my current clarification on this situation: how should we document on 
the expected gcc behavior to handle such situation?

Qing
> 
> Thanks,
> Sid
> 
>> ---
>>  gcc/doc/extend.texi | 35 ++++++++++++++++++++++++++++++++++-
>>  1 file changed, 34 insertions(+), 1 deletion(-)
>> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
>> index 4a89a3eae7c..54e4baf49a9 100644
>> --- a/gcc/doc/extend.texi
>> +++ b/gcc/doc/extend.texi
>> @@ -1748,7 +1748,40 @@ Flexible array members may only appear as the last member of a
>>  A structure containing a flexible array member, or a union containing
>>  such a structure (possibly recursively), may not be a member of a
>>  structure or an element of an array.  (However, these uses are
>> -permitted by GCC as extensions.)
>> +permitted by GCC as extensions, see details below.)
>> +@end itemize
>> +
>> +GCC extension accepts a structure containing a flexible array member, or
>> +a union containing such a structure (possibly recursively) to be a member
>> +of a structure.
>> +
>> +There are two situations:
>> +
>> +@itemize @bullet
>> +@item
>> +The structure with a flexible array member is the last field of another
>> +structure, for example:
>> +
>> +@smallexample
>> +struct flex  @{ int length; char data[]; @};
>> +
>> +struct out_flex @{ int m; struct flex flex_data; @};
>> +@end smallexample
>> +
>> +In the above, @code{flex_data.data[]} is considered as a flexible array too.
>> +
>> +@item
>> +The structure with a flexible array member is the middle field of another
>> +structure, for example:
>> +
>> +@smallexample
>> +struct flex  @{ int length; char data[]; @};
>> +
>> +struct mid_flex @{ int m; struct flex flex_data; int n; @};
>> +@end smallexample
>> +
>> +In the above, @code{flex_data.data[]} is allowed to be extended flexibly to
>> +the padding. E.g, up to 4 elements.
>>  @end itemize
>>    Non-empty initialization of zero-length


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/2] Documentation Update.
  2023-02-01 18:24     ` Qing Zhao
@ 2023-02-01 18:57       ` Siddhesh Poyarekar
  2023-02-01 19:19         ` Qing Zhao
  2023-02-02  8:33         ` Richard Biener
  0 siblings, 2 replies; 45+ messages in thread
From: Siddhesh Poyarekar @ 2023-02-01 18:57 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Biener, gcc Patches, keescook

On 2023-02-01 13:24, Qing Zhao wrote:
> 
> 
>> On Feb 1, 2023, at 11:55 AM, Siddhesh Poyarekar <siddhesh@gotplt.org> wrote:
>>
>> On 2023-01-31 09:11, Qing Zhao wrote:
>>> Update documentation to clarify a GCC extension on structure with
>>> flexible array member being nested in another structure.
>>> gcc/ChangeLog:
>>> 	* doc/extend.texi: Document GCC extension on a structure containing
>>> 	a flexible array member to be a member of another structure.
>>
>> Should this resolve pr#77650 since the proposed action there appears to be to document these semantics?
> 
> My understanding of pr77650 is specifically for documentation on the following case:
> 
> The structure with a flexible array member is the middle field of another structure.
> 
> Which I added in the documentation as the 2nd situation.
> However, I am still not very comfortable on my current clarification on this situation: how should we document on
> the expected gcc behavior to handle such situation?

I reckon wording that dissuades programmers from using this might be 
appropriate, i.e. don't rely on this and if you already have such nested 
flex arrays, change code to remove them.

>>> +In the above, @code{flex_data.data[]} is allowed to be extended flexibly to
>>> +the padding. E.g, up to 4 elements.

"""
... Relying on space in struct padding is bad programming practice and 
any code relying on this behaviour should be modified to ensure that 
flexible array members only end up at the ends of arrays.  The 
`-pedantic` flag should help identify such uses.
"""

Although -pedantic will also flag on flex arrays nested in structs even 
if they're at the end of the parent struct, so my suggestion on the 
warning is not really perfect.

Sid

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/2] Documentation Update.
  2023-02-01 18:57       ` Siddhesh Poyarekar
@ 2023-02-01 19:19         ` Qing Zhao
  2023-02-02  8:33         ` Richard Biener
  1 sibling, 0 replies; 45+ messages in thread
From: Qing Zhao @ 2023-02-01 19:19 UTC (permalink / raw)
  To: Siddhesh Poyarekar; +Cc: Richard Biener, gcc Patches, keescook



> On Feb 1, 2023, at 1:57 PM, Siddhesh Poyarekar <siddhesh@gotplt.org> wrote:
> 
> On 2023-02-01 13:24, Qing Zhao wrote:
>>> On Feb 1, 2023, at 11:55 AM, Siddhesh Poyarekar <siddhesh@gotplt.org> wrote:
>>> 
>>> On 2023-01-31 09:11, Qing Zhao wrote:
>>>> Update documentation to clarify a GCC extension on structure with
>>>> flexible array member being nested in another structure.
>>>> gcc/ChangeLog:
>>>> 	* doc/extend.texi: Document GCC extension on a structure containing
>>>> 	a flexible array member to be a member of another structure.
>>> 
>>> Should this resolve pr#77650 since the proposed action there appears to be to document these semantics?
>> My understanding of pr77650 is specifically for documentation on the following case:
>> The structure with a flexible array member is the middle field of another structure.
>> Which I added in the documentation as the 2nd situation.
>> However, I am still not very comfortable on my current clarification on this situation: how should we document on
>> the expected gcc behavior to handle such situation?
> 
> I reckon wording that dissuades programmers from using this might be appropriate, i.e. don't rely on this and if you already have such nested flex arrays, change code to remove them.

Good suggestion. 

> 
>>>> +In the above, @code{flex_data.data[]} is allowed to be extended flexibly to
>>>> +the padding. E.g, up to 4 elements.
> 
> """
> ... Relying on space in struct padding is bad programming practice and any code relying on this behaviour should be modified to ensure that flexible array members only end up at the ends of arrays.  The `-pedantic` flag should help identify such uses.
> """
> 
> Although -pedantic will also flag on flex arrays nested in structs even if they're at the end of the parent struct, so my suggestion on the warning is not really perfect.

Yes, both the situations (flex arrays nested in the end of of structures, or flex array nested in the middle of structures) are NOT standard-conforming, we might need to dis-encourage both situations?

Qing
> 
> Sid


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-01 14:19     ` Qing Zhao
@ 2023-02-02  8:07       ` Richard Biener
  2023-02-02 13:52         ` Qing Zhao
  0 siblings, 1 reply; 45+ messages in thread
From: Richard Biener @ 2023-02-02  8:07 UTC (permalink / raw)
  To: Qing Zhao; +Cc: gcc-patches, siddhesh, keescook

On Wed, 1 Feb 2023, Qing Zhao wrote:

> 
> 
> > On Feb 1, 2023, at 6:41 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Tue, 31 Jan 2023, Qing Zhao wrote:
> > 
> >> GCC extension accepts the case when a struct with a flexible array member
> >> is embedded into another struct (possibly recursively).
> >> __builtin_object_size should treat such struct as flexible size per
> >> -fstrict-flex-arrays.
> >> 
> >> 	PR tree-optimization/101832
> >> 
> >> gcc/ChangeLog:
> >> 
> >> 	PR tree-optimization/101832
> >> 	* tree-object-size.cc (flexible_size_type_p): New function.
> >> 	(addr_object_size): Handle structure/union type when it has
> >> 	flexible size.
> >> 
> >> gcc/testsuite/ChangeLog:
> >> 
> >> 	PR tree-optimization/101832
> >> 	* gcc.dg/builtin-object-size-pr101832-2.c: New test.
> >> 	* gcc.dg/builtin-object-size-pr101832-3.c: New test.
> >> 	* gcc.dg/builtin-object-size-pr101832-4.c: New test.
> >> 	* gcc.dg/builtin-object-size-pr101832.c: New test.
> >> ---
> >> .../gcc.dg/builtin-object-size-pr101832-2.c   | 135 ++++++++++++++++++
> >> .../gcc.dg/builtin-object-size-pr101832-3.c   | 135 ++++++++++++++++++
> >> .../gcc.dg/builtin-object-size-pr101832-4.c   | 135 ++++++++++++++++++
> >> .../gcc.dg/builtin-object-size-pr101832.c     | 119 +++++++++++++++
> >> gcc/tree-object-size.cc                       | 115 +++++++++++----
> >> 5 files changed, 611 insertions(+), 28 deletions(-)
> >> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
> >> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
> >> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
> >> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
> >> 
> >> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
> >> new file mode 100644
> >> index 00000000000..f38babc5415
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
> >> @@ -0,0 +1,135 @@
> >> +/* PR 101832: 
> >> +   GCC extension accepts the case when a struct with a flexible array member
> >> +   is embedded into another struct (possibly recursively).
> >> +   __builtin_object_size will treat such struct as flexible size per
> >> +   -fstrict-flex-arrays.  */ 
> >> +/* { dg-do run } */
> >> +/* { dg-options "-O2 -fstrict-flex-arrays=1" } */
> >> +
> >> +#include <stdio.h>
> >> +
> >> +unsigned n_fails = 0;
> >> +
> >> +#define expect(p, _v) do { \
> >> +  size_t v = _v; \
> >> +  if (p == v) \
> >> +    printf("ok:  %s == %zd\n", #p, p); \
> >> +  else {\
> >> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> >> +    n_fails++; \
> >> +  } \
> >> +} while (0);
> >> +
> >> +struct A {
> >> +  int n;
> >> +  char data[];/* Content following header */
> >> +};
> >> +
> >> +struct B {
> >> +  int m;
> >> +  struct A a;
> >> +};
> >> +
> >> +struct C {
> >> +  int q;
> >> +  struct B b;
> >> +};
> >> +
> >> +struct A0 {
> >> +  int n;
> >> +  char data[0];/* Content following header */
> >> +};
> >> +
> >> +struct B0 {
> >> +  int m;
> >> +  struct A0 a;
> >> +};
> >> +
> >> +struct C0 {
> >> +  int q;
> >> +  struct B0 b;
> >> +};
> >> +
> >> +struct A1 {
> >> +  int n;
> >> +  char data[1];/* Content following header */
> >> +};
> >> +
> >> +struct B1 {
> >> +  int m;
> >> +  struct A1 a;
> >> +};
> >> +
> >> +struct C1 {
> >> +  int q;
> >> +  struct B1 b;
> >> +};
> >> +
> >> +struct An {
> >> +  int n;
> >> +  char data[8];/* Content following header */
> >> +};
> >> +
> >> +struct Bn {
> >> +  int m;
> >> +  struct An a;
> >> +};
> >> +
> >> +struct Cn {
> >> +  int q;
> >> +  struct Bn b;
> >> +};
> >> +
> >> +volatile void *magic1, *magic2;
> >> +
> >> +int main(int argc, char *argv[])
> >> +{
> >> +    struct B *outer;
> >> +    struct C *outest;
> >> +
> >> +    /* Make sure optimization can't find some other object size. */
> >> +    outer = (void *)magic1;
> >> +    outest = (void *)magic2;
> >> +
> >> +    expect(__builtin_object_size(&outer->a, 1), -1);
> >> +    expect(__builtin_object_size(&outest->b, 1), -1);
> >> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
> >> +
> >> +    struct B0 *outer0;
> >> +    struct C0 *outest0;
> >> +
> >> +    /* Make sure optimization can't find some other object size. */
> >> +    outer0 = (void *)magic1;
> >> +    outest0 = (void *)magic2;
> >> +
> >> +    expect(__builtin_object_size(&outer0->a, 1), -1);
> >> +    expect(__builtin_object_size(&outest0->b, 1), -1);
> >> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
> >> +
> >> +    struct B1 *outer1;
> >> +    struct C1 *outest1;
> >> +
> >> +    /* Make sure optimization can't find some other object size. */
> >> +    outer1 = (void *)magic1;
> >> +    outest1 = (void *)magic2;
> >> +
> >> +    expect(__builtin_object_size(&outer1->a, 1), -1);
> >> +    expect(__builtin_object_size(&outest1->b, 1), -1);
> >> +    expect(__builtin_object_size(&outest1->b.a, 1), -1);
> >> +
> >> +    struct Bn *outern;
> >> +    struct Cn *outestn;
> >> +
> >> +    /* Make sure optimization can't find some other object size. */
> >> +    outern = (void *)magic1;
> >> +    outestn = (void *)magic2;
> >> +
> >> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
> >> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
> >> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
> >> +
> >> +    if (n_fails > 0)
> >> +      __builtin_abort ();
> >> +
> >> +    return 0;
> >> +}
> >> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
> >> new file mode 100644
> >> index 00000000000..aaae99b8d67
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
> >> @@ -0,0 +1,135 @@
> >> +/* PR 101832: 
> >> +   GCC extension accepts the case when a struct with a flexible array member
> >> +   is embedded into another struct (possibly recursively).
> >> +   __builtin_object_size will treat such struct as flexible size per
> >> +   -fstrict-flex-arrays.  */
> >> +/* { dg-do run } */
> >> +/* { dg-options "-O2 -fstrict-flex-arrays=2" } */
> >> +
> >> +#include <stdio.h>
> >> +
> >> +unsigned n_fails = 0;
> >> +
> >> +#define expect(p, _v) do { \
> >> +  size_t v = _v; \
> >> +  if (p == v) \
> >> +    printf("ok:  %s == %zd\n", #p, p); \
> >> +  else {\
> >> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> >> +    n_fails++; \
> >> +  } \
> >> +} while (0);
> >> +
> >> +struct A {
> >> +  int n;
> >> +  char data[];/* Content following header */
> >> +};
> >> +
> >> +struct B {
> >> +  int m;
> >> +  struct A a;
> >> +};
> >> +
> >> +struct C {
> >> +  int q;
> >> +  struct B b;
> >> +};
> >> +
> >> +struct A0 {
> >> +  int n;
> >> +  char data[0];/* Content following header */
> >> +};
> >> +
> >> +struct B0 {
> >> +  int m;
> >> +  struct A0 a;
> >> +};
> >> +
> >> +struct C0 {
> >> +  int q;
> >> +  struct B0 b;
> >> +};
> >> +
> >> +struct A1 {
> >> +  int n;
> >> +  char data[1];/* Content following header */
> >> +};
> >> +
> >> +struct B1 {
> >> +  int m;
> >> +  struct A1 a;
> >> +};
> >> +
> >> +struct C1 {
> >> +  int q;
> >> +  struct B1 b;
> >> +};
> >> +
> >> +struct An {
> >> +  int n;
> >> +  char data[8];/* Content following header */
> >> +};
> >> +
> >> +struct Bn {
> >> +  int m;
> >> +  struct An a;
> >> +};
> >> +
> >> +struct Cn {
> >> +  int q;
> >> +  struct Bn b;
> >> +};
> >> +
> >> +volatile void *magic1, *magic2;
> >> +
> >> +int main(int argc, char *argv[])
> >> +{
> >> +    struct B *outer;
> >> +    struct C *outest;
> >> +
> >> +    /* Make sure optimization can't find some other object size. */
> >> +    outer = (void *)magic1;
> >> +    outest = (void *)magic2;
> >> +
> >> +    expect(__builtin_object_size(&outer->a, 1), -1);
> >> +    expect(__builtin_object_size(&outest->b, 1), -1);
> >> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
> >> +
> >> +    struct B0 *outer0;
> >> +    struct C0 *outest0;
> >> +
> >> +    /* Make sure optimization can't find some other object size. */
> >> +    outer0 = (void *)magic1;
> >> +    outest0 = (void *)magic2;
> >> +
> >> +    expect(__builtin_object_size(&outer0->a, 1), -1);
> >> +    expect(__builtin_object_size(&outest0->b, 1), -1);
> >> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
> >> +
> >> +    struct B1 *outer1;
> >> +    struct C1 *outest1;
> >> +
> >> +    /* Make sure optimization can't find some other object size. */
> >> +    outer1 = (void *)magic1;
> >> +    outest1 = (void *)magic2;
> >> +
> >> +    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
> >> +    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
> >> +    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
> >> +
> >> +    struct Bn *outern;
> >> +    struct Cn *outestn;
> >> +
> >> +    /* Make sure optimization can't find some other object size. */
> >> +    outern = (void *)magic1;
> >> +    outestn = (void *)magic2;
> >> +
> >> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
> >> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
> >> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
> >> +
> >> +    if (n_fails > 0)
> >> +      __builtin_abort ();
> >> +
> >> +    return 0;
> >> +}
> >> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
> >> new file mode 100644
> >> index 00000000000..424264e2acd
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
> >> @@ -0,0 +1,135 @@
> >> +/* PR 101832: 
> >> +   GCC extension accepts the case when a struct with a flexible array member
> >> +   is embedded into another struct (possibly recursively).
> >> +   __builtin_object_size will treat such struct as flexible size per
> >> +   -fstrict-flex-arrays.  */
> >> +/* { dg-do run } */
> >> +/* { dg-options "-O2 -fstrict-flex-arrays=3" } */
> >> +
> >> +#include <stdio.h>
> >> +
> >> +unsigned n_fails = 0;
> >> +
> >> +#define expect(p, _v) do { \
> >> +  size_t v = _v; \
> >> +  if (p == v) \
> >> +    printf("ok:  %s == %zd\n", #p, p); \
> >> +  else {\
> >> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> >> +    n_fails++; \
> >> +  } \
> >> +} while (0);
> >> +
> >> +struct A {
> >> +  int n;
> >> +  char data[];/* Content following header */
> >> +};
> >> +
> >> +struct B {
> >> +  int m;
> >> +  struct A a;
> >> +};
> >> +
> >> +struct C {
> >> +  int q;
> >> +  struct B b;
> >> +};
> >> +
> >> +struct A0 {
> >> +  int n;
> >> +  char data[0];/* Content following header */
> >> +};
> >> +
> >> +struct B0 {
> >> +  int m;
> >> +  struct A0 a;
> >> +};
> >> +
> >> +struct C0 {
> >> +  int q;
> >> +  struct B0 b;
> >> +};
> >> +
> >> +struct A1 {
> >> +  int n;
> >> +  char data[1];/* Content following header */
> >> +};
> >> +
> >> +struct B1 {
> >> +  int m;
> >> +  struct A1 a;
> >> +};
> >> +
> >> +struct C1 {
> >> +  int q;
> >> +  struct B1 b;
> >> +};
> >> +
> >> +struct An {
> >> +  int n;
> >> +  char data[8];/* Content following header */
> >> +};
> >> +
> >> +struct Bn {
> >> +  int m;
> >> +  struct An a;
> >> +};
> >> +
> >> +struct Cn {
> >> +  int q;
> >> +  struct Bn b;
> >> +};
> >> +
> >> +volatile void *magic1, *magic2;
> >> +
> >> +int main(int argc, char *argv[])
> >> +{
> >> +    struct B *outer;
> >> +    struct C *outest;
> >> +
> >> +    /* Make sure optimization can't find some other object size. */
> >> +    outer = (void *)magic1;
> >> +    outest = (void *)magic2;
> >> +
> >> +    expect(__builtin_object_size(&outer->a, 1), -1);
> >> +    expect(__builtin_object_size(&outest->b, 1), -1);
> >> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
> >> +
> >> +    struct B0 *outer0;
> >> +    struct C0 *outest0;
> >> +
> >> +    /* Make sure optimization can't find some other object size. */
> >> +    outer0 = (void *)magic1;
> >> +    outest0 = (void *)magic2;
> >> +
> >> +    expect(__builtin_object_size(&outer0->a, 1), sizeof(outer0->a));
> >> +    expect(__builtin_object_size(&outest0->b, 1), sizeof(outest0->b));
> >> +    expect(__builtin_object_size(&outest0->b.a, 1), sizeof(outest0->b.a));
> >> +
> >> +    struct B1 *outer1;
> >> +    struct C1 *outest1;
> >> +
> >> +    /* Make sure optimization can't find some other object size. */
> >> +    outer1 = (void *)magic1;
> >> +    outest1 = (void *)magic2;
> >> +
> >> +    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
> >> +    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
> >> +    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
> >> +
> >> +    struct Bn *outern;
> >> +    struct Cn *outestn;
> >> +
> >> +    /* Make sure optimization can't find some other object size. */
> >> +    outern = (void *)magic1;
> >> +    outestn = (void *)magic2;
> >> +
> >> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
> >> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
> >> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
> >> +
> >> +    if (n_fails > 0)
> >> +      __builtin_abort ();
> >> +
> >> +    return 0;
> >> +}
> >> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
> >> new file mode 100644
> >> index 00000000000..8ed6980edf0
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
> >> @@ -0,0 +1,119 @@
> >> +/* PR 101832: 
> >> +   GCC extension accepts the case when a struct with a flexible array member
> >> +   is embedded into another struct (possibly recursively).
> >> +   __builtin_object_size will treat such struct as flexible size per
> >> +   -fstrict-flex-arrays.  */
> >> +/* { dg-do run } */
> >> +/* { dg-options "-O2" } */
> >> +
> >> +#include <stdio.h>
> >> +
> >> +unsigned n_fails = 0;
> >> +
> >> +#define expect(p, _v) do { \
> >> +  size_t v = _v; \
> >> +  if (p == v) \
> >> +    printf("ok:  %s == %zd\n", #p, p); \
> >> +  else {\
> >> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> >> +    n_fails++; \
> >> +  } \
> >> +} while (0);
> >> +
> >> +struct A {
> >> +  int n;
> >> +  char data[];/* Content following header */
> >> +};
> >> +
> >> +struct B {
> >> +  int m;
> >> +  struct A a;
> >> +};
> >> +
> >> +struct C {
> >> +  int q;
> >> +  struct B b;
> >> +};
> >> +
> >> +struct A0 {
> >> +  int n;
> >> +  char data[0];/* Content following header */
> >> +};
> >> +
> >> +struct B0 {
> >> +  int m;
> >> +  struct A0 a;
> >> +};
> >> +
> >> +struct C0 {
> >> +  int q;
> >> +  struct B0 b;
> >> +};
> >> +
> >> +struct A1 {
> >> +  int n;
> >> +  char data[1];/* Content following header */
> >> +};
> >> +
> >> +struct B1 {
> >> +  int m;
> >> +  struct A1 a;
> >> +};
> >> +
> >> +struct C1 {
> >> +  int q;
> >> +  struct B1 b;
> >> +};
> >> +
> >> +struct An {
> >> +  int n;
> >> +  char data[8];/* Content following header */
> >> +};
> >> +
> >> +struct Bn {
> >> +  int m;
> >> +  struct An a;
> >> +};
> >> +
> >> +struct Cn {
> >> +  int q;
> >> +  struct Bn b;
> >> +};
> >> +
> >> +volatile void *magic1, *magic2;
> >> +
> >> +int main(int argc, char *argv[])
> >> +{
> >> +    struct B *outer = (void *)magic1;
> >> +    struct C *outest = (void *)magic2;
> >> +
> >> +    expect(__builtin_object_size(&outer->a, 1), -1);
> >> +    expect(__builtin_object_size(&outest->b, 1), -1);
> >> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
> >> +
> >> +    struct B0 *outer0 = (void *)magic1;
> >> +    struct C0 *outest0 = (void *)magic2;
> >> +
> >> +    expect(__builtin_object_size(&outer0->a, 1), -1);
> >> +    expect(__builtin_object_size(&outest0->b, 1), -1);
> >> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
> >> +
> >> +    struct B1 *outer1 = (void *)magic1;
> >> +    struct C1 *outest1 = (void *)magic2;
> >> +
> >> +    expect(__builtin_object_size(&outer1->a, 1), -1);
> >> +    expect(__builtin_object_size(&outest1->b, 1), -1);
> >> +    expect(__builtin_object_size(&outest1->b.a, 1), -1);
> >> +
> >> +    struct Bn *outern = (void *)magic1;
> >> +    struct Cn *outestn = (void *)magic2;
> >> +
> >> +    expect(__builtin_object_size(&outern->a, 1), -1);
> >> +    expect(__builtin_object_size(&outestn->b, 1), -1);
> >> +    expect(__builtin_object_size(&outestn->b.a, 1), -1);
> >> +
> >> +    if (n_fails > 0)
> >> +      __builtin_abort ();
> >> +
> >> +    return 0;
> >> +}
> >> diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
> >> index 9a936a91983..56b78ca2a8c 100644
> >> --- a/gcc/tree-object-size.cc
> >> +++ b/gcc/tree-object-size.cc
> >> @@ -500,6 +500,42 @@ decl_init_size (tree decl, bool min)
> >>   return size;
> >> }
> >> 
> >> +/* Determine whether TYPE is a structure with a flexible array member
> >> +   per -fstrict-flex-array or a union containing such a structure
> >> +   (possibly recursively).  */
> >> +static bool
> >> +flexible_size_type_p (const_tree type)
> >> +{
> >> +  tree x = NULL_TREE;
> >> +  tree last = NULL_TREE;
> >> +  switch (TREE_CODE (type))
> >> +    {
> >> +    case RECORD_TYPE:
> >> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
> >> +	if (TREE_CODE (x) == FIELD_DECL)
> >> +	  last = x;
> >> +      if (last == NULL_TREE)
> >> +	return false;
> >> +      if (TREE_CODE (TREE_TYPE (last)) == ARRAY_TYPE
> >> +	  && !DECL_NOT_FLEXARRAY (last))
> >> +	return true;
> >> +      else if (TREE_CODE (TREE_TYPE (last)) == RECORD_TYPE
> >> +	       || TREE_CODE (TREE_TYPE (last)) == UNION_TYPE)
> >> +	return flexible_size_type_p (TREE_TYPE (last));
> > 
> > For types with many members this can become quite slow (IIRC we had
> > bugs about similar walks of all fields in types), and this function
> > looks like it's invoked multiple times on the same type per TU.
> > 
> > In principle the property is fixed at the time we lay out a record
> > type, so we might want to compute it at that time and record the
> > result.
> 
> You mean in FE? 

Yes, either in the frontend or in the middle-ends layout_type.

> Yes, that?s better and cleaner.
> 
> I will add one more field in the TYPE structure to record this information and check this field during middle end.
> 
> I had the same thought in the beginning, but not sure whether adding a 
> new field in IR is necessary or not, other places in middle end might 
> not use this new field.

It might be interesting to search for other code walking all fields of
a type to determine this or similar info.

> thanks.
> 
> Qing
> 
> > 
> >> +      return false;
> >> +    case UNION_TYPE:
> >> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
> >> +	{
> >> +	  if (TREE_CODE (x) == FIELD_DECL
> >> +	      && flexible_array_type_p (TREE_TYPE (x)))
> >> +	    return true;
> >> +	}
> >> +      return false;
> >> +    default:
> >> +      return false;
> >> +  }
> >> +}
> >> +
> >> /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
> >>    OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
> >>    If unknown, return size_unknown (object_size_type).  */
> >> @@ -633,45 +669,68 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
> >> 		    v = NULL_TREE;
> >> 		    break;
> >> 		  case COMPONENT_REF:
> >> -		    if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
> >> +		    /* When the ref is not to an array, a record or a union, it
> >> +		       will not have flexible size, compute the object size
> >> +		       directly.  */
> >> +		    if ((TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
> >> +			&& (TREE_CODE (TREE_TYPE (v)) != RECORD_TYPE)
> >> +			&& (TREE_CODE (TREE_TYPE (v)) != UNION_TYPE))
> >> 		      {
> >> 			v = NULL_TREE;
> >> 			break;
> >> 		      }
> >> -		    is_flexible_array_mem_ref = array_ref_flexible_size_p (v);
> >> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> >> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >> -			  != UNION_TYPE
> >> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >> -			  != QUAL_UNION_TYPE)
> >> -			break;
> >> -		      else
> >> -			v = TREE_OPERAND (v, 0);
> >> -		    if (TREE_CODE (v) == COMPONENT_REF
> >> -			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >> -			   == RECORD_TYPE)
> >> +		    /* if the record or union does not have flexible size
> >> +		       compute the object size directly.  */
> >> +		    if (TREE_CODE (TREE_TYPE (v)) == RECORD_TYPE
> >> +			|| TREE_CODE (TREE_TYPE (v)) == UNION_TYPE)
> >> 		      {
> >> -			/* compute object size only if v is not a
> >> -			   flexible array member.  */
> >> -			if (!is_flexible_array_mem_ref)
> >> +			if (!flexible_size_type_p (TREE_TYPE (v)))
> >> 			  {
> >> 			    v = NULL_TREE;
> >> 			    break;
> >> 			  }
> >> -			v = TREE_OPERAND (v, 0);
> >> +			else
> >> +			  v = TREE_OPERAND (v, 0);
> >> 		      }
> >> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> >> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >> -			  != UNION_TYPE
> >> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >> -			  != QUAL_UNION_TYPE)
> >> -			break;
> >> -		      else
> >> -			v = TREE_OPERAND (v, 0);
> >> -		    if (v != pt_var)
> >> -		      v = NULL_TREE;
> >> 		    else
> >> -		      v = pt_var;
> >> +		      {
> >> +			/* Now the ref is to an array type.  */
> >> +			is_flexible_array_mem_ref
> >> +			  = array_ref_flexible_size_p (v);
> >> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> >> +			if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >> +			      != UNION_TYPE
> >> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >> +				 != QUAL_UNION_TYPE)
> >> +			  break;
> >> +			else
> >> +			  v = TREE_OPERAND (v, 0);
> >> +			if (TREE_CODE (v) == COMPONENT_REF
> >> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >> +				 == RECORD_TYPE)
> >> +			  {
> >> +			    /* compute object size only if v is not a
> >> +			       flexible array member.  */
> >> +			    if (!is_flexible_array_mem_ref)
> >> +			      {
> >> +				v = NULL_TREE;
> >> +				break;
> >> +			      }
> >> +			    v = TREE_OPERAND (v, 0);
> >> +			  }
> >> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> >> +			  if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >> +				!= UNION_TYPE
> >> +			      && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >> +				   != QUAL_UNION_TYPE)
> >> +			    break;
> >> +			  else
> >> +			    v = TREE_OPERAND (v, 0);
> >> +			if (v != pt_var)
> >> +			  v = NULL_TREE;
> >> +			else
> >> +			  v = pt_var;
> >> +		      }
> >> 		    break;
> >> 		  default:
> >> 		    v = pt_var;
> >> 
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
> > Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
> > HRB 36809 (AG Nuernberg)
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
HRB 36809 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/2] Documentation Update.
  2023-02-01 18:57       ` Siddhesh Poyarekar
  2023-02-01 19:19         ` Qing Zhao
@ 2023-02-02  8:33         ` Richard Biener
  2023-02-02 14:31           ` Qing Zhao
  2023-02-03  4:25           ` Siddhesh Poyarekar
  1 sibling, 2 replies; 45+ messages in thread
From: Richard Biener @ 2023-02-02  8:33 UTC (permalink / raw)
  To: Siddhesh Poyarekar; +Cc: Qing Zhao, gcc Patches, keescook, Joseph S. Myers

On Wed, 1 Feb 2023, Siddhesh Poyarekar wrote:

> On 2023-02-01 13:24, Qing Zhao wrote:
> > 
> > 
> >> On Feb 1, 2023, at 11:55 AM, Siddhesh Poyarekar <siddhesh@gotplt.org>
> >> wrote:
> >>
> >> On 2023-01-31 09:11, Qing Zhao wrote:
> >>> Update documentation to clarify a GCC extension on structure with
> >>> flexible array member being nested in another structure.
> >>> gcc/ChangeLog:
> >>>  * doc/extend.texi: Document GCC extension on a structure containing
> >>>  a flexible array member to be a member of another structure.
> >>
> >> Should this resolve pr#77650 since the proposed action there appears to be
> >> to document these semantics?
> > 
> > My understanding of pr77650 is specifically for documentation on the
> > following case:
> > 
> > The structure with a flexible array member is the middle field of another
> > structure.
> > 
> > Which I added in the documentation as the 2nd situation.
> > However, I am still not very comfortable on my current clarification on this
> > situation: how should we document on
> > the expected gcc behavior to handle such situation?
> 
> I reckon wording that dissuades programmers from using this might be
> appropriate, i.e. don't rely on this and if you already have such nested flex
> arrays, change code to remove them.
> 
> >>> +In the above, @code{flex_data.data[]} is allowed to be extended flexibly
> >>> to
> >>> +the padding. E.g, up to 4 elements.
> 
> """
> ... Relying on space in struct padding is bad programming practice and any
> code relying on this behaviour should be modified to ensure that flexible
> array members only end up at the ends of arrays.  The `-pedantic` flag should
> help identify such uses.
> """
> 
> Although -pedantic will also flag on flex arrays nested in structs even if
> they're at the end of the parent struct, so my suggestion on the warning is
> not really perfect.

Wow, so I checked and we indeed accept

struct X { int n; int data[]; };
struct Y { struct X x; int end; };

and -pedantic says

t.c:2:21: warning: invalid use of structure with flexible array member 
[-Wpedantic]
    2 | struct Y { struct X x; int end; };
      |           

and clang reports

t.c:2:21: warning: field 'x' with variable sized type 'struct X' not at 
the end of a struct or class is a GNU extension 
[-Wgnu-variable-sized-type-not-at-end]
struct Y { struct X x; int end; };
                    ^

looking at PR77650 what seems missing there is the semantics of this
extension as expected/required by the glibc use.  comment#5 seems
to suggest that for my example above its expected that
Y.x.data[0] aliases Y.end?!  There must be a better way to write
the glibc code and IMHO it would be best to deprecate this extension.
Definitely the middle-end wouldn't consider this aliasing for
my example - maybe it "works" when wrapped inside a union but
then for sure only when the union is visible in all accesses ...

typedef union
{
  struct __gconv_info __cd;
  struct
  {
    struct __gconv_info __cd;
    struct __gconv_step_data __data;
  } __combined;
} _G_iconv_t;

could be written as

typedef union
{
  struct __gconv_info __cd;
  char __dummy[sizeof(struct __gconv_info) + sizeof(struct 
__gconv_step_data)];
} _G_iconv_t;

in case the intent is to provide a complete type with space for
a single __gconv_step_data.

Richard.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-02  8:07       ` Richard Biener
@ 2023-02-02 13:52         ` Qing Zhao
  2023-02-02 13:54           ` Richard Biener
  0 siblings, 1 reply; 45+ messages in thread
From: Qing Zhao @ 2023-02-02 13:52 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches, siddhesh, keescook



> On Feb 2, 2023, at 3:07 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Wed, 1 Feb 2023, Qing Zhao wrote:
> 
>> 
>> 
>>> On Feb 1, 2023, at 6:41 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On Tue, 31 Jan 2023, Qing Zhao wrote:
>>> 
>>>> GCC extension accepts the case when a struct with a flexible array member
>>>> is embedded into another struct (possibly recursively).
>>>> __builtin_object_size should treat such struct as flexible size per
>>>> -fstrict-flex-arrays.
>>>> 
>>>> 	PR tree-optimization/101832
>>>> 
>>>> gcc/ChangeLog:
>>>> 
>>>> 	PR tree-optimization/101832
>>>> 	* tree-object-size.cc (flexible_size_type_p): New function.
>>>> 	(addr_object_size): Handle structure/union type when it has
>>>> 	flexible size.
>>>> 
>>>> gcc/testsuite/ChangeLog:
>>>> 
>>>> 	PR tree-optimization/101832
>>>> 	* gcc.dg/builtin-object-size-pr101832-2.c: New test.
>>>> 	* gcc.dg/builtin-object-size-pr101832-3.c: New test.
>>>> 	* gcc.dg/builtin-object-size-pr101832-4.c: New test.
>>>> 	* gcc.dg/builtin-object-size-pr101832.c: New test.
>>>> ---
>>>> .../gcc.dg/builtin-object-size-pr101832-2.c   | 135 ++++++++++++++++++
>>>> .../gcc.dg/builtin-object-size-pr101832-3.c   | 135 ++++++++++++++++++
>>>> .../gcc.dg/builtin-object-size-pr101832-4.c   | 135 ++++++++++++++++++
>>>> .../gcc.dg/builtin-object-size-pr101832.c     | 119 +++++++++++++++
>>>> gcc/tree-object-size.cc                       | 115 +++++++++++----
>>>> 5 files changed, 611 insertions(+), 28 deletions(-)
>>>> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
>>>> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
>>>> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
>>>> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
>>>> 
>>>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
>>>> new file mode 100644
>>>> index 00000000000..f38babc5415
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
>>>> @@ -0,0 +1,135 @@
>>>> +/* PR 101832: 
>>>> +   GCC extension accepts the case when a struct with a flexible array member
>>>> +   is embedded into another struct (possibly recursively).
>>>> +   __builtin_object_size will treat such struct as flexible size per
>>>> +   -fstrict-flex-arrays.  */ 
>>>> +/* { dg-do run } */
>>>> +/* { dg-options "-O2 -fstrict-flex-arrays=1" } */
>>>> +
>>>> +#include <stdio.h>
>>>> +
>>>> +unsigned n_fails = 0;
>>>> +
>>>> +#define expect(p, _v) do { \
>>>> +  size_t v = _v; \
>>>> +  if (p == v) \
>>>> +    printf("ok:  %s == %zd\n", #p, p); \
>>>> +  else {\
>>>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
>>>> +    n_fails++; \
>>>> +  } \
>>>> +} while (0);
>>>> +
>>>> +struct A {
>>>> +  int n;
>>>> +  char data[];/* Content following header */
>>>> +};
>>>> +
>>>> +struct B {
>>>> +  int m;
>>>> +  struct A a;
>>>> +};
>>>> +
>>>> +struct C {
>>>> +  int q;
>>>> +  struct B b;
>>>> +};
>>>> +
>>>> +struct A0 {
>>>> +  int n;
>>>> +  char data[0];/* Content following header */
>>>> +};
>>>> +
>>>> +struct B0 {
>>>> +  int m;
>>>> +  struct A0 a;
>>>> +};
>>>> +
>>>> +struct C0 {
>>>> +  int q;
>>>> +  struct B0 b;
>>>> +};
>>>> +
>>>> +struct A1 {
>>>> +  int n;
>>>> +  char data[1];/* Content following header */
>>>> +};
>>>> +
>>>> +struct B1 {
>>>> +  int m;
>>>> +  struct A1 a;
>>>> +};
>>>> +
>>>> +struct C1 {
>>>> +  int q;
>>>> +  struct B1 b;
>>>> +};
>>>> +
>>>> +struct An {
>>>> +  int n;
>>>> +  char data[8];/* Content following header */
>>>> +};
>>>> +
>>>> +struct Bn {
>>>> +  int m;
>>>> +  struct An a;
>>>> +};
>>>> +
>>>> +struct Cn {
>>>> +  int q;
>>>> +  struct Bn b;
>>>> +};
>>>> +
>>>> +volatile void *magic1, *magic2;
>>>> +
>>>> +int main(int argc, char *argv[])
>>>> +{
>>>> +    struct B *outer;
>>>> +    struct C *outest;
>>>> +
>>>> +    /* Make sure optimization can't find some other object size. */
>>>> +    outer = (void *)magic1;
>>>> +    outest = (void *)magic2;
>>>> +
>>>> +    expect(__builtin_object_size(&outer->a, 1), -1);
>>>> +    expect(__builtin_object_size(&outest->b, 1), -1);
>>>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
>>>> +
>>>> +    struct B0 *outer0;
>>>> +    struct C0 *outest0;
>>>> +
>>>> +    /* Make sure optimization can't find some other object size. */
>>>> +    outer0 = (void *)magic1;
>>>> +    outest0 = (void *)magic2;
>>>> +
>>>> +    expect(__builtin_object_size(&outer0->a, 1), -1);
>>>> +    expect(__builtin_object_size(&outest0->b, 1), -1);
>>>> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
>>>> +
>>>> +    struct B1 *outer1;
>>>> +    struct C1 *outest1;
>>>> +
>>>> +    /* Make sure optimization can't find some other object size. */
>>>> +    outer1 = (void *)magic1;
>>>> +    outest1 = (void *)magic2;
>>>> +
>>>> +    expect(__builtin_object_size(&outer1->a, 1), -1);
>>>> +    expect(__builtin_object_size(&outest1->b, 1), -1);
>>>> +    expect(__builtin_object_size(&outest1->b.a, 1), -1);
>>>> +
>>>> +    struct Bn *outern;
>>>> +    struct Cn *outestn;
>>>> +
>>>> +    /* Make sure optimization can't find some other object size. */
>>>> +    outern = (void *)magic1;
>>>> +    outestn = (void *)magic2;
>>>> +
>>>> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
>>>> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
>>>> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
>>>> +
>>>> +    if (n_fails > 0)
>>>> +      __builtin_abort ();
>>>> +
>>>> +    return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
>>>> new file mode 100644
>>>> index 00000000000..aaae99b8d67
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
>>>> @@ -0,0 +1,135 @@
>>>> +/* PR 101832: 
>>>> +   GCC extension accepts the case when a struct with a flexible array member
>>>> +   is embedded into another struct (possibly recursively).
>>>> +   __builtin_object_size will treat such struct as flexible size per
>>>> +   -fstrict-flex-arrays.  */
>>>> +/* { dg-do run } */
>>>> +/* { dg-options "-O2 -fstrict-flex-arrays=2" } */
>>>> +
>>>> +#include <stdio.h>
>>>> +
>>>> +unsigned n_fails = 0;
>>>> +
>>>> +#define expect(p, _v) do { \
>>>> +  size_t v = _v; \
>>>> +  if (p == v) \
>>>> +    printf("ok:  %s == %zd\n", #p, p); \
>>>> +  else {\
>>>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
>>>> +    n_fails++; \
>>>> +  } \
>>>> +} while (0);
>>>> +
>>>> +struct A {
>>>> +  int n;
>>>> +  char data[];/* Content following header */
>>>> +};
>>>> +
>>>> +struct B {
>>>> +  int m;
>>>> +  struct A a;
>>>> +};
>>>> +
>>>> +struct C {
>>>> +  int q;
>>>> +  struct B b;
>>>> +};
>>>> +
>>>> +struct A0 {
>>>> +  int n;
>>>> +  char data[0];/* Content following header */
>>>> +};
>>>> +
>>>> +struct B0 {
>>>> +  int m;
>>>> +  struct A0 a;
>>>> +};
>>>> +
>>>> +struct C0 {
>>>> +  int q;
>>>> +  struct B0 b;
>>>> +};
>>>> +
>>>> +struct A1 {
>>>> +  int n;
>>>> +  char data[1];/* Content following header */
>>>> +};
>>>> +
>>>> +struct B1 {
>>>> +  int m;
>>>> +  struct A1 a;
>>>> +};
>>>> +
>>>> +struct C1 {
>>>> +  int q;
>>>> +  struct B1 b;
>>>> +};
>>>> +
>>>> +struct An {
>>>> +  int n;
>>>> +  char data[8];/* Content following header */
>>>> +};
>>>> +
>>>> +struct Bn {
>>>> +  int m;
>>>> +  struct An a;
>>>> +};
>>>> +
>>>> +struct Cn {
>>>> +  int q;
>>>> +  struct Bn b;
>>>> +};
>>>> +
>>>> +volatile void *magic1, *magic2;
>>>> +
>>>> +int main(int argc, char *argv[])
>>>> +{
>>>> +    struct B *outer;
>>>> +    struct C *outest;
>>>> +
>>>> +    /* Make sure optimization can't find some other object size. */
>>>> +    outer = (void *)magic1;
>>>> +    outest = (void *)magic2;
>>>> +
>>>> +    expect(__builtin_object_size(&outer->a, 1), -1);
>>>> +    expect(__builtin_object_size(&outest->b, 1), -1);
>>>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
>>>> +
>>>> +    struct B0 *outer0;
>>>> +    struct C0 *outest0;
>>>> +
>>>> +    /* Make sure optimization can't find some other object size. */
>>>> +    outer0 = (void *)magic1;
>>>> +    outest0 = (void *)magic2;
>>>> +
>>>> +    expect(__builtin_object_size(&outer0->a, 1), -1);
>>>> +    expect(__builtin_object_size(&outest0->b, 1), -1);
>>>> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
>>>> +
>>>> +    struct B1 *outer1;
>>>> +    struct C1 *outest1;
>>>> +
>>>> +    /* Make sure optimization can't find some other object size. */
>>>> +    outer1 = (void *)magic1;
>>>> +    outest1 = (void *)magic2;
>>>> +
>>>> +    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
>>>> +    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
>>>> +    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
>>>> +
>>>> +    struct Bn *outern;
>>>> +    struct Cn *outestn;
>>>> +
>>>> +    /* Make sure optimization can't find some other object size. */
>>>> +    outern = (void *)magic1;
>>>> +    outestn = (void *)magic2;
>>>> +
>>>> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
>>>> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
>>>> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
>>>> +
>>>> +    if (n_fails > 0)
>>>> +      __builtin_abort ();
>>>> +
>>>> +    return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
>>>> new file mode 100644
>>>> index 00000000000..424264e2acd
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
>>>> @@ -0,0 +1,135 @@
>>>> +/* PR 101832: 
>>>> +   GCC extension accepts the case when a struct with a flexible array member
>>>> +   is embedded into another struct (possibly recursively).
>>>> +   __builtin_object_size will treat such struct as flexible size per
>>>> +   -fstrict-flex-arrays.  */
>>>> +/* { dg-do run } */
>>>> +/* { dg-options "-O2 -fstrict-flex-arrays=3" } */
>>>> +
>>>> +#include <stdio.h>
>>>> +
>>>> +unsigned n_fails = 0;
>>>> +
>>>> +#define expect(p, _v) do { \
>>>> +  size_t v = _v; \
>>>> +  if (p == v) \
>>>> +    printf("ok:  %s == %zd\n", #p, p); \
>>>> +  else {\
>>>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
>>>> +    n_fails++; \
>>>> +  } \
>>>> +} while (0);
>>>> +
>>>> +struct A {
>>>> +  int n;
>>>> +  char data[];/* Content following header */
>>>> +};
>>>> +
>>>> +struct B {
>>>> +  int m;
>>>> +  struct A a;
>>>> +};
>>>> +
>>>> +struct C {
>>>> +  int q;
>>>> +  struct B b;
>>>> +};
>>>> +
>>>> +struct A0 {
>>>> +  int n;
>>>> +  char data[0];/* Content following header */
>>>> +};
>>>> +
>>>> +struct B0 {
>>>> +  int m;
>>>> +  struct A0 a;
>>>> +};
>>>> +
>>>> +struct C0 {
>>>> +  int q;
>>>> +  struct B0 b;
>>>> +};
>>>> +
>>>> +struct A1 {
>>>> +  int n;
>>>> +  char data[1];/* Content following header */
>>>> +};
>>>> +
>>>> +struct B1 {
>>>> +  int m;
>>>> +  struct A1 a;
>>>> +};
>>>> +
>>>> +struct C1 {
>>>> +  int q;
>>>> +  struct B1 b;
>>>> +};
>>>> +
>>>> +struct An {
>>>> +  int n;
>>>> +  char data[8];/* Content following header */
>>>> +};
>>>> +
>>>> +struct Bn {
>>>> +  int m;
>>>> +  struct An a;
>>>> +};
>>>> +
>>>> +struct Cn {
>>>> +  int q;
>>>> +  struct Bn b;
>>>> +};
>>>> +
>>>> +volatile void *magic1, *magic2;
>>>> +
>>>> +int main(int argc, char *argv[])
>>>> +{
>>>> +    struct B *outer;
>>>> +    struct C *outest;
>>>> +
>>>> +    /* Make sure optimization can't find some other object size. */
>>>> +    outer = (void *)magic1;
>>>> +    outest = (void *)magic2;
>>>> +
>>>> +    expect(__builtin_object_size(&outer->a, 1), -1);
>>>> +    expect(__builtin_object_size(&outest->b, 1), -1);
>>>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
>>>> +
>>>> +    struct B0 *outer0;
>>>> +    struct C0 *outest0;
>>>> +
>>>> +    /* Make sure optimization can't find some other object size. */
>>>> +    outer0 = (void *)magic1;
>>>> +    outest0 = (void *)magic2;
>>>> +
>>>> +    expect(__builtin_object_size(&outer0->a, 1), sizeof(outer0->a));
>>>> +    expect(__builtin_object_size(&outest0->b, 1), sizeof(outest0->b));
>>>> +    expect(__builtin_object_size(&outest0->b.a, 1), sizeof(outest0->b.a));
>>>> +
>>>> +    struct B1 *outer1;
>>>> +    struct C1 *outest1;
>>>> +
>>>> +    /* Make sure optimization can't find some other object size. */
>>>> +    outer1 = (void *)magic1;
>>>> +    outest1 = (void *)magic2;
>>>> +
>>>> +    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
>>>> +    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
>>>> +    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
>>>> +
>>>> +    struct Bn *outern;
>>>> +    struct Cn *outestn;
>>>> +
>>>> +    /* Make sure optimization can't find some other object size. */
>>>> +    outern = (void *)magic1;
>>>> +    outestn = (void *)magic2;
>>>> +
>>>> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
>>>> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
>>>> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
>>>> +
>>>> +    if (n_fails > 0)
>>>> +      __builtin_abort ();
>>>> +
>>>> +    return 0;
>>>> +}
>>>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
>>>> new file mode 100644
>>>> index 00000000000..8ed6980edf0
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
>>>> @@ -0,0 +1,119 @@
>>>> +/* PR 101832: 
>>>> +   GCC extension accepts the case when a struct with a flexible array member
>>>> +   is embedded into another struct (possibly recursively).
>>>> +   __builtin_object_size will treat such struct as flexible size per
>>>> +   -fstrict-flex-arrays.  */
>>>> +/* { dg-do run } */
>>>> +/* { dg-options "-O2" } */
>>>> +
>>>> +#include <stdio.h>
>>>> +
>>>> +unsigned n_fails = 0;
>>>> +
>>>> +#define expect(p, _v) do { \
>>>> +  size_t v = _v; \
>>>> +  if (p == v) \
>>>> +    printf("ok:  %s == %zd\n", #p, p); \
>>>> +  else {\
>>>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
>>>> +    n_fails++; \
>>>> +  } \
>>>> +} while (0);
>>>> +
>>>> +struct A {
>>>> +  int n;
>>>> +  char data[];/* Content following header */
>>>> +};
>>>> +
>>>> +struct B {
>>>> +  int m;
>>>> +  struct A a;
>>>> +};
>>>> +
>>>> +struct C {
>>>> +  int q;
>>>> +  struct B b;
>>>> +};
>>>> +
>>>> +struct A0 {
>>>> +  int n;
>>>> +  char data[0];/* Content following header */
>>>> +};
>>>> +
>>>> +struct B0 {
>>>> +  int m;
>>>> +  struct A0 a;
>>>> +};
>>>> +
>>>> +struct C0 {
>>>> +  int q;
>>>> +  struct B0 b;
>>>> +};
>>>> +
>>>> +struct A1 {
>>>> +  int n;
>>>> +  char data[1];/* Content following header */
>>>> +};
>>>> +
>>>> +struct B1 {
>>>> +  int m;
>>>> +  struct A1 a;
>>>> +};
>>>> +
>>>> +struct C1 {
>>>> +  int q;
>>>> +  struct B1 b;
>>>> +};
>>>> +
>>>> +struct An {
>>>> +  int n;
>>>> +  char data[8];/* Content following header */
>>>> +};
>>>> +
>>>> +struct Bn {
>>>> +  int m;
>>>> +  struct An a;
>>>> +};
>>>> +
>>>> +struct Cn {
>>>> +  int q;
>>>> +  struct Bn b;
>>>> +};
>>>> +
>>>> +volatile void *magic1, *magic2;
>>>> +
>>>> +int main(int argc, char *argv[])
>>>> +{
>>>> +    struct B *outer = (void *)magic1;
>>>> +    struct C *outest = (void *)magic2;
>>>> +
>>>> +    expect(__builtin_object_size(&outer->a, 1), -1);
>>>> +    expect(__builtin_object_size(&outest->b, 1), -1);
>>>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
>>>> +
>>>> +    struct B0 *outer0 = (void *)magic1;
>>>> +    struct C0 *outest0 = (void *)magic2;
>>>> +
>>>> +    expect(__builtin_object_size(&outer0->a, 1), -1);
>>>> +    expect(__builtin_object_size(&outest0->b, 1), -1);
>>>> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
>>>> +
>>>> +    struct B1 *outer1 = (void *)magic1;
>>>> +    struct C1 *outest1 = (void *)magic2;
>>>> +
>>>> +    expect(__builtin_object_size(&outer1->a, 1), -1);
>>>> +    expect(__builtin_object_size(&outest1->b, 1), -1);
>>>> +    expect(__builtin_object_size(&outest1->b.a, 1), -1);
>>>> +
>>>> +    struct Bn *outern = (void *)magic1;
>>>> +    struct Cn *outestn = (void *)magic2;
>>>> +
>>>> +    expect(__builtin_object_size(&outern->a, 1), -1);
>>>> +    expect(__builtin_object_size(&outestn->b, 1), -1);
>>>> +    expect(__builtin_object_size(&outestn->b.a, 1), -1);
>>>> +
>>>> +    if (n_fails > 0)
>>>> +      __builtin_abort ();
>>>> +
>>>> +    return 0;
>>>> +}
>>>> diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
>>>> index 9a936a91983..56b78ca2a8c 100644
>>>> --- a/gcc/tree-object-size.cc
>>>> +++ b/gcc/tree-object-size.cc
>>>> @@ -500,6 +500,42 @@ decl_init_size (tree decl, bool min)
>>>>  return size;
>>>> }
>>>> 
>>>> +/* Determine whether TYPE is a structure with a flexible array member
>>>> +   per -fstrict-flex-array or a union containing such a structure
>>>> +   (possibly recursively).  */
>>>> +static bool
>>>> +flexible_size_type_p (const_tree type)
>>>> +{
>>>> +  tree x = NULL_TREE;
>>>> +  tree last = NULL_TREE;
>>>> +  switch (TREE_CODE (type))
>>>> +    {
>>>> +    case RECORD_TYPE:
>>>> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
>>>> +	if (TREE_CODE (x) == FIELD_DECL)
>>>> +	  last = x;
>>>> +      if (last == NULL_TREE)
>>>> +	return false;
>>>> +      if (TREE_CODE (TREE_TYPE (last)) == ARRAY_TYPE
>>>> +	  && !DECL_NOT_FLEXARRAY (last))
>>>> +	return true;
>>>> +      else if (TREE_CODE (TREE_TYPE (last)) == RECORD_TYPE
>>>> +	       || TREE_CODE (TREE_TYPE (last)) == UNION_TYPE)
>>>> +	return flexible_size_type_p (TREE_TYPE (last));
>>> 
>>> For types with many members this can become quite slow (IIRC we had
>>> bugs about similar walks of all fields in types), and this function
>>> looks like it's invoked multiple times on the same type per TU.
>>> 
>>> In principle the property is fixed at the time we lay out a record
>>> type, so we might want to compute it at that time and record the
>>> result.
>> 
>> You mean in FE? 
> 
> Yes, either in the frontend or in the middle-ends layout_type.
> 
>> Yes, that?s better and cleaner.
>> 
>> I will add one more field in the TYPE structure to record this information and check this field during middle end.
>> 
>> I had the same thought in the beginning, but not sure whether adding a 
>> new field in IR is necessary or not, other places in middle end might 
>> not use this new field.
> 
> It might be interesting to search for other code walking all fields of
> a type to determine this or similar info.

There is one which is defined in tree.cc but only is referenced in c/c-decl.cc:

/* Determine whether TYPE is a structure with a flexible array member,
   or a union containing such a structure (possibly recursively).  */
flexible_array_type_p

However, this routine is a little different than the one I tried to add:

In the current routine “flexible_array_type_p”,  only one level nesting in the structure is accepted, multiple nesting in structure is not permitted.

So, my question is:  shall we accept multiple nesting in structure? i.e.

struct A {
  int n;
  char data[];/* Content following header */
};

struct B {
  int m;
  struct A a;
};

struct C {
  int q;
  struct B b;
};

Qing
> 
>> thanks.
>> 
>> Qing
>> 
>>> 
>>>> +      return false;
>>>> +    case UNION_TYPE:
>>>> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
>>>> +	{
>>>> +	  if (TREE_CODE (x) == FIELD_DECL
>>>> +	      && flexible_array_type_p (TREE_TYPE (x)))
>>>> +	    return true;
>>>> +	}
>>>> +      return false;
>>>> +    default:
>>>> +      return false;
>>>> +  }
>>>> +}
>>>> +
>>>> /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
>>>>   OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
>>>>   If unknown, return size_unknown (object_size_type).  */
>>>> @@ -633,45 +669,68 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
>>>> 		    v = NULL_TREE;
>>>> 		    break;
>>>> 		  case COMPONENT_REF:
>>>> -		    if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
>>>> +		    /* When the ref is not to an array, a record or a union, it
>>>> +		       will not have flexible size, compute the object size
>>>> +		       directly.  */
>>>> +		    if ((TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
>>>> +			&& (TREE_CODE (TREE_TYPE (v)) != RECORD_TYPE)
>>>> +			&& (TREE_CODE (TREE_TYPE (v)) != UNION_TYPE))
>>>> 		      {
>>>> 			v = NULL_TREE;
>>>> 			break;
>>>> 		      }
>>>> -		    is_flexible_array_mem_ref = array_ref_flexible_size_p (v);
>>>> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>>>> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>> -			  != UNION_TYPE
>>>> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>> -			  != QUAL_UNION_TYPE)
>>>> -			break;
>>>> -		      else
>>>> -			v = TREE_OPERAND (v, 0);
>>>> -		    if (TREE_CODE (v) == COMPONENT_REF
>>>> -			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>> -			   == RECORD_TYPE)
>>>> +		    /* if the record or union does not have flexible size
>>>> +		       compute the object size directly.  */
>>>> +		    if (TREE_CODE (TREE_TYPE (v)) == RECORD_TYPE
>>>> +			|| TREE_CODE (TREE_TYPE (v)) == UNION_TYPE)
>>>> 		      {
>>>> -			/* compute object size only if v is not a
>>>> -			   flexible array member.  */
>>>> -			if (!is_flexible_array_mem_ref)
>>>> +			if (!flexible_size_type_p (TREE_TYPE (v)))
>>>> 			  {
>>>> 			    v = NULL_TREE;
>>>> 			    break;
>>>> 			  }
>>>> -			v = TREE_OPERAND (v, 0);
>>>> +			else
>>>> +			  v = TREE_OPERAND (v, 0);
>>>> 		      }
>>>> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>>>> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>> -			  != UNION_TYPE
>>>> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>> -			  != QUAL_UNION_TYPE)
>>>> -			break;
>>>> -		      else
>>>> -			v = TREE_OPERAND (v, 0);
>>>> -		    if (v != pt_var)
>>>> -		      v = NULL_TREE;
>>>> 		    else
>>>> -		      v = pt_var;
>>>> +		      {
>>>> +			/* Now the ref is to an array type.  */
>>>> +			is_flexible_array_mem_ref
>>>> +			  = array_ref_flexible_size_p (v);
>>>> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>>>> +			if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>> +			      != UNION_TYPE
>>>> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>> +				 != QUAL_UNION_TYPE)
>>>> +			  break;
>>>> +			else
>>>> +			  v = TREE_OPERAND (v, 0);
>>>> +			if (TREE_CODE (v) == COMPONENT_REF
>>>> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>> +				 == RECORD_TYPE)
>>>> +			  {
>>>> +			    /* compute object size only if v is not a
>>>> +			       flexible array member.  */
>>>> +			    if (!is_flexible_array_mem_ref)
>>>> +			      {
>>>> +				v = NULL_TREE;
>>>> +				break;
>>>> +			      }
>>>> +			    v = TREE_OPERAND (v, 0);
>>>> +			  }
>>>> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>>>> +			  if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>> +				!= UNION_TYPE
>>>> +			      && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>> +				   != QUAL_UNION_TYPE)
>>>> +			    break;
>>>> +			  else
>>>> +			    v = TREE_OPERAND (v, 0);
>>>> +			if (v != pt_var)
>>>> +			  v = NULL_TREE;
>>>> +			else
>>>> +			  v = pt_var;
>>>> +		      }
>>>> 		    break;
>>>> 		  default:
>>>> 		    v = pt_var;
>>>> 
>>> 
>>> -- 
>>> Richard Biener <rguenther@suse.de>
>>> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
>>> Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
>>> HRB 36809 (AG Nuernberg)
>> 
>> 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
> Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
> HRB 36809 (AG Nuernberg)


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-02 13:52         ` Qing Zhao
@ 2023-02-02 13:54           ` Richard Biener
  2023-02-02 14:38             ` Qing Zhao
  0 siblings, 1 reply; 45+ messages in thread
From: Richard Biener @ 2023-02-02 13:54 UTC (permalink / raw)
  To: Qing Zhao; +Cc: gcc-patches, siddhesh, keescook

On Thu, 2 Feb 2023, Qing Zhao wrote:

> 
> 
> > On Feb 2, 2023, at 3:07 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Wed, 1 Feb 2023, Qing Zhao wrote:
> > 
> >> 
> >> 
> >>> On Feb 1, 2023, at 6:41 AM, Richard Biener <rguenther@suse.de> wrote:
> >>> 
> >>> On Tue, 31 Jan 2023, Qing Zhao wrote:
> >>> 
> >>>> GCC extension accepts the case when a struct with a flexible array member
> >>>> is embedded into another struct (possibly recursively).
> >>>> __builtin_object_size should treat such struct as flexible size per
> >>>> -fstrict-flex-arrays.
> >>>> 
> >>>> 	PR tree-optimization/101832
> >>>> 
> >>>> gcc/ChangeLog:
> >>>> 
> >>>> 	PR tree-optimization/101832
> >>>> 	* tree-object-size.cc (flexible_size_type_p): New function.
> >>>> 	(addr_object_size): Handle structure/union type when it has
> >>>> 	flexible size.
> >>>> 
> >>>> gcc/testsuite/ChangeLog:
> >>>> 
> >>>> 	PR tree-optimization/101832
> >>>> 	* gcc.dg/builtin-object-size-pr101832-2.c: New test.
> >>>> 	* gcc.dg/builtin-object-size-pr101832-3.c: New test.
> >>>> 	* gcc.dg/builtin-object-size-pr101832-4.c: New test.
> >>>> 	* gcc.dg/builtin-object-size-pr101832.c: New test.
> >>>> ---
> >>>> .../gcc.dg/builtin-object-size-pr101832-2.c   | 135 ++++++++++++++++++
> >>>> .../gcc.dg/builtin-object-size-pr101832-3.c   | 135 ++++++++++++++++++
> >>>> .../gcc.dg/builtin-object-size-pr101832-4.c   | 135 ++++++++++++++++++
> >>>> .../gcc.dg/builtin-object-size-pr101832.c     | 119 +++++++++++++++
> >>>> gcc/tree-object-size.cc                       | 115 +++++++++++----
> >>>> 5 files changed, 611 insertions(+), 28 deletions(-)
> >>>> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
> >>>> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
> >>>> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
> >>>> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
> >>>> 
> >>>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
> >>>> new file mode 100644
> >>>> index 00000000000..f38babc5415
> >>>> --- /dev/null
> >>>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
> >>>> @@ -0,0 +1,135 @@
> >>>> +/* PR 101832: 
> >>>> +   GCC extension accepts the case when a struct with a flexible array member
> >>>> +   is embedded into another struct (possibly recursively).
> >>>> +   __builtin_object_size will treat such struct as flexible size per
> >>>> +   -fstrict-flex-arrays.  */ 
> >>>> +/* { dg-do run } */
> >>>> +/* { dg-options "-O2 -fstrict-flex-arrays=1" } */
> >>>> +
> >>>> +#include <stdio.h>
> >>>> +
> >>>> +unsigned n_fails = 0;
> >>>> +
> >>>> +#define expect(p, _v) do { \
> >>>> +  size_t v = _v; \
> >>>> +  if (p == v) \
> >>>> +    printf("ok:  %s == %zd\n", #p, p); \
> >>>> +  else {\
> >>>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> >>>> +    n_fails++; \
> >>>> +  } \
> >>>> +} while (0);
> >>>> +
> >>>> +struct A {
> >>>> +  int n;
> >>>> +  char data[];/* Content following header */
> >>>> +};
> >>>> +
> >>>> +struct B {
> >>>> +  int m;
> >>>> +  struct A a;
> >>>> +};
> >>>> +
> >>>> +struct C {
> >>>> +  int q;
> >>>> +  struct B b;
> >>>> +};
> >>>> +
> >>>> +struct A0 {
> >>>> +  int n;
> >>>> +  char data[0];/* Content following header */
> >>>> +};
> >>>> +
> >>>> +struct B0 {
> >>>> +  int m;
> >>>> +  struct A0 a;
> >>>> +};
> >>>> +
> >>>> +struct C0 {
> >>>> +  int q;
> >>>> +  struct B0 b;
> >>>> +};
> >>>> +
> >>>> +struct A1 {
> >>>> +  int n;
> >>>> +  char data[1];/* Content following header */
> >>>> +};
> >>>> +
> >>>> +struct B1 {
> >>>> +  int m;
> >>>> +  struct A1 a;
> >>>> +};
> >>>> +
> >>>> +struct C1 {
> >>>> +  int q;
> >>>> +  struct B1 b;
> >>>> +};
> >>>> +
> >>>> +struct An {
> >>>> +  int n;
> >>>> +  char data[8];/* Content following header */
> >>>> +};
> >>>> +
> >>>> +struct Bn {
> >>>> +  int m;
> >>>> +  struct An a;
> >>>> +};
> >>>> +
> >>>> +struct Cn {
> >>>> +  int q;
> >>>> +  struct Bn b;
> >>>> +};
> >>>> +
> >>>> +volatile void *magic1, *magic2;
> >>>> +
> >>>> +int main(int argc, char *argv[])
> >>>> +{
> >>>> +    struct B *outer;
> >>>> +    struct C *outest;
> >>>> +
> >>>> +    /* Make sure optimization can't find some other object size. */
> >>>> +    outer = (void *)magic1;
> >>>> +    outest = (void *)magic2;
> >>>> +
> >>>> +    expect(__builtin_object_size(&outer->a, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest->b, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
> >>>> +
> >>>> +    struct B0 *outer0;
> >>>> +    struct C0 *outest0;
> >>>> +
> >>>> +    /* Make sure optimization can't find some other object size. */
> >>>> +    outer0 = (void *)magic1;
> >>>> +    outest0 = (void *)magic2;
> >>>> +
> >>>> +    expect(__builtin_object_size(&outer0->a, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest0->b, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
> >>>> +
> >>>> +    struct B1 *outer1;
> >>>> +    struct C1 *outest1;
> >>>> +
> >>>> +    /* Make sure optimization can't find some other object size. */
> >>>> +    outer1 = (void *)magic1;
> >>>> +    outest1 = (void *)magic2;
> >>>> +
> >>>> +    expect(__builtin_object_size(&outer1->a, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest1->b, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest1->b.a, 1), -1);
> >>>> +
> >>>> +    struct Bn *outern;
> >>>> +    struct Cn *outestn;
> >>>> +
> >>>> +    /* Make sure optimization can't find some other object size. */
> >>>> +    outern = (void *)magic1;
> >>>> +    outestn = (void *)magic2;
> >>>> +
> >>>> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
> >>>> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
> >>>> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
> >>>> +
> >>>> +    if (n_fails > 0)
> >>>> +      __builtin_abort ();
> >>>> +
> >>>> +    return 0;
> >>>> +}
> >>>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
> >>>> new file mode 100644
> >>>> index 00000000000..aaae99b8d67
> >>>> --- /dev/null
> >>>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
> >>>> @@ -0,0 +1,135 @@
> >>>> +/* PR 101832: 
> >>>> +   GCC extension accepts the case when a struct with a flexible array member
> >>>> +   is embedded into another struct (possibly recursively).
> >>>> +   __builtin_object_size will treat such struct as flexible size per
> >>>> +   -fstrict-flex-arrays.  */
> >>>> +/* { dg-do run } */
> >>>> +/* { dg-options "-O2 -fstrict-flex-arrays=2" } */
> >>>> +
> >>>> +#include <stdio.h>
> >>>> +
> >>>> +unsigned n_fails = 0;
> >>>> +
> >>>> +#define expect(p, _v) do { \
> >>>> +  size_t v = _v; \
> >>>> +  if (p == v) \
> >>>> +    printf("ok:  %s == %zd\n", #p, p); \
> >>>> +  else {\
> >>>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> >>>> +    n_fails++; \
> >>>> +  } \
> >>>> +} while (0);
> >>>> +
> >>>> +struct A {
> >>>> +  int n;
> >>>> +  char data[];/* Content following header */
> >>>> +};
> >>>> +
> >>>> +struct B {
> >>>> +  int m;
> >>>> +  struct A a;
> >>>> +};
> >>>> +
> >>>> +struct C {
> >>>> +  int q;
> >>>> +  struct B b;
> >>>> +};
> >>>> +
> >>>> +struct A0 {
> >>>> +  int n;
> >>>> +  char data[0];/* Content following header */
> >>>> +};
> >>>> +
> >>>> +struct B0 {
> >>>> +  int m;
> >>>> +  struct A0 a;
> >>>> +};
> >>>> +
> >>>> +struct C0 {
> >>>> +  int q;
> >>>> +  struct B0 b;
> >>>> +};
> >>>> +
> >>>> +struct A1 {
> >>>> +  int n;
> >>>> +  char data[1];/* Content following header */
> >>>> +};
> >>>> +
> >>>> +struct B1 {
> >>>> +  int m;
> >>>> +  struct A1 a;
> >>>> +};
> >>>> +
> >>>> +struct C1 {
> >>>> +  int q;
> >>>> +  struct B1 b;
> >>>> +};
> >>>> +
> >>>> +struct An {
> >>>> +  int n;
> >>>> +  char data[8];/* Content following header */
> >>>> +};
> >>>> +
> >>>> +struct Bn {
> >>>> +  int m;
> >>>> +  struct An a;
> >>>> +};
> >>>> +
> >>>> +struct Cn {
> >>>> +  int q;
> >>>> +  struct Bn b;
> >>>> +};
> >>>> +
> >>>> +volatile void *magic1, *magic2;
> >>>> +
> >>>> +int main(int argc, char *argv[])
> >>>> +{
> >>>> +    struct B *outer;
> >>>> +    struct C *outest;
> >>>> +
> >>>> +    /* Make sure optimization can't find some other object size. */
> >>>> +    outer = (void *)magic1;
> >>>> +    outest = (void *)magic2;
> >>>> +
> >>>> +    expect(__builtin_object_size(&outer->a, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest->b, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
> >>>> +
> >>>> +    struct B0 *outer0;
> >>>> +    struct C0 *outest0;
> >>>> +
> >>>> +    /* Make sure optimization can't find some other object size. */
> >>>> +    outer0 = (void *)magic1;
> >>>> +    outest0 = (void *)magic2;
> >>>> +
> >>>> +    expect(__builtin_object_size(&outer0->a, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest0->b, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
> >>>> +
> >>>> +    struct B1 *outer1;
> >>>> +    struct C1 *outest1;
> >>>> +
> >>>> +    /* Make sure optimization can't find some other object size. */
> >>>> +    outer1 = (void *)magic1;
> >>>> +    outest1 = (void *)magic2;
> >>>> +
> >>>> +    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
> >>>> +    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
> >>>> +    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
> >>>> +
> >>>> +    struct Bn *outern;
> >>>> +    struct Cn *outestn;
> >>>> +
> >>>> +    /* Make sure optimization can't find some other object size. */
> >>>> +    outern = (void *)magic1;
> >>>> +    outestn = (void *)magic2;
> >>>> +
> >>>> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
> >>>> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
> >>>> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
> >>>> +
> >>>> +    if (n_fails > 0)
> >>>> +      __builtin_abort ();
> >>>> +
> >>>> +    return 0;
> >>>> +}
> >>>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
> >>>> new file mode 100644
> >>>> index 00000000000..424264e2acd
> >>>> --- /dev/null
> >>>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
> >>>> @@ -0,0 +1,135 @@
> >>>> +/* PR 101832: 
> >>>> +   GCC extension accepts the case when a struct with a flexible array member
> >>>> +   is embedded into another struct (possibly recursively).
> >>>> +   __builtin_object_size will treat such struct as flexible size per
> >>>> +   -fstrict-flex-arrays.  */
> >>>> +/* { dg-do run } */
> >>>> +/* { dg-options "-O2 -fstrict-flex-arrays=3" } */
> >>>> +
> >>>> +#include <stdio.h>
> >>>> +
> >>>> +unsigned n_fails = 0;
> >>>> +
> >>>> +#define expect(p, _v) do { \
> >>>> +  size_t v = _v; \
> >>>> +  if (p == v) \
> >>>> +    printf("ok:  %s == %zd\n", #p, p); \
> >>>> +  else {\
> >>>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> >>>> +    n_fails++; \
> >>>> +  } \
> >>>> +} while (0);
> >>>> +
> >>>> +struct A {
> >>>> +  int n;
> >>>> +  char data[];/* Content following header */
> >>>> +};
> >>>> +
> >>>> +struct B {
> >>>> +  int m;
> >>>> +  struct A a;
> >>>> +};
> >>>> +
> >>>> +struct C {
> >>>> +  int q;
> >>>> +  struct B b;
> >>>> +};
> >>>> +
> >>>> +struct A0 {
> >>>> +  int n;
> >>>> +  char data[0];/* Content following header */
> >>>> +};
> >>>> +
> >>>> +struct B0 {
> >>>> +  int m;
> >>>> +  struct A0 a;
> >>>> +};
> >>>> +
> >>>> +struct C0 {
> >>>> +  int q;
> >>>> +  struct B0 b;
> >>>> +};
> >>>> +
> >>>> +struct A1 {
> >>>> +  int n;
> >>>> +  char data[1];/* Content following header */
> >>>> +};
> >>>> +
> >>>> +struct B1 {
> >>>> +  int m;
> >>>> +  struct A1 a;
> >>>> +};
> >>>> +
> >>>> +struct C1 {
> >>>> +  int q;
> >>>> +  struct B1 b;
> >>>> +};
> >>>> +
> >>>> +struct An {
> >>>> +  int n;
> >>>> +  char data[8];/* Content following header */
> >>>> +};
> >>>> +
> >>>> +struct Bn {
> >>>> +  int m;
> >>>> +  struct An a;
> >>>> +};
> >>>> +
> >>>> +struct Cn {
> >>>> +  int q;
> >>>> +  struct Bn b;
> >>>> +};
> >>>> +
> >>>> +volatile void *magic1, *magic2;
> >>>> +
> >>>> +int main(int argc, char *argv[])
> >>>> +{
> >>>> +    struct B *outer;
> >>>> +    struct C *outest;
> >>>> +
> >>>> +    /* Make sure optimization can't find some other object size. */
> >>>> +    outer = (void *)magic1;
> >>>> +    outest = (void *)magic2;
> >>>> +
> >>>> +    expect(__builtin_object_size(&outer->a, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest->b, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
> >>>> +
> >>>> +    struct B0 *outer0;
> >>>> +    struct C0 *outest0;
> >>>> +
> >>>> +    /* Make sure optimization can't find some other object size. */
> >>>> +    outer0 = (void *)magic1;
> >>>> +    outest0 = (void *)magic2;
> >>>> +
> >>>> +    expect(__builtin_object_size(&outer0->a, 1), sizeof(outer0->a));
> >>>> +    expect(__builtin_object_size(&outest0->b, 1), sizeof(outest0->b));
> >>>> +    expect(__builtin_object_size(&outest0->b.a, 1), sizeof(outest0->b.a));
> >>>> +
> >>>> +    struct B1 *outer1;
> >>>> +    struct C1 *outest1;
> >>>> +
> >>>> +    /* Make sure optimization can't find some other object size. */
> >>>> +    outer1 = (void *)magic1;
> >>>> +    outest1 = (void *)magic2;
> >>>> +
> >>>> +    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
> >>>> +    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
> >>>> +    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
> >>>> +
> >>>> +    struct Bn *outern;
> >>>> +    struct Cn *outestn;
> >>>> +
> >>>> +    /* Make sure optimization can't find some other object size. */
> >>>> +    outern = (void *)magic1;
> >>>> +    outestn = (void *)magic2;
> >>>> +
> >>>> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
> >>>> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
> >>>> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
> >>>> +
> >>>> +    if (n_fails > 0)
> >>>> +      __builtin_abort ();
> >>>> +
> >>>> +    return 0;
> >>>> +}
> >>>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
> >>>> new file mode 100644
> >>>> index 00000000000..8ed6980edf0
> >>>> --- /dev/null
> >>>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
> >>>> @@ -0,0 +1,119 @@
> >>>> +/* PR 101832: 
> >>>> +   GCC extension accepts the case when a struct with a flexible array member
> >>>> +   is embedded into another struct (possibly recursively).
> >>>> +   __builtin_object_size will treat such struct as flexible size per
> >>>> +   -fstrict-flex-arrays.  */
> >>>> +/* { dg-do run } */
> >>>> +/* { dg-options "-O2" } */
> >>>> +
> >>>> +#include <stdio.h>
> >>>> +
> >>>> +unsigned n_fails = 0;
> >>>> +
> >>>> +#define expect(p, _v) do { \
> >>>> +  size_t v = _v; \
> >>>> +  if (p == v) \
> >>>> +    printf("ok:  %s == %zd\n", #p, p); \
> >>>> +  else {\
> >>>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> >>>> +    n_fails++; \
> >>>> +  } \
> >>>> +} while (0);
> >>>> +
> >>>> +struct A {
> >>>> +  int n;
> >>>> +  char data[];/* Content following header */
> >>>> +};
> >>>> +
> >>>> +struct B {
> >>>> +  int m;
> >>>> +  struct A a;
> >>>> +};
> >>>> +
> >>>> +struct C {
> >>>> +  int q;
> >>>> +  struct B b;
> >>>> +};
> >>>> +
> >>>> +struct A0 {
> >>>> +  int n;
> >>>> +  char data[0];/* Content following header */
> >>>> +};
> >>>> +
> >>>> +struct B0 {
> >>>> +  int m;
> >>>> +  struct A0 a;
> >>>> +};
> >>>> +
> >>>> +struct C0 {
> >>>> +  int q;
> >>>> +  struct B0 b;
> >>>> +};
> >>>> +
> >>>> +struct A1 {
> >>>> +  int n;
> >>>> +  char data[1];/* Content following header */
> >>>> +};
> >>>> +
> >>>> +struct B1 {
> >>>> +  int m;
> >>>> +  struct A1 a;
> >>>> +};
> >>>> +
> >>>> +struct C1 {
> >>>> +  int q;
> >>>> +  struct B1 b;
> >>>> +};
> >>>> +
> >>>> +struct An {
> >>>> +  int n;
> >>>> +  char data[8];/* Content following header */
> >>>> +};
> >>>> +
> >>>> +struct Bn {
> >>>> +  int m;
> >>>> +  struct An a;
> >>>> +};
> >>>> +
> >>>> +struct Cn {
> >>>> +  int q;
> >>>> +  struct Bn b;
> >>>> +};
> >>>> +
> >>>> +volatile void *magic1, *magic2;
> >>>> +
> >>>> +int main(int argc, char *argv[])
> >>>> +{
> >>>> +    struct B *outer = (void *)magic1;
> >>>> +    struct C *outest = (void *)magic2;
> >>>> +
> >>>> +    expect(__builtin_object_size(&outer->a, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest->b, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
> >>>> +
> >>>> +    struct B0 *outer0 = (void *)magic1;
> >>>> +    struct C0 *outest0 = (void *)magic2;
> >>>> +
> >>>> +    expect(__builtin_object_size(&outer0->a, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest0->b, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
> >>>> +
> >>>> +    struct B1 *outer1 = (void *)magic1;
> >>>> +    struct C1 *outest1 = (void *)magic2;
> >>>> +
> >>>> +    expect(__builtin_object_size(&outer1->a, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest1->b, 1), -1);
> >>>> +    expect(__builtin_object_size(&outest1->b.a, 1), -1);
> >>>> +
> >>>> +    struct Bn *outern = (void *)magic1;
> >>>> +    struct Cn *outestn = (void *)magic2;
> >>>> +
> >>>> +    expect(__builtin_object_size(&outern->a, 1), -1);
> >>>> +    expect(__builtin_object_size(&outestn->b, 1), -1);
> >>>> +    expect(__builtin_object_size(&outestn->b.a, 1), -1);
> >>>> +
> >>>> +    if (n_fails > 0)
> >>>> +      __builtin_abort ();
> >>>> +
> >>>> +    return 0;
> >>>> +}
> >>>> diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
> >>>> index 9a936a91983..56b78ca2a8c 100644
> >>>> --- a/gcc/tree-object-size.cc
> >>>> +++ b/gcc/tree-object-size.cc
> >>>> @@ -500,6 +500,42 @@ decl_init_size (tree decl, bool min)
> >>>>  return size;
> >>>> }
> >>>> 
> >>>> +/* Determine whether TYPE is a structure with a flexible array member
> >>>> +   per -fstrict-flex-array or a union containing such a structure
> >>>> +   (possibly recursively).  */
> >>>> +static bool
> >>>> +flexible_size_type_p (const_tree type)
> >>>> +{
> >>>> +  tree x = NULL_TREE;
> >>>> +  tree last = NULL_TREE;
> >>>> +  switch (TREE_CODE (type))
> >>>> +    {
> >>>> +    case RECORD_TYPE:
> >>>> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
> >>>> +	if (TREE_CODE (x) == FIELD_DECL)
> >>>> +	  last = x;
> >>>> +      if (last == NULL_TREE)
> >>>> +	return false;
> >>>> +      if (TREE_CODE (TREE_TYPE (last)) == ARRAY_TYPE
> >>>> +	  && !DECL_NOT_FLEXARRAY (last))
> >>>> +	return true;
> >>>> +      else if (TREE_CODE (TREE_TYPE (last)) == RECORD_TYPE
> >>>> +	       || TREE_CODE (TREE_TYPE (last)) == UNION_TYPE)
> >>>> +	return flexible_size_type_p (TREE_TYPE (last));
> >>> 
> >>> For types with many members this can become quite slow (IIRC we had
> >>> bugs about similar walks of all fields in types), and this function
> >>> looks like it's invoked multiple times on the same type per TU.
> >>> 
> >>> In principle the property is fixed at the time we lay out a record
> >>> type, so we might want to compute it at that time and record the
> >>> result.
> >> 
> >> You mean in FE? 
> > 
> > Yes, either in the frontend or in the middle-ends layout_type.
> > 
> >> Yes, that?s better and cleaner.
> >> 
> >> I will add one more field in the TYPE structure to record this information and check this field during middle end.
> >> 
> >> I had the same thought in the beginning, but not sure whether adding a 
> >> new field in IR is necessary or not, other places in middle end might 
> >> not use this new field.
> > 
> > It might be interesting to search for other code walking all fields of
> > a type to determine this or similar info.
> 
> There is one which is defined in tree.cc but only is referenced in c/c-decl.cc:
> 
> /* Determine whether TYPE is a structure with a flexible array member,
>    or a union containing such a structure (possibly recursively).  */
> flexible_array_type_p
> 
> However, this routine is a little different than the one I tried to add:
> 
> In the current routine ?flexible_array_type_p?,  only one level nesting in the structure is accepted, multiple nesting in structure is not permitted.
> 
> So, my question is:  shall we accept multiple nesting in structure? i.e.

If we don't reject the testcase with an error, then yes.

> struct A {
>   int n;
>   char data[];/* Content following header */
> };
> 
> struct B {
>   int m;
>   struct A a;
> };
> 
> struct C {
>   int q;
>   struct B b;
> };
> 
> Qing
> > 
> >> thanks.
> >> 
> >> Qing
> >> 
> >>> 
> >>>> +      return false;
> >>>> +    case UNION_TYPE:
> >>>> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
> >>>> +	{
> >>>> +	  if (TREE_CODE (x) == FIELD_DECL
> >>>> +	      && flexible_array_type_p (TREE_TYPE (x)))
> >>>> +	    return true;
> >>>> +	}
> >>>> +      return false;
> >>>> +    default:
> >>>> +      return false;
> >>>> +  }
> >>>> +}
> >>>> +
> >>>> /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
> >>>>   OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
> >>>>   If unknown, return size_unknown (object_size_type).  */
> >>>> @@ -633,45 +669,68 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
> >>>> 		    v = NULL_TREE;
> >>>> 		    break;
> >>>> 		  case COMPONENT_REF:
> >>>> -		    if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
> >>>> +		    /* When the ref is not to an array, a record or a union, it
> >>>> +		       will not have flexible size, compute the object size
> >>>> +		       directly.  */
> >>>> +		    if ((TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
> >>>> +			&& (TREE_CODE (TREE_TYPE (v)) != RECORD_TYPE)
> >>>> +			&& (TREE_CODE (TREE_TYPE (v)) != UNION_TYPE))
> >>>> 		      {
> >>>> 			v = NULL_TREE;
> >>>> 			break;
> >>>> 		      }
> >>>> -		    is_flexible_array_mem_ref = array_ref_flexible_size_p (v);
> >>>> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> >>>> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>> -			  != UNION_TYPE
> >>>> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>> -			  != QUAL_UNION_TYPE)
> >>>> -			break;
> >>>> -		      else
> >>>> -			v = TREE_OPERAND (v, 0);
> >>>> -		    if (TREE_CODE (v) == COMPONENT_REF
> >>>> -			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>> -			   == RECORD_TYPE)
> >>>> +		    /* if the record or union does not have flexible size
> >>>> +		       compute the object size directly.  */
> >>>> +		    if (TREE_CODE (TREE_TYPE (v)) == RECORD_TYPE
> >>>> +			|| TREE_CODE (TREE_TYPE (v)) == UNION_TYPE)
> >>>> 		      {
> >>>> -			/* compute object size only if v is not a
> >>>> -			   flexible array member.  */
> >>>> -			if (!is_flexible_array_mem_ref)
> >>>> +			if (!flexible_size_type_p (TREE_TYPE (v)))
> >>>> 			  {
> >>>> 			    v = NULL_TREE;
> >>>> 			    break;
> >>>> 			  }
> >>>> -			v = TREE_OPERAND (v, 0);
> >>>> +			else
> >>>> +			  v = TREE_OPERAND (v, 0);
> >>>> 		      }
> >>>> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> >>>> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>> -			  != UNION_TYPE
> >>>> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>> -			  != QUAL_UNION_TYPE)
> >>>> -			break;
> >>>> -		      else
> >>>> -			v = TREE_OPERAND (v, 0);
> >>>> -		    if (v != pt_var)
> >>>> -		      v = NULL_TREE;
> >>>> 		    else
> >>>> -		      v = pt_var;
> >>>> +		      {
> >>>> +			/* Now the ref is to an array type.  */
> >>>> +			is_flexible_array_mem_ref
> >>>> +			  = array_ref_flexible_size_p (v);
> >>>> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> >>>> +			if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>> +			      != UNION_TYPE
> >>>> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>> +				 != QUAL_UNION_TYPE)
> >>>> +			  break;
> >>>> +			else
> >>>> +			  v = TREE_OPERAND (v, 0);
> >>>> +			if (TREE_CODE (v) == COMPONENT_REF
> >>>> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>> +				 == RECORD_TYPE)
> >>>> +			  {
> >>>> +			    /* compute object size only if v is not a
> >>>> +			       flexible array member.  */
> >>>> +			    if (!is_flexible_array_mem_ref)
> >>>> +			      {
> >>>> +				v = NULL_TREE;
> >>>> +				break;
> >>>> +			      }
> >>>> +			    v = TREE_OPERAND (v, 0);
> >>>> +			  }
> >>>> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> >>>> +			  if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>> +				!= UNION_TYPE
> >>>> +			      && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>> +				   != QUAL_UNION_TYPE)
> >>>> +			    break;
> >>>> +			  else
> >>>> +			    v = TREE_OPERAND (v, 0);
> >>>> +			if (v != pt_var)
> >>>> +			  v = NULL_TREE;
> >>>> +			else
> >>>> +			  v = pt_var;
> >>>> +		      }
> >>>> 		    break;
> >>>> 		  default:
> >>>> 		    v = pt_var;
> >>>> 
> >>> 
> >>> -- 
> >>> Richard Biener <rguenther@suse.de>
> >>> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
> >>> Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
> >>> HRB 36809 (AG Nuernberg)
> >> 
> >> 
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
> > Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
> > HRB 36809 (AG Nuernberg)
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
HRB 36809 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/2] Documentation Update.
  2023-02-02  8:33         ` Richard Biener
@ 2023-02-02 14:31           ` Qing Zhao
  2023-02-02 17:05             ` Kees Cook
  2023-02-03  4:25           ` Siddhesh Poyarekar
  1 sibling, 1 reply; 45+ messages in thread
From: Qing Zhao @ 2023-02-02 14:31 UTC (permalink / raw)
  To: Richard Biener; +Cc: Siddhesh Poyarekar, gcc Patches, keescook, Joseph S. Myers



> On Feb 2, 2023, at 3:33 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Wed, 1 Feb 2023, Siddhesh Poyarekar wrote:
> 
>> On 2023-02-01 13:24, Qing Zhao wrote:
>>> 
>>> 
>>>> On Feb 1, 2023, at 11:55 AM, Siddhesh Poyarekar <siddhesh@gotplt.org>
>>>> wrote:
>>>> 
>>>> On 2023-01-31 09:11, Qing Zhao wrote:
>>>>> Update documentation to clarify a GCC extension on structure with
>>>>> flexible array member being nested in another structure.
>>>>> gcc/ChangeLog:
>>>>> * doc/extend.texi: Document GCC extension on a structure containing
>>>>> a flexible array member to be a member of another structure.
>>>> 
>>>> Should this resolve pr#77650 since the proposed action there appears to be
>>>> to document these semantics?
>>> 
>>> My understanding of pr77650 is specifically for documentation on the
>>> following case:
>>> 
>>> The structure with a flexible array member is the middle field of another
>>> structure.
>>> 
>>> Which I added in the documentation as the 2nd situation.
>>> However, I am still not very comfortable on my current clarification on this
>>> situation: how should we document on
>>> the expected gcc behavior to handle such situation?
>> 
>> I reckon wording that dissuades programmers from using this might be
>> appropriate, i.e. don't rely on this and if you already have such nested flex
>> arrays, change code to remove them.
>> 
>>>>> +In the above, @code{flex_data.data[]} is allowed to be extended flexibly
>>>>> to
>>>>> +the padding. E.g, up to 4 elements.
>> 
>> """
>> ... Relying on space in struct padding is bad programming practice and any
>> code relying on this behaviour should be modified to ensure that flexible
>> array members only end up at the ends of arrays.  The `-pedantic` flag should
>> help identify such uses.
>> """
>> 
>> Although -pedantic will also flag on flex arrays nested in structs even if
>> they're at the end of the parent struct, so my suggestion on the warning is
>> not really perfect.
> 
> Wow, so I checked and we indeed accept
> 
> struct X { int n; int data[]; };
> struct Y { struct X x; int end; };
> 
> and -pedantic says
> 
> t.c:2:21: warning: invalid use of structure with flexible array member 
> [-Wpedantic]
>    2 | struct Y { struct X x; int end; };
>      |    

Currently, -pedantic report the same message for flex arrays nested in structs at the end of the parent struct AND in the middle of the parent struct. 
Shall we distinguish them and report different warning messages in order to discourage the latter case? 

And at the same time, in the documentation, clarify these two situations, and discourage the latter case at the same time as well?
>       
> 
> and clang reports
> 
> t.c:2:21: warning: field 'x' with variable sized type 'struct X' not at 
> the end of a struct or class is a GNU extension 
> [-Wgnu-variable-sized-type-not-at-end]
> struct Y { struct X x; int end; };
>  
>                  ^

Clang’s warning message is clearer. 
> 
> looking at PR77650 what seems missing there is the semantics of this
> extension as expected/required by the glibc use.  comment#5 seems
> to suggest that for my example above its expected that
> Y.x.data[0] aliases Y.end?!

Should we mentioned this alias relationship in the doc?

>  There must be a better way to write
> the glibc code and IMHO it would be best to deprecate this extension.

Agreed. This is really a bad practice, should be deprecated. 
We can give warning first in this release, and then deprecate this extension in a latter release. 

> Definitely the middle-end wouldn't consider this aliasing for
> my example - maybe it "works" when wrapped inside a union but
> then for sure only when the union is visible in all accesses ...
> 
> typedef union
> {
>  struct __gconv_info __cd;
>  struct
>  {
>    struct __gconv_info __cd;
>    struct __gconv_step_data __data;
>  } __combined;
> } _G_iconv_t;
> 
> could be written as
> 
> typedef union
> {
>  struct __gconv_info __cd;
>  char __dummy[sizeof(struct __gconv_info) + sizeof(struct 
> __gconv_step_data)];
> } _G_iconv_t;
> 
> in case the intent is to provide a complete type with space for
> a single __gconv_step_data.

Since the current middle end doesn’t handle such case consistently, what should we document this case? 
Or just mentioned this case is not handled consistently in the compiler and will be deprecated in the future, 
 user should not depend on it and should rewrite their code?

I don’t think it worth the effort to update GCC to consistently handle this case in general.

What’s your opinion?

Qing


> 
> Richard.


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-02 13:54           ` Richard Biener
@ 2023-02-02 14:38             ` Qing Zhao
  2023-02-03  7:49               ` Richard Biener
  0 siblings, 1 reply; 45+ messages in thread
From: Qing Zhao @ 2023-02-02 14:38 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches, siddhesh, keescook



> On Feb 2, 2023, at 8:54 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Thu, 2 Feb 2023, Qing Zhao wrote:
> 
>> 
>> 
>>> On Feb 2, 2023, at 3:07 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On Wed, 1 Feb 2023, Qing Zhao wrote:
>>> 
>>>> 
>>>> 
>>>>> On Feb 1, 2023, at 6:41 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>> 
>>>>> On Tue, 31 Jan 2023, Qing Zhao wrote:
>>>>> 
>>>>>> GCC extension accepts the case when a struct with a flexible array member
>>>>>> is embedded into another struct (possibly recursively).
>>>>>> __builtin_object_size should treat such struct as flexible size per
>>>>>> -fstrict-flex-arrays.
>>>>>> 
>>>>>> 	PR tree-optimization/101832
>>>>>> 
>>>>>> gcc/ChangeLog:
>>>>>> 
>>>>>> 	PR tree-optimization/101832
>>>>>> 	* tree-object-size.cc (flexible_size_type_p): New function.
>>>>>> 	(addr_object_size): Handle structure/union type when it has
>>>>>> 	flexible size.
>>>>>> 
>>>>>> gcc/testsuite/ChangeLog:
>>>>>> 
>>>>>> 	PR tree-optimization/101832
>>>>>> 	* gcc.dg/builtin-object-size-pr101832-2.c: New test.
>>>>>> 	* gcc.dg/builtin-object-size-pr101832-3.c: New test.
>>>>>> 	* gcc.dg/builtin-object-size-pr101832-4.c: New test.
>>>>>> 	* gcc.dg/builtin-object-size-pr101832.c: New test.
>>>>>> ---
>>>>>> .../gcc.dg/builtin-object-size-pr101832-2.c   | 135 ++++++++++++++++++
>>>>>> .../gcc.dg/builtin-object-size-pr101832-3.c   | 135 ++++++++++++++++++
>>>>>> .../gcc.dg/builtin-object-size-pr101832-4.c   | 135 ++++++++++++++++++
>>>>>> .../gcc.dg/builtin-object-size-pr101832.c     | 119 +++++++++++++++
>>>>>> gcc/tree-object-size.cc                       | 115 +++++++++++----
>>>>>> 5 files changed, 611 insertions(+), 28 deletions(-)
>>>>>> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
>>>>>> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
>>>>>> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
>>>>>> create mode 100644 gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
>>>>>> 
>>>>>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
>>>>>> new file mode 100644
>>>>>> index 00000000000..f38babc5415
>>>>>> --- /dev/null
>>>>>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-2.c
>>>>>> @@ -0,0 +1,135 @@
>>>>>> +/* PR 101832: 
>>>>>> +   GCC extension accepts the case when a struct with a flexible array member
>>>>>> +   is embedded into another struct (possibly recursively).
>>>>>> +   __builtin_object_size will treat such struct as flexible size per
>>>>>> +   -fstrict-flex-arrays.  */ 
>>>>>> +/* { dg-do run } */
>>>>>> +/* { dg-options "-O2 -fstrict-flex-arrays=1" } */
>>>>>> +
>>>>>> +#include <stdio.h>
>>>>>> +
>>>>>> +unsigned n_fails = 0;
>>>>>> +
>>>>>> +#define expect(p, _v) do { \
>>>>>> +  size_t v = _v; \
>>>>>> +  if (p == v) \
>>>>>> +    printf("ok:  %s == %zd\n", #p, p); \
>>>>>> +  else {\
>>>>>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
>>>>>> +    n_fails++; \
>>>>>> +  } \
>>>>>> +} while (0);
>>>>>> +
>>>>>> +struct A {
>>>>>> +  int n;
>>>>>> +  char data[];/* Content following header */
>>>>>> +};
>>>>>> +
>>>>>> +struct B {
>>>>>> +  int m;
>>>>>> +  struct A a;
>>>>>> +};
>>>>>> +
>>>>>> +struct C {
>>>>>> +  int q;
>>>>>> +  struct B b;
>>>>>> +};
>>>>>> +
>>>>>> +struct A0 {
>>>>>> +  int n;
>>>>>> +  char data[0];/* Content following header */
>>>>>> +};
>>>>>> +
>>>>>> +struct B0 {
>>>>>> +  int m;
>>>>>> +  struct A0 a;
>>>>>> +};
>>>>>> +
>>>>>> +struct C0 {
>>>>>> +  int q;
>>>>>> +  struct B0 b;
>>>>>> +};
>>>>>> +
>>>>>> +struct A1 {
>>>>>> +  int n;
>>>>>> +  char data[1];/* Content following header */
>>>>>> +};
>>>>>> +
>>>>>> +struct B1 {
>>>>>> +  int m;
>>>>>> +  struct A1 a;
>>>>>> +};
>>>>>> +
>>>>>> +struct C1 {
>>>>>> +  int q;
>>>>>> +  struct B1 b;
>>>>>> +};
>>>>>> +
>>>>>> +struct An {
>>>>>> +  int n;
>>>>>> +  char data[8];/* Content following header */
>>>>>> +};
>>>>>> +
>>>>>> +struct Bn {
>>>>>> +  int m;
>>>>>> +  struct An a;
>>>>>> +};
>>>>>> +
>>>>>> +struct Cn {
>>>>>> +  int q;
>>>>>> +  struct Bn b;
>>>>>> +};
>>>>>> +
>>>>>> +volatile void *magic1, *magic2;
>>>>>> +
>>>>>> +int main(int argc, char *argv[])
>>>>>> +{
>>>>>> +    struct B *outer;
>>>>>> +    struct C *outest;
>>>>>> +
>>>>>> +    /* Make sure optimization can't find some other object size. */
>>>>>> +    outer = (void *)magic1;
>>>>>> +    outest = (void *)magic2;
>>>>>> +
>>>>>> +    expect(__builtin_object_size(&outer->a, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest->b, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
>>>>>> +
>>>>>> +    struct B0 *outer0;
>>>>>> +    struct C0 *outest0;
>>>>>> +
>>>>>> +    /* Make sure optimization can't find some other object size. */
>>>>>> +    outer0 = (void *)magic1;
>>>>>> +    outest0 = (void *)magic2;
>>>>>> +
>>>>>> +    expect(__builtin_object_size(&outer0->a, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest0->b, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
>>>>>> +
>>>>>> +    struct B1 *outer1;
>>>>>> +    struct C1 *outest1;
>>>>>> +
>>>>>> +    /* Make sure optimization can't find some other object size. */
>>>>>> +    outer1 = (void *)magic1;
>>>>>> +    outest1 = (void *)magic2;
>>>>>> +
>>>>>> +    expect(__builtin_object_size(&outer1->a, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest1->b, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest1->b.a, 1), -1);
>>>>>> +
>>>>>> +    struct Bn *outern;
>>>>>> +    struct Cn *outestn;
>>>>>> +
>>>>>> +    /* Make sure optimization can't find some other object size. */
>>>>>> +    outern = (void *)magic1;
>>>>>> +    outestn = (void *)magic2;
>>>>>> +
>>>>>> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
>>>>>> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
>>>>>> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
>>>>>> +
>>>>>> +    if (n_fails > 0)
>>>>>> +      __builtin_abort ();
>>>>>> +
>>>>>> +    return 0;
>>>>>> +}
>>>>>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
>>>>>> new file mode 100644
>>>>>> index 00000000000..aaae99b8d67
>>>>>> --- /dev/null
>>>>>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-3.c
>>>>>> @@ -0,0 +1,135 @@
>>>>>> +/* PR 101832: 
>>>>>> +   GCC extension accepts the case when a struct with a flexible array member
>>>>>> +   is embedded into another struct (possibly recursively).
>>>>>> +   __builtin_object_size will treat such struct as flexible size per
>>>>>> +   -fstrict-flex-arrays.  */
>>>>>> +/* { dg-do run } */
>>>>>> +/* { dg-options "-O2 -fstrict-flex-arrays=2" } */
>>>>>> +
>>>>>> +#include <stdio.h>
>>>>>> +
>>>>>> +unsigned n_fails = 0;
>>>>>> +
>>>>>> +#define expect(p, _v) do { \
>>>>>> +  size_t v = _v; \
>>>>>> +  if (p == v) \
>>>>>> +    printf("ok:  %s == %zd\n", #p, p); \
>>>>>> +  else {\
>>>>>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
>>>>>> +    n_fails++; \
>>>>>> +  } \
>>>>>> +} while (0);
>>>>>> +
>>>>>> +struct A {
>>>>>> +  int n;
>>>>>> +  char data[];/* Content following header */
>>>>>> +};
>>>>>> +
>>>>>> +struct B {
>>>>>> +  int m;
>>>>>> +  struct A a;
>>>>>> +};
>>>>>> +
>>>>>> +struct C {
>>>>>> +  int q;
>>>>>> +  struct B b;
>>>>>> +};
>>>>>> +
>>>>>> +struct A0 {
>>>>>> +  int n;
>>>>>> +  char data[0];/* Content following header */
>>>>>> +};
>>>>>> +
>>>>>> +struct B0 {
>>>>>> +  int m;
>>>>>> +  struct A0 a;
>>>>>> +};
>>>>>> +
>>>>>> +struct C0 {
>>>>>> +  int q;
>>>>>> +  struct B0 b;
>>>>>> +};
>>>>>> +
>>>>>> +struct A1 {
>>>>>> +  int n;
>>>>>> +  char data[1];/* Content following header */
>>>>>> +};
>>>>>> +
>>>>>> +struct B1 {
>>>>>> +  int m;
>>>>>> +  struct A1 a;
>>>>>> +};
>>>>>> +
>>>>>> +struct C1 {
>>>>>> +  int q;
>>>>>> +  struct B1 b;
>>>>>> +};
>>>>>> +
>>>>>> +struct An {
>>>>>> +  int n;
>>>>>> +  char data[8];/* Content following header */
>>>>>> +};
>>>>>> +
>>>>>> +struct Bn {
>>>>>> +  int m;
>>>>>> +  struct An a;
>>>>>> +};
>>>>>> +
>>>>>> +struct Cn {
>>>>>> +  int q;
>>>>>> +  struct Bn b;
>>>>>> +};
>>>>>> +
>>>>>> +volatile void *magic1, *magic2;
>>>>>> +
>>>>>> +int main(int argc, char *argv[])
>>>>>> +{
>>>>>> +    struct B *outer;
>>>>>> +    struct C *outest;
>>>>>> +
>>>>>> +    /* Make sure optimization can't find some other object size. */
>>>>>> +    outer = (void *)magic1;
>>>>>> +    outest = (void *)magic2;
>>>>>> +
>>>>>> +    expect(__builtin_object_size(&outer->a, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest->b, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
>>>>>> +
>>>>>> +    struct B0 *outer0;
>>>>>> +    struct C0 *outest0;
>>>>>> +
>>>>>> +    /* Make sure optimization can't find some other object size. */
>>>>>> +    outer0 = (void *)magic1;
>>>>>> +    outest0 = (void *)magic2;
>>>>>> +
>>>>>> +    expect(__builtin_object_size(&outer0->a, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest0->b, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
>>>>>> +
>>>>>> +    struct B1 *outer1;
>>>>>> +    struct C1 *outest1;
>>>>>> +
>>>>>> +    /* Make sure optimization can't find some other object size. */
>>>>>> +    outer1 = (void *)magic1;
>>>>>> +    outest1 = (void *)magic2;
>>>>>> +
>>>>>> +    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
>>>>>> +    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
>>>>>> +    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
>>>>>> +
>>>>>> +    struct Bn *outern;
>>>>>> +    struct Cn *outestn;
>>>>>> +
>>>>>> +    /* Make sure optimization can't find some other object size. */
>>>>>> +    outern = (void *)magic1;
>>>>>> +    outestn = (void *)magic2;
>>>>>> +
>>>>>> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
>>>>>> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
>>>>>> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
>>>>>> +
>>>>>> +    if (n_fails > 0)
>>>>>> +      __builtin_abort ();
>>>>>> +
>>>>>> +    return 0;
>>>>>> +}
>>>>>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
>>>>>> new file mode 100644
>>>>>> index 00000000000..424264e2acd
>>>>>> --- /dev/null
>>>>>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832-4.c
>>>>>> @@ -0,0 +1,135 @@
>>>>>> +/* PR 101832: 
>>>>>> +   GCC extension accepts the case when a struct with a flexible array member
>>>>>> +   is embedded into another struct (possibly recursively).
>>>>>> +   __builtin_object_size will treat such struct as flexible size per
>>>>>> +   -fstrict-flex-arrays.  */
>>>>>> +/* { dg-do run } */
>>>>>> +/* { dg-options "-O2 -fstrict-flex-arrays=3" } */
>>>>>> +
>>>>>> +#include <stdio.h>
>>>>>> +
>>>>>> +unsigned n_fails = 0;
>>>>>> +
>>>>>> +#define expect(p, _v) do { \
>>>>>> +  size_t v = _v; \
>>>>>> +  if (p == v) \
>>>>>> +    printf("ok:  %s == %zd\n", #p, p); \
>>>>>> +  else {\
>>>>>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
>>>>>> +    n_fails++; \
>>>>>> +  } \
>>>>>> +} while (0);
>>>>>> +
>>>>>> +struct A {
>>>>>> +  int n;
>>>>>> +  char data[];/* Content following header */
>>>>>> +};
>>>>>> +
>>>>>> +struct B {
>>>>>> +  int m;
>>>>>> +  struct A a;
>>>>>> +};
>>>>>> +
>>>>>> +struct C {
>>>>>> +  int q;
>>>>>> +  struct B b;
>>>>>> +};
>>>>>> +
>>>>>> +struct A0 {
>>>>>> +  int n;
>>>>>> +  char data[0];/* Content following header */
>>>>>> +};
>>>>>> +
>>>>>> +struct B0 {
>>>>>> +  int m;
>>>>>> +  struct A0 a;
>>>>>> +};
>>>>>> +
>>>>>> +struct C0 {
>>>>>> +  int q;
>>>>>> +  struct B0 b;
>>>>>> +};
>>>>>> +
>>>>>> +struct A1 {
>>>>>> +  int n;
>>>>>> +  char data[1];/* Content following header */
>>>>>> +};
>>>>>> +
>>>>>> +struct B1 {
>>>>>> +  int m;
>>>>>> +  struct A1 a;
>>>>>> +};
>>>>>> +
>>>>>> +struct C1 {
>>>>>> +  int q;
>>>>>> +  struct B1 b;
>>>>>> +};
>>>>>> +
>>>>>> +struct An {
>>>>>> +  int n;
>>>>>> +  char data[8];/* Content following header */
>>>>>> +};
>>>>>> +
>>>>>> +struct Bn {
>>>>>> +  int m;
>>>>>> +  struct An a;
>>>>>> +};
>>>>>> +
>>>>>> +struct Cn {
>>>>>> +  int q;
>>>>>> +  struct Bn b;
>>>>>> +};
>>>>>> +
>>>>>> +volatile void *magic1, *magic2;
>>>>>> +
>>>>>> +int main(int argc, char *argv[])
>>>>>> +{
>>>>>> +    struct B *outer;
>>>>>> +    struct C *outest;
>>>>>> +
>>>>>> +    /* Make sure optimization can't find some other object size. */
>>>>>> +    outer = (void *)magic1;
>>>>>> +    outest = (void *)magic2;
>>>>>> +
>>>>>> +    expect(__builtin_object_size(&outer->a, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest->b, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
>>>>>> +
>>>>>> +    struct B0 *outer0;
>>>>>> +    struct C0 *outest0;
>>>>>> +
>>>>>> +    /* Make sure optimization can't find some other object size. */
>>>>>> +    outer0 = (void *)magic1;
>>>>>> +    outest0 = (void *)magic2;
>>>>>> +
>>>>>> +    expect(__builtin_object_size(&outer0->a, 1), sizeof(outer0->a));
>>>>>> +    expect(__builtin_object_size(&outest0->b, 1), sizeof(outest0->b));
>>>>>> +    expect(__builtin_object_size(&outest0->b.a, 1), sizeof(outest0->b.a));
>>>>>> +
>>>>>> +    struct B1 *outer1;
>>>>>> +    struct C1 *outest1;
>>>>>> +
>>>>>> +    /* Make sure optimization can't find some other object size. */
>>>>>> +    outer1 = (void *)magic1;
>>>>>> +    outest1 = (void *)magic2;
>>>>>> +
>>>>>> +    expect(__builtin_object_size(&outer1->a, 1), sizeof(outer1->a));
>>>>>> +    expect(__builtin_object_size(&outest1->b, 1), sizeof(outest1->b));
>>>>>> +    expect(__builtin_object_size(&outest1->b.a, 1), sizeof(outest1->b.a));
>>>>>> +
>>>>>> +    struct Bn *outern;
>>>>>> +    struct Cn *outestn;
>>>>>> +
>>>>>> +    /* Make sure optimization can't find some other object size. */
>>>>>> +    outern = (void *)magic1;
>>>>>> +    outestn = (void *)magic2;
>>>>>> +
>>>>>> +    expect(__builtin_object_size(&outern->a, 1), sizeof(outern->a));
>>>>>> +    expect(__builtin_object_size(&outestn->b, 1), sizeof(outestn->b));
>>>>>> +    expect(__builtin_object_size(&outestn->b.a, 1), sizeof(outestn->b.a));
>>>>>> +
>>>>>> +    if (n_fails > 0)
>>>>>> +      __builtin_abort ();
>>>>>> +
>>>>>> +    return 0;
>>>>>> +}
>>>>>> diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
>>>>>> new file mode 100644
>>>>>> index 00000000000..8ed6980edf0
>>>>>> --- /dev/null
>>>>>> +++ b/gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
>>>>>> @@ -0,0 +1,119 @@
>>>>>> +/* PR 101832: 
>>>>>> +   GCC extension accepts the case when a struct with a flexible array member
>>>>>> +   is embedded into another struct (possibly recursively).
>>>>>> +   __builtin_object_size will treat such struct as flexible size per
>>>>>> +   -fstrict-flex-arrays.  */
>>>>>> +/* { dg-do run } */
>>>>>> +/* { dg-options "-O2" } */
>>>>>> +
>>>>>> +#include <stdio.h>
>>>>>> +
>>>>>> +unsigned n_fails = 0;
>>>>>> +
>>>>>> +#define expect(p, _v) do { \
>>>>>> +  size_t v = _v; \
>>>>>> +  if (p == v) \
>>>>>> +    printf("ok:  %s == %zd\n", #p, p); \
>>>>>> +  else {\
>>>>>> +    printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
>>>>>> +    n_fails++; \
>>>>>> +  } \
>>>>>> +} while (0);
>>>>>> +
>>>>>> +struct A {
>>>>>> +  int n;
>>>>>> +  char data[];/* Content following header */
>>>>>> +};
>>>>>> +
>>>>>> +struct B {
>>>>>> +  int m;
>>>>>> +  struct A a;
>>>>>> +};
>>>>>> +
>>>>>> +struct C {
>>>>>> +  int q;
>>>>>> +  struct B b;
>>>>>> +};
>>>>>> +
>>>>>> +struct A0 {
>>>>>> +  int n;
>>>>>> +  char data[0];/* Content following header */
>>>>>> +};
>>>>>> +
>>>>>> +struct B0 {
>>>>>> +  int m;
>>>>>> +  struct A0 a;
>>>>>> +};
>>>>>> +
>>>>>> +struct C0 {
>>>>>> +  int q;
>>>>>> +  struct B0 b;
>>>>>> +};
>>>>>> +
>>>>>> +struct A1 {
>>>>>> +  int n;
>>>>>> +  char data[1];/* Content following header */
>>>>>> +};
>>>>>> +
>>>>>> +struct B1 {
>>>>>> +  int m;
>>>>>> +  struct A1 a;
>>>>>> +};
>>>>>> +
>>>>>> +struct C1 {
>>>>>> +  int q;
>>>>>> +  struct B1 b;
>>>>>> +};
>>>>>> +
>>>>>> +struct An {
>>>>>> +  int n;
>>>>>> +  char data[8];/* Content following header */
>>>>>> +};
>>>>>> +
>>>>>> +struct Bn {
>>>>>> +  int m;
>>>>>> +  struct An a;
>>>>>> +};
>>>>>> +
>>>>>> +struct Cn {
>>>>>> +  int q;
>>>>>> +  struct Bn b;
>>>>>> +};
>>>>>> +
>>>>>> +volatile void *magic1, *magic2;
>>>>>> +
>>>>>> +int main(int argc, char *argv[])
>>>>>> +{
>>>>>> +    struct B *outer = (void *)magic1;
>>>>>> +    struct C *outest = (void *)magic2;
>>>>>> +
>>>>>> +    expect(__builtin_object_size(&outer->a, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest->b, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest->b.a, 1), -1);
>>>>>> +
>>>>>> +    struct B0 *outer0 = (void *)magic1;
>>>>>> +    struct C0 *outest0 = (void *)magic2;
>>>>>> +
>>>>>> +    expect(__builtin_object_size(&outer0->a, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest0->b, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest0->b.a, 1), -1);
>>>>>> +
>>>>>> +    struct B1 *outer1 = (void *)magic1;
>>>>>> +    struct C1 *outest1 = (void *)magic2;
>>>>>> +
>>>>>> +    expect(__builtin_object_size(&outer1->a, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest1->b, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outest1->b.a, 1), -1);
>>>>>> +
>>>>>> +    struct Bn *outern = (void *)magic1;
>>>>>> +    struct Cn *outestn = (void *)magic2;
>>>>>> +
>>>>>> +    expect(__builtin_object_size(&outern->a, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outestn->b, 1), -1);
>>>>>> +    expect(__builtin_object_size(&outestn->b.a, 1), -1);
>>>>>> +
>>>>>> +    if (n_fails > 0)
>>>>>> +      __builtin_abort ();
>>>>>> +
>>>>>> +    return 0;
>>>>>> +}
>>>>>> diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
>>>>>> index 9a936a91983..56b78ca2a8c 100644
>>>>>> --- a/gcc/tree-object-size.cc
>>>>>> +++ b/gcc/tree-object-size.cc
>>>>>> @@ -500,6 +500,42 @@ decl_init_size (tree decl, bool min)
>>>>>> return size;
>>>>>> }
>>>>>> 
>>>>>> +/* Determine whether TYPE is a structure with a flexible array member
>>>>>> +   per -fstrict-flex-array or a union containing such a structure
>>>>>> +   (possibly recursively).  */
>>>>>> +static bool
>>>>>> +flexible_size_type_p (const_tree type)
>>>>>> +{
>>>>>> +  tree x = NULL_TREE;
>>>>>> +  tree last = NULL_TREE;
>>>>>> +  switch (TREE_CODE (type))
>>>>>> +    {
>>>>>> +    case RECORD_TYPE:
>>>>>> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
>>>>>> +	if (TREE_CODE (x) == FIELD_DECL)
>>>>>> +	  last = x;
>>>>>> +      if (last == NULL_TREE)
>>>>>> +	return false;
>>>>>> +      if (TREE_CODE (TREE_TYPE (last)) == ARRAY_TYPE
>>>>>> +	  && !DECL_NOT_FLEXARRAY (last))
>>>>>> +	return true;
>>>>>> +      else if (TREE_CODE (TREE_TYPE (last)) == RECORD_TYPE
>>>>>> +	       || TREE_CODE (TREE_TYPE (last)) == UNION_TYPE)
>>>>>> +	return flexible_size_type_p (TREE_TYPE (last));
>>>>> 
>>>>> For types with many members this can become quite slow (IIRC we had
>>>>> bugs about similar walks of all fields in types), and this function
>>>>> looks like it's invoked multiple times on the same type per TU.
>>>>> 
>>>>> In principle the property is fixed at the time we lay out a record
>>>>> type, so we might want to compute it at that time and record the
>>>>> result.
>>>> 
>>>> You mean in FE? 
>>> 
>>> Yes, either in the frontend or in the middle-ends layout_type.
>>> 
>>>> Yes, that?s better and cleaner.
>>>> 
>>>> I will add one more field in the TYPE structure to record this information and check this field during middle end.
>>>> 
>>>> I had the same thought in the beginning, but not sure whether adding a 
>>>> new field in IR is necessary or not, other places in middle end might 
>>>> not use this new field.
>>> 
>>> It might be interesting to search for other code walking all fields of
>>> a type to determine this or similar info.
>> 
>> There is one which is defined in tree.cc but only is referenced in c/c-decl.cc:
>> 
>> /* Determine whether TYPE is a structure with a flexible array member,
>>   or a union containing such a structure (possibly recursively).  */
>> flexible_array_type_p
>> 
>> However, this routine is a little different than the one I tried to add:
>> 
>> In the current routine ?flexible_array_type_p?,  only one level nesting in the structure is accepted, multiple nesting in structure is not permitted.
>> 
>> So, my question is:  shall we accept multiple nesting in structure? i.e.
> 
> If we don't reject the testcase with an error, then yes.

Gcc currently accepts the multiple nesting in structure without error.  So, we will continue to accept such extension as long as the flex array is at the end of the structure.
At the same time, for the case the flex array is in the middle of the structure, issue additional warnings now to discourage such usage, and deprecate this case in a future release. 

Does this sound reasonable? 

Qing
> 
>> struct A {
>>  int n;
>>  char data[];/* Content following header */
>> };
>> 
>> struct B {
>>  int m;
>>  struct A a;
>> };
>> 
>> struct C {
>>  int q;
>>  struct B b;
>> };
>> 
>> Qing
>>> 
>>>> thanks.
>>>> 
>>>> Qing
>>>> 
>>>>> 
>>>>>> +      return false;
>>>>>> +    case UNION_TYPE:
>>>>>> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
>>>>>> +	{
>>>>>> +	  if (TREE_CODE (x) == FIELD_DECL
>>>>>> +	      && flexible_array_type_p (TREE_TYPE (x)))
>>>>>> +	    return true;
>>>>>> +	}
>>>>>> +      return false;
>>>>>> +    default:
>>>>>> +      return false;
>>>>>> +  }
>>>>>> +}
>>>>>> +
>>>>>> /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
>>>>>>  OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
>>>>>>  If unknown, return size_unknown (object_size_type).  */
>>>>>> @@ -633,45 +669,68 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
>>>>>> 		    v = NULL_TREE;
>>>>>> 		    break;
>>>>>> 		  case COMPONENT_REF:
>>>>>> -		    if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
>>>>>> +		    /* When the ref is not to an array, a record or a union, it
>>>>>> +		       will not have flexible size, compute the object size
>>>>>> +		       directly.  */
>>>>>> +		    if ((TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
>>>>>> +			&& (TREE_CODE (TREE_TYPE (v)) != RECORD_TYPE)
>>>>>> +			&& (TREE_CODE (TREE_TYPE (v)) != UNION_TYPE))
>>>>>> 		      {
>>>>>> 			v = NULL_TREE;
>>>>>> 			break;
>>>>>> 		      }
>>>>>> -		    is_flexible_array_mem_ref = array_ref_flexible_size_p (v);
>>>>>> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>>>>>> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>> -			  != UNION_TYPE
>>>>>> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>> -			  != QUAL_UNION_TYPE)
>>>>>> -			break;
>>>>>> -		      else
>>>>>> -			v = TREE_OPERAND (v, 0);
>>>>>> -		    if (TREE_CODE (v) == COMPONENT_REF
>>>>>> -			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>> -			   == RECORD_TYPE)
>>>>>> +		    /* if the record or union does not have flexible size
>>>>>> +		       compute the object size directly.  */
>>>>>> +		    if (TREE_CODE (TREE_TYPE (v)) == RECORD_TYPE
>>>>>> +			|| TREE_CODE (TREE_TYPE (v)) == UNION_TYPE)
>>>>>> 		      {
>>>>>> -			/* compute object size only if v is not a
>>>>>> -			   flexible array member.  */
>>>>>> -			if (!is_flexible_array_mem_ref)
>>>>>> +			if (!flexible_size_type_p (TREE_TYPE (v)))
>>>>>> 			  {
>>>>>> 			    v = NULL_TREE;
>>>>>> 			    break;
>>>>>> 			  }
>>>>>> -			v = TREE_OPERAND (v, 0);
>>>>>> +			else
>>>>>> +			  v = TREE_OPERAND (v, 0);
>>>>>> 		      }
>>>>>> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>>>>>> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>> -			  != UNION_TYPE
>>>>>> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>> -			  != QUAL_UNION_TYPE)
>>>>>> -			break;
>>>>>> -		      else
>>>>>> -			v = TREE_OPERAND (v, 0);
>>>>>> -		    if (v != pt_var)
>>>>>> -		      v = NULL_TREE;
>>>>>> 		    else
>>>>>> -		      v = pt_var;
>>>>>> +		      {
>>>>>> +			/* Now the ref is to an array type.  */
>>>>>> +			is_flexible_array_mem_ref
>>>>>> +			  = array_ref_flexible_size_p (v);
>>>>>> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>>>>>> +			if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>> +			      != UNION_TYPE
>>>>>> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>> +				 != QUAL_UNION_TYPE)
>>>>>> +			  break;
>>>>>> +			else
>>>>>> +			  v = TREE_OPERAND (v, 0);
>>>>>> +			if (TREE_CODE (v) == COMPONENT_REF
>>>>>> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>> +				 == RECORD_TYPE)
>>>>>> +			  {
>>>>>> +			    /* compute object size only if v is not a
>>>>>> +			       flexible array member.  */
>>>>>> +			    if (!is_flexible_array_mem_ref)
>>>>>> +			      {
>>>>>> +				v = NULL_TREE;
>>>>>> +				break;
>>>>>> +			      }
>>>>>> +			    v = TREE_OPERAND (v, 0);
>>>>>> +			  }
>>>>>> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>>>>>> +			  if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>> +				!= UNION_TYPE
>>>>>> +			      && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>> +				   != QUAL_UNION_TYPE)
>>>>>> +			    break;
>>>>>> +			  else
>>>>>> +			    v = TREE_OPERAND (v, 0);
>>>>>> +			if (v != pt_var)
>>>>>> +			  v = NULL_TREE;
>>>>>> +			else
>>>>>> +			  v = pt_var;
>>>>>> +		      }
>>>>>> 		    break;
>>>>>> 		  default:
>>>>>> 		    v = pt_var;
>>>>>> 
>>>>> 
>>>>> -- 
>>>>> Richard Biener <rguenther@suse.de>
>>>>> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
>>>>> Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
>>>>> HRB 36809 (AG Nuernberg)
>>>> 
>>>> 
>>> 
>>> -- 
>>> Richard Biener <rguenther@suse.de>
>>> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
>>> Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
>>> HRB 36809 (AG Nuernberg)
>> 
>> 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
> Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
> HRB 36809 (AG Nuernberg)


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/2] Documentation Update.
  2023-02-02 14:31           ` Qing Zhao
@ 2023-02-02 17:05             ` Kees Cook
  2023-02-03 15:56               ` Jeff Law
  0 siblings, 1 reply; 45+ messages in thread
From: Kees Cook @ 2023-02-02 17:05 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Richard Biener, Siddhesh Poyarekar, gcc Patches, Joseph S. Myers

On Thu, Feb 02, 2023 at 02:31:53PM +0000, Qing Zhao wrote:
> 
> > On Feb 2, 2023, at 3:33 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Wed, 1 Feb 2023, Siddhesh Poyarekar wrote:
> > 
> >> On 2023-02-01 13:24, Qing Zhao wrote:
> >>> 
> >>> 
> >>>> On Feb 1, 2023, at 11:55 AM, Siddhesh Poyarekar <siddhesh@gotplt.org>
> >>>> wrote:
> >>>> 
> >>>> On 2023-01-31 09:11, Qing Zhao wrote:
> >>>>> Update documentation to clarify a GCC extension on structure with
> >>>>> flexible array member being nested in another structure.
> >>>>> gcc/ChangeLog:
> >>>>> * doc/extend.texi: Document GCC extension on a structure containing
> >>>>> a flexible array member to be a member of another structure.
> >>>> 
> >>>> Should this resolve pr#77650 since the proposed action there appears to be
> >>>> to document these semantics?
> >>> 
> >>> My understanding of pr77650 is specifically for documentation on the
> >>> following case:
> >>> 
> >>> The structure with a flexible array member is the middle field of another
> >>> structure.
> >>> 
> >>> Which I added in the documentation as the 2nd situation.
> >>> However, I am still not very comfortable on my current clarification on this
> >>> situation: how should we document on
> >>> the expected gcc behavior to handle such situation?
> >> 
> >> I reckon wording that dissuades programmers from using this might be
> >> appropriate, i.e. don't rely on this and if you already have such nested flex
> >> arrays, change code to remove them.
> >> 
> >>>>> +In the above, @code{flex_data.data[]} is allowed to be extended flexibly
> >>>>> to
> >>>>> +the padding. E.g, up to 4 elements.
> >> 
> >> """
> >> ... Relying on space in struct padding is bad programming practice and any
> >> code relying on this behaviour should be modified to ensure that flexible
> >> array members only end up at the ends of arrays.  The `-pedantic` flag should
> >> help identify such uses.
> >> """
> >> 
> >> Although -pedantic will also flag on flex arrays nested in structs even if
> >> they're at the end of the parent struct, so my suggestion on the warning is
> >> not really perfect.
> > 
> > Wow, so I checked and we indeed accept
> > 
> > struct X { int n; int data[]; };
> > struct Y { struct X x; int end; };
> > 
> > and -pedantic says
> > 
> > t.c:2:21: warning: invalid use of structure with flexible array member 
> > [-Wpedantic]
> >    2 | struct Y { struct X x; int end; };
> >      |    
> 
> Currently, -pedantic report the same message for flex arrays nested in structs at the end of the parent struct AND in the middle of the parent struct. 
> Shall we distinguish them and report different warning messages in order to discourage the latter case? 
> 
> And at the same time, in the documentation, clarify these two situations, and discourage the latter case at the same time as well?
> >       
> > 
> > and clang reports
> > 
> > t.c:2:21: warning: field 'x' with variable sized type 'struct X' not at 
> > the end of a struct or class is a GNU extension 
> > [-Wgnu-variable-sized-type-not-at-end]
> > struct Y { struct X x; int end; };
> >  
> >                  ^
> 
> Clang’s warning message is clearer. 
> > 
> > looking at PR77650 what seems missing there is the semantics of this
> > extension as expected/required by the glibc use.  comment#5 seems
> > to suggest that for my example above its expected that
> > Y.x.data[0] aliases Y.end?!
> 
> Should we mentioned this alias relationship in the doc?
> 
> >  There must be a better way to write
> > the glibc code and IMHO it would be best to deprecate this extension.
> 
> Agreed. This is really a bad practice, should be deprecated. 
> We can give warning first in this release, and then deprecate this extension in a latter release. 

Right -- this can lead (at least) to type confusion and other problems
too. We've been trying to remove all of these overlaps in the Linux
kernel. I mention it the "Overlapping composite structure members"
section at https://people.kernel.org/kees/bounded-flexible-arrays-in-c

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/2] Documentation Update.
  2023-02-02  8:33         ` Richard Biener
  2023-02-02 14:31           ` Qing Zhao
@ 2023-02-03  4:25           ` Siddhesh Poyarekar
  2023-02-03 14:52             ` Qing Zhao
  2023-02-03 20:55             ` Joseph Myers
  1 sibling, 2 replies; 45+ messages in thread
From: Siddhesh Poyarekar @ 2023-02-03  4:25 UTC (permalink / raw)
  To: Richard Biener; +Cc: Qing Zhao, gcc Patches, keescook, Joseph S. Myers

On 2023-02-02 03:33, Richard Biener wrote:
> looking at PR77650 what seems missing there is the semantics of this
> extension as expected/required by the glibc use.  comment#5 seems
> to suggest that for my example above its expected that
> Y.x.data[0] aliases Y.end?!  There must be a better way to write
> the glibc code and IMHO it would be best to deprecate this extension.
> Definitely the middle-end wouldn't consider this aliasing for
> my example - maybe it "works" when wrapped inside a union but
> then for sure only when the union is visible in all accesses ...
> 
> typedef union
> {
>    struct __gconv_info __cd;
>    struct
>    {
>      struct __gconv_info __cd;
>      struct __gconv_step_data __data;
>    } __combined;
> } _G_iconv_t;
> 
> could be written as
> 
> typedef union
> {
>    struct __gconv_info __cd;
>    char __dummy[sizeof(struct __gconv_info) + sizeof(struct
> __gconv_step_data)];
> } _G_iconv_t;
> 
> in case the intent is to provide a complete type with space for
> a single __gconv_step_data.

I dug into this on the glibc end and it looks like this commit:

commit 63fb8f9aa9d19f85599afe4b849b567aefd70a36
Author: Zack Weinberg <zackw@panix.com>
Date:   Mon Feb 5 14:13:41 2018 -0500

     Post-cleanup 2: minimize _G_config.h.

ripped all of that gunk out.  AFAICT there's no use of struct 
__gconv_info anywhere else in the code.

I reckon it is safe to say now that glibc no longer needs this misfeature.

Sid

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-02 14:38             ` Qing Zhao
@ 2023-02-03  7:49               ` Richard Biener
  2023-02-03 13:17                 ` Qing Zhao
  0 siblings, 1 reply; 45+ messages in thread
From: Richard Biener @ 2023-02-03  7:49 UTC (permalink / raw)
  To: Qing Zhao; +Cc: gcc-patches, siddhesh, keescook

On Thu, 2 Feb 2023, Qing Zhao wrote:

> 
> 
> > On Feb 2, 2023, at 8:54 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Thu, 2 Feb 2023, Qing Zhao wrote:
> > 
> >> 
> >> 

[...]

> >>>>>> +	return flexible_size_type_p (TREE_TYPE (last));
> >>>>> 
> >>>>> For types with many members this can become quite slow (IIRC we had
> >>>>> bugs about similar walks of all fields in types), and this function
> >>>>> looks like it's invoked multiple times on the same type per TU.
> >>>>> 
> >>>>> In principle the property is fixed at the time we lay out a record
> >>>>> type, so we might want to compute it at that time and record the
> >>>>> result.
> >>>> 
> >>>> You mean in FE? 
> >>> 
> >>> Yes, either in the frontend or in the middle-ends layout_type.
> >>> 
> >>>> Yes, that?s better and cleaner.
> >>>> 
> >>>> I will add one more field in the TYPE structure to record this information and check this field during middle end.
> >>>> 
> >>>> I had the same thought in the beginning, but not sure whether adding a 
> >>>> new field in IR is necessary or not, other places in middle end might 
> >>>> not use this new field.
> >>> 
> >>> It might be interesting to search for other code walking all fields of
> >>> a type to determine this or similar info.
> >> 
> >> There is one which is defined in tree.cc but only is referenced in c/c-decl.cc:
> >> 
> >> /* Determine whether TYPE is a structure with a flexible array member,
> >>   or a union containing such a structure (possibly recursively).  */
> >> flexible_array_type_p
> >> 
> >> However, this routine is a little different than the one I tried to add:
> >> 
> >> In the current routine ?flexible_array_type_p?,  only one level nesting in the structure is accepted, multiple nesting in structure is not permitted.
> >> 
> >> So, my question is:  shall we accept multiple nesting in structure? i.e.
> > 
> > If we don't reject the testcase with an error, then yes.
> 
> Gcc currently accepts the multiple nesting in structure without error.  
> So, we will continue to accept such extension as long as the flex array 
> is at the end of the structure. At the same time, for the case the flex 
> array is in the middle of the structure, issue additional warnings now 
> to discourage such usage, and deprecate this case in a future release.
> 
> Does this sound reasonable? 

Please don't mix several issues - I think the flex array in the
middle of a structure is separate and we shouldn't report that
as flexible_array_type_p or flexible_size_type_p since the size
of the containing structure is not variable.

For diagnostic purposes the intended use case is to treat
a pointer to a structure that appears to have a fixed size
but has (recursive) a member with a flexible array at the end
as having variable size.  Just the same as array_at_struct_end_p
treats this for the case of accesses involving such a type.

For the middle position case that's not the case.

Richard.

> Qing
> > 
> >> struct A {
> >>  int n;
> >>  char data[];/* Content following header */
> >> };
> >> 
> >> struct B {
> >>  int m;
> >>  struct A a;
> >> };
> >> 
> >> struct C {
> >>  int q;
> >>  struct B b;
> >> };
> >> 
> >> Qing
> >>> 
> >>>> thanks.
> >>>> 
> >>>> Qing
> >>>> 
> >>>>> 
> >>>>>> +      return false;
> >>>>>> +    case UNION_TYPE:
> >>>>>> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
> >>>>>> +	{
> >>>>>> +	  if (TREE_CODE (x) == FIELD_DECL
> >>>>>> +	      && flexible_array_type_p (TREE_TYPE (x)))
> >>>>>> +	    return true;
> >>>>>> +	}
> >>>>>> +      return false;
> >>>>>> +    default:
> >>>>>> +      return false;
> >>>>>> +  }
> >>>>>> +}
> >>>>>> +
> >>>>>> /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
> >>>>>>  OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
> >>>>>>  If unknown, return size_unknown (object_size_type).  */
> >>>>>> @@ -633,45 +669,68 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
> >>>>>> 		    v = NULL_TREE;
> >>>>>> 		    break;
> >>>>>> 		  case COMPONENT_REF:
> >>>>>> -		    if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
> >>>>>> +		    /* When the ref is not to an array, a record or a union, it
> >>>>>> +		       will not have flexible size, compute the object size
> >>>>>> +		       directly.  */
> >>>>>> +		    if ((TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
> >>>>>> +			&& (TREE_CODE (TREE_TYPE (v)) != RECORD_TYPE)
> >>>>>> +			&& (TREE_CODE (TREE_TYPE (v)) != UNION_TYPE))
> >>>>>> 		      {
> >>>>>> 			v = NULL_TREE;
> >>>>>> 			break;
> >>>>>> 		      }
> >>>>>> -		    is_flexible_array_mem_ref = array_ref_flexible_size_p (v);
> >>>>>> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> >>>>>> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>>>> -			  != UNION_TYPE
> >>>>>> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>>>> -			  != QUAL_UNION_TYPE)
> >>>>>> -			break;
> >>>>>> -		      else
> >>>>>> -			v = TREE_OPERAND (v, 0);
> >>>>>> -		    if (TREE_CODE (v) == COMPONENT_REF
> >>>>>> -			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>>>> -			   == RECORD_TYPE)
> >>>>>> +		    /* if the record or union does not have flexible size
> >>>>>> +		       compute the object size directly.  */
> >>>>>> +		    if (TREE_CODE (TREE_TYPE (v)) == RECORD_TYPE
> >>>>>> +			|| TREE_CODE (TREE_TYPE (v)) == UNION_TYPE)
> >>>>>> 		      {
> >>>>>> -			/* compute object size only if v is not a
> >>>>>> -			   flexible array member.  */
> >>>>>> -			if (!is_flexible_array_mem_ref)
> >>>>>> +			if (!flexible_size_type_p (TREE_TYPE (v)))
> >>>>>> 			  {
> >>>>>> 			    v = NULL_TREE;
> >>>>>> 			    break;
> >>>>>> 			  }
> >>>>>> -			v = TREE_OPERAND (v, 0);
> >>>>>> +			else
> >>>>>> +			  v = TREE_OPERAND (v, 0);
> >>>>>> 		      }
> >>>>>> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> >>>>>> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>>>> -			  != UNION_TYPE
> >>>>>> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>>>> -			  != QUAL_UNION_TYPE)
> >>>>>> -			break;
> >>>>>> -		      else
> >>>>>> -			v = TREE_OPERAND (v, 0);
> >>>>>> -		    if (v != pt_var)
> >>>>>> -		      v = NULL_TREE;
> >>>>>> 		    else
> >>>>>> -		      v = pt_var;
> >>>>>> +		      {
> >>>>>> +			/* Now the ref is to an array type.  */
> >>>>>> +			is_flexible_array_mem_ref
> >>>>>> +			  = array_ref_flexible_size_p (v);
> >>>>>> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> >>>>>> +			if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>>>> +			      != UNION_TYPE
> >>>>>> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>>>> +				 != QUAL_UNION_TYPE)
> >>>>>> +			  break;
> >>>>>> +			else
> >>>>>> +			  v = TREE_OPERAND (v, 0);
> >>>>>> +			if (TREE_CODE (v) == COMPONENT_REF
> >>>>>> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>>>> +				 == RECORD_TYPE)
> >>>>>> +			  {
> >>>>>> +			    /* compute object size only if v is not a
> >>>>>> +			       flexible array member.  */
> >>>>>> +			    if (!is_flexible_array_mem_ref)
> >>>>>> +			      {
> >>>>>> +				v = NULL_TREE;
> >>>>>> +				break;
> >>>>>> +			      }
> >>>>>> +			    v = TREE_OPERAND (v, 0);
> >>>>>> +			  }
> >>>>>> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
> >>>>>> +			  if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>>>> +				!= UNION_TYPE
> >>>>>> +			      && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
> >>>>>> +				   != QUAL_UNION_TYPE)
> >>>>>> +			    break;
> >>>>>> +			  else
> >>>>>> +			    v = TREE_OPERAND (v, 0);
> >>>>>> +			if (v != pt_var)
> >>>>>> +			  v = NULL_TREE;
> >>>>>> +			else
> >>>>>> +			  v = pt_var;
> >>>>>> +		      }
> >>>>>> 		    break;
> >>>>>> 		  default:
> >>>>>> 		    v = pt_var;
> >>>>>> 
> >>>>> 
> >>>>> -- 
> >>>>> Richard Biener <rguenther@suse.de>
> >>>>> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
> >>>>> Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
> >>>>> HRB 36809 (AG Nuernberg)
> >>>> 
> >>>> 
> >>> 
> >>> -- 
> >>> Richard Biener <rguenther@suse.de>
> >>> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
> >>> Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
> >>> HRB 36809 (AG Nuernberg)
> >> 
> >> 
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
> > Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
> > HRB 36809 (AG Nuernberg)
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
HRB 36809 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-03  7:49               ` Richard Biener
@ 2023-02-03 13:17                 ` Qing Zhao
  2023-02-06  9:31                   ` Richard Biener
  0 siblings, 1 reply; 45+ messages in thread
From: Qing Zhao @ 2023-02-03 13:17 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches, siddhesh, keescook



> On Feb 3, 2023, at 2:49 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Thu, 2 Feb 2023, Qing Zhao wrote:
> 
>> 
>> 
>>> On Feb 2, 2023, at 8:54 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On Thu, 2 Feb 2023, Qing Zhao wrote:
>>> 
>>>> 
>>>> 
> 
> [...]
> 
>>>>>>>> +	return flexible_size_type_p (TREE_TYPE (last));
>>>>>>> 
>>>>>>> For types with many members this can become quite slow (IIRC we had
>>>>>>> bugs about similar walks of all fields in types), and this function
>>>>>>> looks like it's invoked multiple times on the same type per TU.
>>>>>>> 
>>>>>>> In principle the property is fixed at the time we lay out a record
>>>>>>> type, so we might want to compute it at that time and record the
>>>>>>> result.
>>>>>> 
>>>>>> You mean in FE? 
>>>>> 
>>>>> Yes, either in the frontend or in the middle-ends layout_type.
>>>>> 
>>>>>> Yes, that?s better and cleaner.
>>>>>> 
>>>>>> I will add one more field in the TYPE structure to record this information and check this field during middle end.
>>>>>> 
>>>>>> I had the same thought in the beginning, but not sure whether adding a 
>>>>>> new field in IR is necessary or not, other places in middle end might 
>>>>>> not use this new field.
>>>>> 
>>>>> It might be interesting to search for other code walking all fields of
>>>>> a type to determine this or similar info.
>>>> 
>>>> There is one which is defined in tree.cc but only is referenced in c/c-decl.cc:
>>>> 
>>>> /* Determine whether TYPE is a structure with a flexible array member,
>>>>  or a union containing such a structure (possibly recursively).  */
>>>> flexible_array_type_p
>>>> 
>>>> However, this routine is a little different than the one I tried to add:
>>>> 
>>>> In the current routine ?flexible_array_type_p?,  only one level nesting in the structure is accepted, multiple nesting in structure is not permitted.
>>>> 
>>>> So, my question is:  shall we accept multiple nesting in structure? i.e.
>>> 
>>> If we don't reject the testcase with an error, then yes.
>> 
>> Gcc currently accepts the multiple nesting in structure without error.  
>> So, we will continue to accept such extension as long as the flex array 
>> is at the end of the structure. At the same time, for the case the flex 
>> array is in the middle of the structure, issue additional warnings now 
>> to discourage such usage, and deprecate this case in a future release.
>> 
>> Does this sound reasonable? 
> 
> Please don't mix several issues - I think the flex array in the
> middle of a structure is separate and we shouldn't report that
> as flexible_array_type_p or flexible_size_type_p since the size
> of the containing structure is not variable.
Agreed on this.

My major question here is (for documentation change, sorry for mixing this thread with the documentation change): do we need to document this case together with the case in which struct with flex array is embedded into another structure? (As a GCC extension?)
> 
> For diagnostic purposes the intended use case is to treat
> a pointer to a structure that appears to have a fixed size
> but has (recursive) a member with a flexible array at the end
> as having variable size.  Just the same as array_at_struct_end_p
> treats this for the case of accesses involving such a type.

Yes. 
> 
> For the middle position case that's not the case.
Yes. 

Thanks.

Qing
> 
> Richard.
> 
>> Qing
>>> 
>>>> struct A {
>>>> int n;
>>>> char data[];/* Content following header */
>>>> };
>>>> 
>>>> struct B {
>>>> int m;
>>>> struct A a;
>>>> };
>>>> 
>>>> struct C {
>>>> int q;
>>>> struct B b;
>>>> };
>>>> 
>>>> Qing
>>>>> 
>>>>>> thanks.
>>>>>> 
>>>>>> Qing
>>>>>> 
>>>>>>> 
>>>>>>>> +      return false;
>>>>>>>> +    case UNION_TYPE:
>>>>>>>> +      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
>>>>>>>> +	{
>>>>>>>> +	  if (TREE_CODE (x) == FIELD_DECL
>>>>>>>> +	      && flexible_array_type_p (TREE_TYPE (x)))
>>>>>>>> +	    return true;
>>>>>>>> +	}
>>>>>>>> +      return false;
>>>>>>>> +    default:
>>>>>>>> +      return false;
>>>>>>>> +  }
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
>>>>>>>> OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
>>>>>>>> If unknown, return size_unknown (object_size_type).  */
>>>>>>>> @@ -633,45 +669,68 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
>>>>>>>> 		    v = NULL_TREE;
>>>>>>>> 		    break;
>>>>>>>> 		  case COMPONENT_REF:
>>>>>>>> -		    if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
>>>>>>>> +		    /* When the ref is not to an array, a record or a union, it
>>>>>>>> +		       will not have flexible size, compute the object size
>>>>>>>> +		       directly.  */
>>>>>>>> +		    if ((TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
>>>>>>>> +			&& (TREE_CODE (TREE_TYPE (v)) != RECORD_TYPE)
>>>>>>>> +			&& (TREE_CODE (TREE_TYPE (v)) != UNION_TYPE))
>>>>>>>> 		      {
>>>>>>>> 			v = NULL_TREE;
>>>>>>>> 			break;
>>>>>>>> 		      }
>>>>>>>> -		    is_flexible_array_mem_ref = array_ref_flexible_size_p (v);
>>>>>>>> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>>>>>>>> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>>>> -			  != UNION_TYPE
>>>>>>>> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>>>> -			  != QUAL_UNION_TYPE)
>>>>>>>> -			break;
>>>>>>>> -		      else
>>>>>>>> -			v = TREE_OPERAND (v, 0);
>>>>>>>> -		    if (TREE_CODE (v) == COMPONENT_REF
>>>>>>>> -			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>>>> -			   == RECORD_TYPE)
>>>>>>>> +		    /* if the record or union does not have flexible size
>>>>>>>> +		       compute the object size directly.  */
>>>>>>>> +		    if (TREE_CODE (TREE_TYPE (v)) == RECORD_TYPE
>>>>>>>> +			|| TREE_CODE (TREE_TYPE (v)) == UNION_TYPE)
>>>>>>>> 		      {
>>>>>>>> -			/* compute object size only if v is not a
>>>>>>>> -			   flexible array member.  */
>>>>>>>> -			if (!is_flexible_array_mem_ref)
>>>>>>>> +			if (!flexible_size_type_p (TREE_TYPE (v)))
>>>>>>>> 			  {
>>>>>>>> 			    v = NULL_TREE;
>>>>>>>> 			    break;
>>>>>>>> 			  }
>>>>>>>> -			v = TREE_OPERAND (v, 0);
>>>>>>>> +			else
>>>>>>>> +			  v = TREE_OPERAND (v, 0);
>>>>>>>> 		      }
>>>>>>>> -		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>>>>>>>> -		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>>>> -			  != UNION_TYPE
>>>>>>>> -			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>>>> -			  != QUAL_UNION_TYPE)
>>>>>>>> -			break;
>>>>>>>> -		      else
>>>>>>>> -			v = TREE_OPERAND (v, 0);
>>>>>>>> -		    if (v != pt_var)
>>>>>>>> -		      v = NULL_TREE;
>>>>>>>> 		    else
>>>>>>>> -		      v = pt_var;
>>>>>>>> +		      {
>>>>>>>> +			/* Now the ref is to an array type.  */
>>>>>>>> +			is_flexible_array_mem_ref
>>>>>>>> +			  = array_ref_flexible_size_p (v);
>>>>>>>> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>>>>>>>> +			if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>>>> +			      != UNION_TYPE
>>>>>>>> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>>>> +				 != QUAL_UNION_TYPE)
>>>>>>>> +			  break;
>>>>>>>> +			else
>>>>>>>> +			  v = TREE_OPERAND (v, 0);
>>>>>>>> +			if (TREE_CODE (v) == COMPONENT_REF
>>>>>>>> +			    && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>>>> +				 == RECORD_TYPE)
>>>>>>>> +			  {
>>>>>>>> +			    /* compute object size only if v is not a
>>>>>>>> +			       flexible array member.  */
>>>>>>>> +			    if (!is_flexible_array_mem_ref)
>>>>>>>> +			      {
>>>>>>>> +				v = NULL_TREE;
>>>>>>>> +				break;
>>>>>>>> +			      }
>>>>>>>> +			    v = TREE_OPERAND (v, 0);
>>>>>>>> +			  }
>>>>>>>> +			while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
>>>>>>>> +			  if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>>>> +				!= UNION_TYPE
>>>>>>>> +			      && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
>>>>>>>> +				   != QUAL_UNION_TYPE)
>>>>>>>> +			    break;
>>>>>>>> +			  else
>>>>>>>> +			    v = TREE_OPERAND (v, 0);
>>>>>>>> +			if (v != pt_var)
>>>>>>>> +			  v = NULL_TREE;
>>>>>>>> +			else
>>>>>>>> +			  v = pt_var;
>>>>>>>> +		      }
>>>>>>>> 		    break;
>>>>>>>> 		  default:
>>>>>>>> 		    v = pt_var;
>>>>>>>> 
>>>>>>> 
>>>>>>> -- 
>>>>>>> Richard Biener <rguenther@suse.de>
>>>>>>> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
>>>>>>> Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
>>>>>>> HRB 36809 (AG Nuernberg)
>>>>>> 
>>>>>> 
>>>>> 
>>>>> -- 
>>>>> Richard Biener <rguenther@suse.de>
>>>>> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
>>>>> Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
>>>>> HRB 36809 (AG Nuernberg)
>>>> 
>>>> 
>>> 
>>> -- 
>>> Richard Biener <rguenther@suse.de>
>>> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
>>> Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
>>> HRB 36809 (AG Nuernberg)
>> 
>> 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
> Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
> HRB 36809 (AG Nuernberg)


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/2] Documentation Update.
  2023-02-03  4:25           ` Siddhesh Poyarekar
@ 2023-02-03 14:52             ` Qing Zhao
  2023-02-03 20:55             ` Joseph Myers
  1 sibling, 0 replies; 45+ messages in thread
From: Qing Zhao @ 2023-02-03 14:52 UTC (permalink / raw)
  To: Siddhesh Poyarekar; +Cc: Richard Biener, gcc Patches, keescook, Joseph S. Myers




> On Feb 2, 2023, at 11:25 PM, Siddhesh Poyarekar <siddhesh@gotplt.org> wrote:
> 
> On 2023-02-02 03:33, Richard Biener wrote:
>> looking at PR77650 what seems missing there is the semantics of this
>> extension as expected/required by the glibc use.  comment#5 seems
>> to suggest that for my example above its expected that
>> Y.x.data[0] aliases Y.end?!  There must be a better way to write
>> the glibc code and IMHO it would be best to deprecate this extension.
>> Definitely the middle-end wouldn't consider this aliasing for
>> my example - maybe it "works" when wrapped inside a union but
>> then for sure only when the union is visible in all accesses ...
>> typedef union
>> {
>>   struct __gconv_info __cd;
>>   struct
>>   {
>>     struct __gconv_info __cd;
>>     struct __gconv_step_data __data;
>>   } __combined;
>> } _G_iconv_t;
>> could be written as
>> typedef union
>> {
>>   struct __gconv_info __cd;
>>   char __dummy[sizeof(struct __gconv_info) + sizeof(struct
>> __gconv_step_data)];
>> } _G_iconv_t;
>> in case the intent is to provide a complete type with space for
>> a single __gconv_step_data.
> 
> I dug into this on the glibc end and it looks like this commit:
> 
> commit 63fb8f9aa9d19f85599afe4b849b567aefd70a36
> Author: Zack Weinberg <zackw@panix.com>
> Date:   Mon Feb 5 14:13:41 2018 -0500
> 
>    Post-cleanup 2: minimize _G_config.h.
> 
> ripped all of that gunk out.  AFAICT there's no use of struct __gconv_info anywhere else in the code.
> 
> I reckon it is safe to say now that glibc no longer needs this misfeature.

Thanks a lot for the info.

Looks like it’s good time to start deprecating this misfeature from GCC.

Qing

> 
> Sid


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/2] Documentation Update.
  2023-02-02 17:05             ` Kees Cook
@ 2023-02-03 15:56               ` Jeff Law
  0 siblings, 0 replies; 45+ messages in thread
From: Jeff Law @ 2023-02-03 15:56 UTC (permalink / raw)
  To: gcc-patches



On 2/2/23 10:05, Kees Cook via Gcc-patches wrote:

> 
> Right -- this can lead (at least) to type confusion and other problems
> too. We've been trying to remove all of these overlaps in the Linux
> kernel. I mention it the "Overlapping composite structure members"
> section at https://people.kernel.org/kees/bounded-flexible-arrays-in-c
Good.  We found several of these when Martin S was doing his work on the 
diagnostics a few years back.  It wasn't hard to see what the intent 
was, but it struck me as a poor (ab)use of the feature and that I 
wouldn't be surprised if compilers might differ in their semantics 
around this stuff.

jeff

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/2] Documentation Update.
  2023-02-03  4:25           ` Siddhesh Poyarekar
  2023-02-03 14:52             ` Qing Zhao
@ 2023-02-03 20:55             ` Joseph Myers
  2023-02-03 22:38               ` Qing Zhao
  1 sibling, 1 reply; 45+ messages in thread
From: Joseph Myers @ 2023-02-03 20:55 UTC (permalink / raw)
  To: Siddhesh Poyarekar; +Cc: Richard Biener, Qing Zhao, gcc Patches, keescook

On Thu, 2 Feb 2023, Siddhesh Poyarekar wrote:

> I dug into this on the glibc end and it looks like this commit:
> 
> commit 63fb8f9aa9d19f85599afe4b849b567aefd70a36
> Author: Zack Weinberg <zackw@panix.com>
> Date:   Mon Feb 5 14:13:41 2018 -0500
> 
>     Post-cleanup 2: minimize _G_config.h.
> 
> ripped all of that gunk out.  AFAICT there's no use of struct __gconv_info
> anywhere else in the code.
> 
> I reckon it is safe to say now that glibc no longer needs this misfeature.

It would be worth testing whether any change warns anywhere else in glibc 
(not necessarily in installed headers).  And to have fixincludes for the 
installed _G_config.h from old glibc if we start rejecting such code.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 2/2] Documentation Update.
  2023-02-03 20:55             ` Joseph Myers
@ 2023-02-03 22:38               ` Qing Zhao
  0 siblings, 0 replies; 45+ messages in thread
From: Qing Zhao @ 2023-02-03 22:38 UTC (permalink / raw)
  To: Joseph Myers, Richard Biener, Siddhesh Poyarekar, kees Cook, jeffreyalaw
  Cc: gcc Patches

Okay, thanks all for the comments and suggestions.

Based on the discussion so far, I have the following plan for resolving this issue:

In GCC13:

1. Add documentation in extend.texi to include all the following 3 cases as GCC extension:

Case 1: The structure with a flexible array member is the last field of another
structure, for example:

struct flex  { int length; char data[]; }
struct out_flex { int m; struct flex flex_data; }

In the above, flex_data.data[] is considered as a flexible array too.

Case 2: The structure with a flexible array member is the field of another union, for example:

struct flex1  { int length1; char data1[]; }
struct flex2  { int length2; char data2[]; }
union out_flex { struct flex1 flex_data1; struct flex2 flex_data2; }

In the above, flex_data1.data1[] or flex_data2.data2[] is considered as flexible arrays too.

Case 3: The structure with a flexible array member is the middle field of another
structure, for example:

struct flex  { int length; char data[]; }
struct out_flex { int m; struct flex flex_data; int n; }

In the above, flex_data.data[] is allowed to be extended flexibly to
the padding. E.g, up to 4 elements.

However, relying on space in struct padding is a bad programming practice,  compilers do not 
handle such extension consistently, and any code relying on this behavior should be modified
to ensure that flexible array members only end up at the ends of structures.

Please use warning option -Wgnu-variable-sized-type-not-at-end (to be consistent with CLANG) 
to identify all such cases in the source code and modify them. This extension will be deprecated
from gcc in the next release.

2. Add a new warning option -Wgnu-varaible-sized-type-not-at-end to warn such usage.

In GCC14:

1. Include this new warning -Wgnu-varaible-sized-type-not-at-end to -Wall
2. Deprecate this extension from GCC. (Or delay this to next release?).


Let me know any comments and suggestions?

thanks.

Qing



> On Feb 3, 2023, at 3:55 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> 
> On Thu, 2 Feb 2023, Siddhesh Poyarekar wrote:
> 
>> I dug into this on the glibc end and it looks like this commit:
>> 
>> commit 63fb8f9aa9d19f85599afe4b849b567aefd70a36
>> Author: Zack Weinberg <zackw@panix.com>
>> Date:   Mon Feb 5 14:13:41 2018 -0500
>> 
>>    Post-cleanup 2: minimize _G_config.h.
>> 
>> ripped all of that gunk out.  AFAICT there's no use of struct __gconv_info
>> anywhere else in the code.
>> 
>> I reckon it is safe to say now that glibc no longer needs this misfeature.
> 
> It would be worth testing whether any change warns anywhere else in glibc 
> (not necessarily in installed headers).  And to have fixincludes for the 
> installed _G_config.h from old glibc if we start rejecting such code.
> 
> -- 
> Joseph S. Myers
> joseph@codesourcery.com


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-03 13:17                 ` Qing Zhao
@ 2023-02-06  9:31                   ` Richard Biener
  2023-02-06 14:38                     ` Qing Zhao
  0 siblings, 1 reply; 45+ messages in thread
From: Richard Biener @ 2023-02-06  9:31 UTC (permalink / raw)
  To: Qing Zhao; +Cc: gcc-patches, siddhesh, keescook, Joseph S. Myers

On Fri, 3 Feb 2023, Qing Zhao wrote:

> 
> 
> > On Feb 3, 2023, at 2:49 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Thu, 2 Feb 2023, Qing Zhao wrote:
> > 
> >> 
> >> 
> >>> On Feb 2, 2023, at 8:54 AM, Richard Biener <rguenther@suse.de> wrote:
> >>> 
> >>> On Thu, 2 Feb 2023, Qing Zhao wrote:
> >>> 
> >>>> 
> >>>> 
> > 
> > [...]
> > 
> >>>>>>>> +	return flexible_size_type_p (TREE_TYPE (last));
> >>>>>>> 
> >>>>>>> For types with many members this can become quite slow (IIRC we had
> >>>>>>> bugs about similar walks of all fields in types), and this function
> >>>>>>> looks like it's invoked multiple times on the same type per TU.
> >>>>>>> 
> >>>>>>> In principle the property is fixed at the time we lay out a record
> >>>>>>> type, so we might want to compute it at that time and record the
> >>>>>>> result.
> >>>>>> 
> >>>>>> You mean in FE? 
> >>>>> 
> >>>>> Yes, either in the frontend or in the middle-ends layout_type.
> >>>>> 
> >>>>>> Yes, that?s better and cleaner.
> >>>>>> 
> >>>>>> I will add one more field in the TYPE structure to record this information and check this field during middle end.
> >>>>>> 
> >>>>>> I had the same thought in the beginning, but not sure whether adding a 
> >>>>>> new field in IR is necessary or not, other places in middle end might 
> >>>>>> not use this new field.
> >>>>> 
> >>>>> It might be interesting to search for other code walking all fields of
> >>>>> a type to determine this or similar info.
> >>>> 
> >>>> There is one which is defined in tree.cc but only is referenced in c/c-decl.cc:
> >>>> 
> >>>> /* Determine whether TYPE is a structure with a flexible array member,
> >>>>  or a union containing such a structure (possibly recursively).  */
> >>>> flexible_array_type_p
> >>>> 
> >>>> However, this routine is a little different than the one I tried to add:
> >>>> 
> >>>> In the current routine ?flexible_array_type_p?,  only one level nesting in the structure is accepted, multiple nesting in structure is not permitted.
> >>>> 
> >>>> So, my question is:  shall we accept multiple nesting in structure? i.e.
> >>> 
> >>> If we don't reject the testcase with an error, then yes.
> >> 
> >> Gcc currently accepts the multiple nesting in structure without error.  
> >> So, we will continue to accept such extension as long as the flex array 
> >> is at the end of the structure. At the same time, for the case the flex 
> >> array is in the middle of the structure, issue additional warnings now 
> >> to discourage such usage, and deprecate this case in a future release.
> >> 
> >> Does this sound reasonable? 
> > 
> > Please don't mix several issues - I think the flex array in the
> > middle of a structure is separate and we shouldn't report that
> > as flexible_array_type_p or flexible_size_type_p since the size
> > of the containing structure is not variable.
> Agreed on this.
> 
> My major question here is (for documentation change, sorry for mixing 
> this thread with the documentation change): do we need to document this 
> case together with the case in which struct with flex array is embedded 
> into another structure? (As a GCC extension?)

I think this should be Josephs call - documenting this might
encourage people to use such an extension, even if it's a bad
one we want to get rid of.

Maybe the easiest thing is to come up with a patch documenting it
which we can then turn into a deprecation note depending on this
outcome.

Richard.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-06  9:31                   ` Richard Biener
@ 2023-02-06 14:38                     ` Qing Zhao
  2023-02-06 23:14                       ` Joseph Myers
  0 siblings, 1 reply; 45+ messages in thread
From: Qing Zhao @ 2023-02-06 14:38 UTC (permalink / raw)
  To: Richard Biener, Joseph Myers
  Cc: gcc-patches, siddhesh, keescook, Joseph S. Myers



> On Feb 6, 2023, at 4:31 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Fri, 3 Feb 2023, Qing Zhao wrote:
> 
>> 
>> 
>>> On Feb 3, 2023, at 2:49 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On Thu, 2 Feb 2023, Qing Zhao wrote:
>>> 
>>>> 
>>>> 
>>>>> On Feb 2, 2023, at 8:54 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>> 
>>>>> On Thu, 2 Feb 2023, Qing Zhao wrote:
>>>>> 
>>>>>> 
>>>>>> 
>>> 
>>> [...]
>>> 
>>>>>>>>>> +	return flexible_size_type_p (TREE_TYPE (last));
>>>>>>>>> 
>>>>>>>>> For types with many members this can become quite slow (IIRC we had
>>>>>>>>> bugs about similar walks of all fields in types), and this function
>>>>>>>>> looks like it's invoked multiple times on the same type per TU.
>>>>>>>>> 
>>>>>>>>> In principle the property is fixed at the time we lay out a record
>>>>>>>>> type, so we might want to compute it at that time and record the
>>>>>>>>> result.
>>>>>>>> 
>>>>>>>> You mean in FE? 
>>>>>>> 
>>>>>>> Yes, either in the frontend or in the middle-ends layout_type.
>>>>>>> 
>>>>>>>> Yes, that?s better and cleaner.
>>>>>>>> 
>>>>>>>> I will add one more field in the TYPE structure to record this information and check this field during middle end.
>>>>>>>> 
>>>>>>>> I had the same thought in the beginning, but not sure whether adding a 
>>>>>>>> new field in IR is necessary or not, other places in middle end might 
>>>>>>>> not use this new field.
>>>>>>> 
>>>>>>> It might be interesting to search for other code walking all fields of
>>>>>>> a type to determine this or similar info.
>>>>>> 
>>>>>> There is one which is defined in tree.cc but only is referenced in c/c-decl.cc:
>>>>>> 
>>>>>> /* Determine whether TYPE is a structure with a flexible array member,
>>>>>> or a union containing such a structure (possibly recursively).  */
>>>>>> flexible_array_type_p
>>>>>> 
>>>>>> However, this routine is a little different than the one I tried to add:
>>>>>> 
>>>>>> In the current routine ?flexible_array_type_p?,  only one level nesting in the structure is accepted, multiple nesting in structure is not permitted.
>>>>>> 
>>>>>> So, my question is:  shall we accept multiple nesting in structure? i.e.
>>>>> 
>>>>> If we don't reject the testcase with an error, then yes.
>>>> 
>>>> Gcc currently accepts the multiple nesting in structure without error.  
>>>> So, we will continue to accept such extension as long as the flex array 
>>>> is at the end of the structure. At the same time, for the case the flex 
>>>> array is in the middle of the structure, issue additional warnings now 
>>>> to discourage such usage, and deprecate this case in a future release.
>>>> 
>>>> Does this sound reasonable? 
>>> 
>>> Please don't mix several issues - I think the flex array in the
>>> middle of a structure is separate and we shouldn't report that
>>> as flexible_array_type_p or flexible_size_type_p since the size
>>> of the containing structure is not variable.
>> Agreed on this.
>> 
>> My major question here is (for documentation change, sorry for mixing 
>> this thread with the documentation change): do we need to document this 
>> case together with the case in which struct with flex array is embedded 
>> into another structure? (As a GCC extension?)
> 
> I think this should be Josephs call - documenting this might
> encourage people to use such an extension, even if it's a bad
> one we want to get rid of.
That’s true...
> 
> Maybe the easiest thing is to come up with a patch documenting it
> which we can then turn into a deprecation note depending on this
> outcome.

In the other thread for the documentation change, I have listed a plan based on the discussion.
 Could you please take a look at it and provide me some comments in that thread? (I just copied my 
plan below for your convenience)

Thanks.

Qing

==================

In GCC13:

1. Add documentation in extend.texi to include all the following 3 cases as GCC extension:

Case 1: The structure with a flexible array member is the last field of another
structure, for example:

struct flex  { int length; char data[]; }
struct out_flex { int m; struct flex flex_data; }

In the above, flex_data.data[] is considered as a flexible array too.

Case 2: The structure with a flexible array member is the field of another union, for example:

struct flex1  { int length1; char data1[]; }
struct flex2  { int length2; char data2[]; }
union out_flex { struct flex1 flex_data1; struct flex2 flex_data2; }

In the above, flex_data1.data1[] or flex_data2.data2[] is considered as flexible arrays too.

Case 3: The structure with a flexible array member is the middle field of another
structure, for example:

struct flex  { int length; char data[]; }
struct out_flex { int m; struct flex flex_data; int n; }

In the above, flex_data.data[] is allowed to be extended flexibly to
the padding. E.g, up to 4 elements.

However, relying on space in struct padding is a bad programming practice,  compilers do not 
handle such extension consistently, and any code relying on this behavior should be modified
to ensure that flexible array members only end up at the ends of structures.

Please use warning option -Wgnu-variable-sized-type-not-at-end (to be consistent with CLANG) 
to identify all such cases in the source code and modify them. This extension will be deprecated
from gcc in the next release.

2. Add a new warning option -Wgnu-varaible-sized-type-not-at-end to warn such usage.

In GCC14:

1. Include this new warning -Wgnu-varaible-sized-type-not-at-end to -Wall
2. Deprecate this extension from GCC. (Or delay this to next release?).


> 
> Richard.


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-06 14:38                     ` Qing Zhao
@ 2023-02-06 23:14                       ` Joseph Myers
  2023-02-07 14:54                         ` Qing Zhao
  2023-02-07 15:28                         ` Siddhesh Poyarekar
  0 siblings, 2 replies; 45+ messages in thread
From: Joseph Myers @ 2023-02-06 23:14 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Biener, gcc-patches, siddhesh, keescook

On Mon, 6 Feb 2023, Qing Zhao via Gcc-patches wrote:

> In GCC14:
> 
> 1. Include this new warning -Wgnu-varaible-sized-type-not-at-end to -Wall
> 2. Deprecate this extension from GCC. (Or delay this to next release?).

Any deprecation, or inclusion in -Wall, would best come with evidence 
about the prevalance of use (possibly unintentional, probably undesirable) 
of these extensions.  For example, maybe someone could do a distribution 
rebuild with a patch to enable these warnings and report the results?

Various misuses of flexible array members are only pedwarns-if-pedantic 
because of such uses - and while the original motivating case 
<https://gcc.gnu.org/legacy-ml/gcc-patches/2002-08/msg01149.html> was 
_G_config.h, which has since been fixed (though existing installed headers 
from old glibc would need fixincluding, at least if it becomes an error), 
it's very plausible there are uses of these extensions elsewhere.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-06 23:14                       ` Joseph Myers
@ 2023-02-07 14:54                         ` Qing Zhao
  2023-02-07 19:17                           ` Joseph Myers
  2023-02-07 15:28                         ` Siddhesh Poyarekar
  1 sibling, 1 reply; 45+ messages in thread
From: Qing Zhao @ 2023-02-07 14:54 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Richard Biener, gcc-patches, siddhesh, keescook

Hi, Joseph,


> On Feb 6, 2023, at 6:14 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> 
> On Mon, 6 Feb 2023, Qing Zhao via Gcc-patches wrote:
> 
>> In GCC14:
>> 
>> 1. Include this new warning -Wgnu-varaible-sized-type-not-at-end to -Wall
>> 2. Deprecate this extension from GCC. (Or delay this to next release?).
> 
> Any deprecation, or inclusion in -Wall, would best come with evidence 
> about the prevalance of use (possibly unintentional, probably undesirable) 
> of these extensions.  For example, maybe someone could do a distribution 
> rebuild with a patch to enable these warnings and report the results?
Yes, before we deprecate this extension, it’s better to make sure all such
 misuses are updated already.
> 
> Various misuses of flexible array members are only pedwarns-if-pedantic 
> because of such uses - and while the original motivating case 
> <https://gcc.gnu.org/legacy-ml/gcc-patches/2002-08/msg01149.html>

Just checked this patch (which has been in GCC source tree already), the routine flexible_array_type_p 
+/* Determine whether TYPE is a structure with a flexible array member,
+   or a union containing such a structure (possibly recursively).  */
+
+static bool
+flexible_array_type_p (type)

Did not include the following cases:

1.  Structure with flexible array member embedded into other structures recursively, for example:

struct A {
  int n;
  char data[];
};

struct B {
  int m;
  struct A a;
};

struct C {
  int q;
  struct B b;
};

In the above, “struct C” will not be caught by this routine.

Shall “struct C” be included?

2. Only C99 standard flexible array member be included, [0] and [1] are not included, for example:

struct A {
  int n;
  char data[0];
};

struct B {
  int m;
  struct A a;
};

struct C {
  int q;
  struct B b;
};

In the above, “struct B” and “struct C” will not be caught by this routine.

Shall “the above struct B” and “struct C” be included per -fstrict-flex-arrays?

Could you please take a look at my latest patch:

https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611445.html

To see whether the new bit “TYPE_INCLUDE_FLEXARRAY” covers the above “flexible_array_type_p”? Then we can merge them together?


> was 
> _G_config.h, which has since been fixed (though existing installed headers 
> from old glibc would need fixincluding, at least if it becomes an error), 
> it's very plausible there are uses of these extensions elsewhere.
If this is the case, we should definitely deprecate this extension.

Thanks.

Qing
> 
> -- 
> Joseph S. Myers
> joseph@codesourcery.com


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-06 23:14                       ` Joseph Myers
  2023-02-07 14:54                         ` Qing Zhao
@ 2023-02-07 15:28                         ` Siddhesh Poyarekar
  2023-02-07 15:38                           ` Qing Zhao
  1 sibling, 1 reply; 45+ messages in thread
From: Siddhesh Poyarekar @ 2023-02-07 15:28 UTC (permalink / raw)
  To: Joseph Myers, Qing Zhao; +Cc: Richard Biener, gcc-patches, keescook, fberat

On 2023-02-06 18:14, Joseph Myers wrote:
> On Mon, 6 Feb 2023, Qing Zhao via Gcc-patches wrote:
> 
>> In GCC14:
>>
>> 1. Include this new warning -Wgnu-varaible-sized-type-not-at-end to -Wall
>> 2. Deprecate this extension from GCC. (Or delay this to next release?).
> 
> Any deprecation, or inclusion in -Wall, would best come with evidence
> about the prevalance of use (possibly unintentional, probably undesirable)
> of these extensions.  For example, maybe someone could do a distribution
> rebuild with a patch to enable these warnings and report the results?

FWIW, Fred from our team has been working on a mass prebuilder that can 
be used for this kind of distribution-wide validation.  I've used it for 
_FORTIFY_SOURCE validation as well as coverage analysis.

I can help you with this Qing, once you have a patch ready.

Sid

[1] https://gitlab.com/fedora/packager-tools/mass-prebuild/

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-07 15:28                         ` Siddhesh Poyarekar
@ 2023-02-07 15:38                           ` Qing Zhao
  0 siblings, 0 replies; 45+ messages in thread
From: Qing Zhao @ 2023-02-07 15:38 UTC (permalink / raw)
  To: Siddhesh Poyarekar
  Cc: Joseph Myers, Richard Biener, gcc-patches, keescook, fberat



> On Feb 7, 2023, at 10:28 AM, Siddhesh Poyarekar <siddhesh@gotplt.org> wrote:
> 
> On 2023-02-06 18:14, Joseph Myers wrote:
>> On Mon, 6 Feb 2023, Qing Zhao via Gcc-patches wrote:
>>> In GCC14:
>>> 
>>> 1. Include this new warning -Wgnu-varaible-sized-type-not-at-end to -Wall
>>> 2. Deprecate this extension from GCC. (Or delay this to next release?).
>> Any deprecation, or inclusion in -Wall, would best come with evidence
>> about the prevalance of use (possibly unintentional, probably undesirable)
>> of these extensions.  For example, maybe someone could do a distribution
>> rebuild with a patch to enable these warnings and report the results?
> 
> FWIW, Fred from our team has been working on a mass prebuilder that can be used for this kind of distribution-wide validation.  I've used it for _FORTIFY_SOURCE validation as well as coverage analysis.
> 
> I can help you with this Qing, once you have a patch ready.

Thanks a lot!

Qing
> 
> Sid
> 
> [1] https://gitlab.com/fedora/packager-tools/mass-prebuild/


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-07 14:54                         ` Qing Zhao
@ 2023-02-07 19:17                           ` Joseph Myers
  2023-02-07 19:57                             ` Qing Zhao
  0 siblings, 1 reply; 45+ messages in thread
From: Joseph Myers @ 2023-02-07 19:17 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Biener, gcc-patches, siddhesh, keescook

[-- Attachment #1: Type: text/plain, Size: 1309 bytes --]

On Tue, 7 Feb 2023, Qing Zhao via Gcc-patches wrote:

> 1.  Structure with flexible array member embedded into other structures 
> recursively, for example:
> 
> struct A {
>   int n;
>   char data[];
> };
> 
> struct B {
>   int m;
>   struct A a;
> };
> 
> struct C {
>   int q;
>   struct B b;
> };
> 
> In the above, “struct C” will not be caught by this routine.

Because struct B is diagnosed with -pedantic when it embed struct A, there 
is no need for -pedantic to diagnose struct C as well when it embeds 
struct B.

> 2. Only C99 standard flexible array member be included, [0] and [1] are 
> not included, for example:

Obviously we can't diagnose use of structures with [1] trailing members, 
because it's perfectly valid to embed those structures at any position 
inside other structures.  And the same is the case for the [0] extension 
when it's used to mean "empty array" rather than "flexible array".

Note that my comments above are about what diagnostics are appropriate 
under the standard.  They are *not* about how code generation might allow 
for possible uses of certain source code constructs as if they were 
flexible array members.  The two contexts may very well require different 
notions of what counts as a flexible array member.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-07 19:17                           ` Joseph Myers
@ 2023-02-07 19:57                             ` Qing Zhao
  2023-02-07 23:37                               ` Joseph Myers
  0 siblings, 1 reply; 45+ messages in thread
From: Qing Zhao @ 2023-02-07 19:57 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Richard Biener, gcc-patches, siddhesh, keescook



> On Feb 7, 2023, at 2:17 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> 
> On Tue, 7 Feb 2023, Qing Zhao via Gcc-patches wrote:
> 
>> 1.  Structure with flexible array member embedded into other structures 
>> recursively, for example:
>> 
>> struct A {
>>  int n;
>>  char data[];
>> };
>> 
>> struct B {
>>  int m;
>>  struct A a;
>> };
>> 
>> struct C {
>>  int q;
>>  struct B b;
>> };
>> 
>> In the above, “struct C” will not be caught by this routine.
> 
> Because struct B is diagnosed with -pedantic when it embed struct A, there 
> is no need for -pedantic to diagnose struct C as well when it embeds 
> struct B.

Oh, yes.
Then, this routine (flexible_array_type_p) is mainly for diagnostic purpose.
It cannot be used to determine whether the structure/union type recursively
include a flexible array member at the end.

Is my understanding correct?

> 
>> 2. Only C99 standard flexible array member be included, [0] and [1] are 
>> not included, for example:
> 
> Obviously we can't diagnose use of structures with [1] trailing members, 
> because it's perfectly valid to embed those structures at any position 
> inside other structures.  And the same is the case for the [0] extension 
> when it's used to mean "empty array" rather than "flexible array".

With the -fstrict-flex-arrays available, we should be able to diagnose
the flexible array member per gnu extension (i.e [0] or [1]) the same as []. 

> 
> Note that my comments above are about what diagnostics are appropriate 
> under the standard.  They are *not* about how code generation might allow 
> for possible uses of certain source code constructs as if they were 
> flexible array members.  The two contexts may very well require different 
> notions of what counts as a flexible array member.

Yes. That’s right.

Thanks.

Qing
> 
> -- 
> Joseph S. Myers
> joseph@codesourcery.com


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-07 19:57                             ` Qing Zhao
@ 2023-02-07 23:37                               ` Joseph Myers
  2023-02-08 15:06                                 ` Qing Zhao
  0 siblings, 1 reply; 45+ messages in thread
From: Joseph Myers @ 2023-02-07 23:37 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Biener, gcc-patches, siddhesh, keescook

On Tue, 7 Feb 2023, Qing Zhao via Gcc-patches wrote:

> Then, this routine (flexible_array_type_p) is mainly for diagnostic purpose.
> It cannot be used to determine whether the structure/union type recursively
> include a flexible array member at the end.
> 
> Is my understanding correct?

My comments were about basic principles of what gets diagnosed, and the 
need for different predicates in different contexts; I wasn't trying to 
assert anything about how that maps onto what functions should be used in 
what contexts.

> >> 2. Only C99 standard flexible array member be included, [0] and [1] are 
> >> not included, for example:
> > 
> > Obviously we can't diagnose use of structures with [1] trailing members, 
> > because it's perfectly valid to embed those structures at any position 
> > inside other structures.  And the same is the case for the [0] extension 
> > when it's used to mean "empty array" rather than "flexible array".
> 
> With the -fstrict-flex-arrays available, we should be able to diagnose
> the flexible array member per gnu extension (i.e [0] or [1]) the same as []. 

There are different sorts of diagnostic that might be involved.

* Simply having [0] or [1] at the end of a structure embedded in another 
structure isn't appropriate to diagnose, because [0] and [1] have 
perfectly good meanings in such a context that aren't trying to be 
flexible array members at all.  [0] might be an empty type (possibly one 
that wouldn't be empty when built with a different configuration).  [1] 
might be the use of arrays in C to produce a passed-by-reference type.

* Trying to use such an embedded [0] or [1] array as if it were a flexible 
array member - i.e. accessing any member of the [0] array, or any member 
other than the [0] member of the [1] array - *is* a sign of the 
problematic use as a flexible array member, that might be appropriate to 
diagnose.  (Actually I'd guess the array index tends to be non-constant in 
accesses, and it would be odd to use a non-constant index when you mean 
that constant always to be 0, which it would need to be in the 
non-flexible case.)

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-07 23:37                               ` Joseph Myers
@ 2023-02-08 15:06                                 ` Qing Zhao
  2023-02-08 19:09                                   ` Joseph Myers
  2023-02-09 10:35                                   ` Richard Biener
  0 siblings, 2 replies; 45+ messages in thread
From: Qing Zhao @ 2023-02-08 15:06 UTC (permalink / raw)
  To: Joseph Myers, richard Biener; +Cc: gcc-patches, siddhesh, keescook



> On Feb 7, 2023, at 6:37 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> 
> On Tue, 7 Feb 2023, Qing Zhao via Gcc-patches wrote:
> 
>> Then, this routine (flexible_array_type_p) is mainly for diagnostic purpose.
>> It cannot be used to determine whether the structure/union type recursively
>> include a flexible array member at the end.
>> 
>> Is my understanding correct?
> 
> My comments were about basic principles of what gets diagnosed, and the 
> need for different predicates in different contexts; I wasn't trying to 
> assert anything about how that maps onto what functions should be used in 
> what contexts.
Okay. 

But I noticed that “flexible_array_type_p” later was moved from FE to
 middle-end and put into tree.cc, tree.h as a general utility routine, and to 

/* Determine whether TYPE is a structure with a flexible array member,
   or a union containing such a structure (possibly recursively).  */

However, since this routine does not cover the cases when the structure 
with flexible array member was recursively embedded into structures, (which we 
agreed that it should be considered as a flexible sized type). 

Therefore, I feel that It might not be proper to include this routine in middle end 
(and actually no other places In middle end use this routine so far).

That’s the reason I asked the previous question. 

It might be better to move the routine “flexible_array_type_p” back from middle-end to
FE for the diagnosis purpose only. 


> 
>>>> 2. Only C99 standard flexible array member be included, [0] and [1] are 
>>>> not included, for example:
>>> 
>>> Obviously we can't diagnose use of structures with [1] trailing members, 
>>> because it's perfectly valid to embed those structures at any position 
>>> inside other structures.  And the same is the case for the [0] extension 
>>> when it's used to mean "empty array" rather than "flexible array".
>> 
>> With the -fstrict-flex-arrays available, we should be able to diagnose
>> the flexible array member per gnu extension (i.e [0] or [1]) the same as []. 
> 
> There are different sorts of diagnostic that might be involved.
> 
> * Simply having [0] or [1] at the end of a structure embedded in another 
> structure isn't appropriate to diagnose, because [0] and [1] have 
> perfectly good meanings in such a context that aren't trying to be 
> flexible array members at all.  [0] might be an empty type (possibly one 
> that wouldn't be empty when built with a different configuration).  [1] 
> might be the use of arrays in C to produce a passed-by-reference type.


So, you mean, by default, Only having [] at the end of a structure embedded
 in another structure is considered to be flexible sized type?

i.e.
struct flex { int n; int data[ ]; };
struct out_flex_end { int m; struct flex0 flex_data; }; 
struct outer_flex_end{ int p; struct out_flex_end0 out_flex_data; }; 

In the above, all “flex”, “out_flex_end” and “outer_flex_end” are flexible sized type.

But:

struct flex0 { int n; int data[0]; };
struct out_flex_end0 { int m; struct flex0 flex_data; }; 
struct outer_flex_end0 { int p; struct out_flex_end0 out_flex_data; }; 

In the above, only “flex0” is flexible sized type by default. 
But “out_flex_end0” and “out_flex_end0” are Not considered as flexible sized type by default? 

> 
> * Trying to use such an embedded [0] or [1] array as if it were a flexible 
> array member - i.e. accessing any member of the [0] array, or any member 
> other than the [0] member of the [1] array - *is* a sign of the 
> problematic use as a flexible array member, that might be appropriate to 
> diagnose.

Yes, this was diagnosed with -Wstrict-flex-arrays + -fstrict-flex-arrays=n.

thanks.

Qing

>  (Actually I'd guess the array index tends to be non-constant in 
> accesses, and it would be odd to use a non-constant index when you mean 
> that constant always to be 0, which it would need to be in the 
> non-flexible case.)
> 
> -- 
> Joseph S. Myers
> joseph@codesourcery.com


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-08 15:06                                 ` Qing Zhao
@ 2023-02-08 19:09                                   ` Joseph Myers
  2023-02-08 19:20                                     ` Siddhesh Poyarekar
  2023-02-08 23:18                                     ` Qing Zhao
  2023-02-09 10:35                                   ` Richard Biener
  1 sibling, 2 replies; 45+ messages in thread
From: Joseph Myers @ 2023-02-08 19:09 UTC (permalink / raw)
  To: Qing Zhao; +Cc: richard Biener, gcc-patches, siddhesh, keescook

[-- Attachment #1: Type: text/plain, Size: 2007 bytes --]

On Wed, 8 Feb 2023, Qing Zhao via Gcc-patches wrote:

> But I noticed that “flexible_array_type_p” later was moved from FE to
>  middle-end and put into tree.cc, tree.h as a general utility routine, and to 
> 
> /* Determine whether TYPE is a structure with a flexible array member,
>    or a union containing such a structure (possibly recursively).  */
> 
> However, since this routine does not cover the cases when the structure 
> with flexible array member was recursively embedded into structures, (which we 
> agreed that it should be considered as a flexible sized type). 
> 
> Therefore, I feel that It might not be proper to include this routine in middle end 
> (and actually no other places In middle end use this routine so far).

I think we've established that diagnostics and at least some middle-end 
purposes need different conditions.  Diagnostics for nesting a structure 
with a flexible array member inside another structure should only count [] 
as a flexible array member, whereas permitting flexible array uses in the 
middle end should allow [0] and [1] under some circumstances (depending on 
command-line options).

> But:
> 
> struct flex0 { int n; int data[0]; };
> struct out_flex_end0 { int m; struct flex0 flex_data; }; 
> struct outer_flex_end0 { int p; struct out_flex_end0 out_flex_data; }; 
> 
> In the above, only “flex0” is flexible sized type by default. 
> But “out_flex_end0” and “out_flex_end0” are Not considered as flexible sized type by default? 

It would be OK (and I'm not saying here that this is necessarily 
desirable), since that's at the end of another structure rather than in 
the middle, to consider them flexible for the purposes of code generation.

What must be avoided is -pedantic diagnostics for

struct flex1 { int n; int data[1]; };
struct out_flex_end1 { int m; struct flex1 flex_data; };

regardless of whether considered flexible or not, since that's clearly 
valid in standard C.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-08 19:09                                   ` Joseph Myers
@ 2023-02-08 19:20                                     ` Siddhesh Poyarekar
  2023-02-08 20:51                                       ` Joseph Myers
  2023-02-08 22:53                                       ` Qing Zhao
  2023-02-08 23:18                                     ` Qing Zhao
  1 sibling, 2 replies; 45+ messages in thread
From: Siddhesh Poyarekar @ 2023-02-08 19:20 UTC (permalink / raw)
  To: Joseph Myers, Qing Zhao; +Cc: richard Biener, gcc-patches, keescook

On 2023-02-08 14:09, Joseph Myers wrote:
> What must be avoided is -pedantic diagnostics for
> 
> struct flex1 { int n; int data[1]; };
> struct out_flex_end1 { int m; struct flex1 flex_data; };
> 
> regardless of whether considered flexible or not, since that's clearly
> valid in standard C.
> 

Are you sure about "regardless of whether considered flexible or not", 
since ISTM the validity of the above in standard C is limited to when 
it's considered a non-flexible array.  So with -pedantic it shouldn't 
warn, but it also then shouldn't consider it a flexible array.

In other words, perhaps it makes sense to imply -fstrict-flex-arrays 
with -pedantic?

Sid

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-08 19:20                                     ` Siddhesh Poyarekar
@ 2023-02-08 20:51                                       ` Joseph Myers
  2023-02-08 22:53                                       ` Qing Zhao
  1 sibling, 0 replies; 45+ messages in thread
From: Joseph Myers @ 2023-02-08 20:51 UTC (permalink / raw)
  To: Siddhesh Poyarekar; +Cc: Qing Zhao, richard Biener, gcc-patches, keescook

On Wed, 8 Feb 2023, Siddhesh Poyarekar wrote:

> On 2023-02-08 14:09, Joseph Myers wrote:
> > What must be avoided is -pedantic diagnostics for
> > 
> > struct flex1 { int n; int data[1]; };
> > struct out_flex_end1 { int m; struct flex1 flex_data; };
> > 
> > regardless of whether considered flexible or not, since that's clearly
> > valid in standard C.
> > 
> 
> Are you sure about "regardless of whether considered flexible or not", since
> ISTM the validity of the above in standard C is limited to when it's
> considered a non-flexible array.  So with -pedantic it shouldn't warn, but it
> also then shouldn't consider it a flexible array.
> 
> In other words, perhaps it makes sense to imply -fstrict-flex-arrays with
> -pedantic?

There should be no code generation effects from -pedantic.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-08 19:20                                     ` Siddhesh Poyarekar
  2023-02-08 20:51                                       ` Joseph Myers
@ 2023-02-08 22:53                                       ` Qing Zhao
  1 sibling, 0 replies; 45+ messages in thread
From: Qing Zhao @ 2023-02-08 22:53 UTC (permalink / raw)
  To: Siddhesh Poyarekar; +Cc: Joseph Myers, richard Biener, gcc-patches, keescook



> On Feb 8, 2023, at 2:20 PM, Siddhesh Poyarekar <siddhesh@gotplt.org> wrote:
> 
> On 2023-02-08 14:09, Joseph Myers wrote:
>> What must be avoided is -pedantic diagnostics for
>> struct flex1 { int n; int data[1]; };
>> struct out_flex_end1 { int m; struct flex1 flex_data; };
>> regardless of whether considered flexible or not, since that's clearly
>> valid in standard C.
> 
> Are you sure about "regardless of whether considered flexible or not", since ISTM the validity of the above in standard C is limited to when it's considered a non-flexible array.  So with -pedantic it shouldn't warn, but it also then shouldn't consider it a flexible array.
> 
> In other words, perhaps it makes sense to imply -fstrict-flex-arrays with -pedantic?
I think -pedantic might imply -fstrict-flex-arrays=3, but not -fstrict-flex-arrays=n when n < 3. Right?

Qing
> 
> Sid


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-08 19:09                                   ` Joseph Myers
  2023-02-08 19:20                                     ` Siddhesh Poyarekar
@ 2023-02-08 23:18                                     ` Qing Zhao
  2023-02-09 14:40                                       ` Qing Zhao
  1 sibling, 1 reply; 45+ messages in thread
From: Qing Zhao @ 2023-02-08 23:18 UTC (permalink / raw)
  To: Joseph Myers, Richard Biener; +Cc: gcc-patches, siddhesh, keescook



> On Feb 8, 2023, at 2:09 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> 
> On Wed, 8 Feb 2023, Qing Zhao via Gcc-patches wrote:
> 
>> But I noticed that “flexible_array_type_p” later was moved from FE to
>> middle-end and put into tree.cc, tree.h as a general utility routine, and to 
>> 
>> /* Determine whether TYPE is a structure with a flexible array member,
>>   or a union containing such a structure (possibly recursively).  */
>> 
>> However, since this routine does not cover the cases when the structure 
>> with flexible array member was recursively embedded into structures, (which we 
>> agreed that it should be considered as a flexible sized type). 
>> 
>> Therefore, I feel that It might not be proper to include this routine in middle end 
>> (and actually no other places In middle end use this routine so far).
> 
> I think we've established that diagnostics and at least some middle-end 
> purposes need different conditions.

Yes, agreed.

>  Diagnostics for nesting a structure 
> with a flexible array member inside another structure should only count [] 
> as a flexible array member,

Diagnostics should be consistent with the documentation. 
The use cases that violate what is defined in documentation should be diagnostics. 

This include both C standard and GCC extension. 
For C standard violation, -pedantic will report them.
For GCC extension, the corresponding warning message should report them.

And both such warning can be issued either in FE or in Middle end. 

Is the above understand correct?

> whereas permitting flexible array uses in the 
> middle end should allow [0] and [1] under some circumstances (depending on 
> command-line options).

> 
>> But:
>> 
>> struct flex0 { int n; int data[0]; };
>> struct out_flex_end0 { int m; struct flex0 flex_data; }; 
>> struct outer_flex_end0 { int p; struct out_flex_end0 out_flex_data; }; 
>> 
>> In the above, only “flex0” is flexible sized type by default. 
>> But “out_flex_end0” and “out_flex_end0” are Not considered as flexible sized type by default? 
> 
> It would be OK (and I'm not saying here that this is necessarily 
> desirable), since that's at the end of another structure rather than in 
> the middle, to consider them flexible for the purposes of code generation.

This is the part I am still not very clear and not feel very comfortable:

In the documentation on GCC extension of embedding structure with flexible array member into another structure/union, 

Should we include [0], [1] and [n] cases as GCC extension by default? Or we only include [] for nested struct as an extension?

For example:

struct flex0  { int length; char data[0]; };

struct out_flex0 { int m; struct flex0 flex_data; };
struct out_flex0_mid  {  struct flex0 flex_data; int m};

Should we treat the above out_flex0->flex_data as flexible array by default?
Should we issue warning for the above out_flex9_mid with a new warning option -Wgnu-variable-sized-type-at-end?

How about the following:
struct flex1  { int length; char data[1]; };

struct out_flex1 { int m; struct flex1 flex_data; };
struct out_flex1_mid  {  struct flex1 flex_data; int m};

And:
struct flexn { int length; char data[4]; };

struct out_flexn { int m; struct flexn flex_data; };
struct out_flexn_mid  {  struct flexn flex_data; int m};

????


> 
> What must be avoided is -pedantic diagnostics for
> 
> struct flex1 { int n; int data[1]; };
> struct out_flex_end1 { int m; struct flex1 flex_data; };
> 
> regardless of whether considered flexible or not, since that's clearly 
> valid in standard C.
Yes, agreed.

Thanks.

Qing
> 
> -- 
> Joseph S. Myers
> joseph@codesourcery.com


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-08 15:06                                 ` Qing Zhao
  2023-02-08 19:09                                   ` Joseph Myers
@ 2023-02-09 10:35                                   ` Richard Biener
  2023-02-09 13:44                                     ` Qing Zhao
  1 sibling, 1 reply; 45+ messages in thread
From: Richard Biener @ 2023-02-09 10:35 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Joseph Myers, gcc-patches, siddhesh, keescook, sandra

[-- Attachment #1: Type: text/plain, Size: 2316 bytes --]

On Wed, 8 Feb 2023, Qing Zhao wrote:

> 
> 
> > On Feb 7, 2023, at 6:37 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> > 
> > On Tue, 7 Feb 2023, Qing Zhao via Gcc-patches wrote:
> > 
> >> Then, this routine (flexible_array_type_p) is mainly for diagnostic purpose.
> >> It cannot be used to determine whether the structure/union type recursively
> >> include a flexible array member at the end.
> >> 
> >> Is my understanding correct?
> > 
> > My comments were about basic principles of what gets diagnosed, and the 
> > need for different predicates in different contexts; I wasn't trying to 
> > assert anything about how that maps onto what functions should be used in 
> > what contexts.
> Okay. 
> 
> But I noticed that “flexible_array_type_p” later was moved from FE to
>  middle-end and put into tree.cc, tree.h as a general utility routine, and to 
> 
> /* Determine whether TYPE is a structure with a flexible array member,
>    or a union containing such a structure (possibly recursively).  */
> 
> However, since this routine does not cover the cases when the structure 
> with flexible array member was recursively embedded into structures, (which we 
> agreed that it should be considered as a flexible sized type). 
> 
> Therefore, I feel that It might not be proper to include this routine in middle end 
> (and actually no other places In middle end use this routine so far).
> 
> That’s the reason I asked the previous question. 
> 
> It might be better to move the routine “flexible_array_type_p” back from middle-end to
> FE for the diagnosis purpose only. 

It's always dangerous to move functions with such a descriptive name to
a place where it suggests wider use is applicable.  Also since
objc/objc-act.cc has a function with the same name (if that had same
content before r10-5097-g4569f8b3652ae1 then the function should
have been moved to c-family/ instead).

The only "middle-end" use, btw., is in ./config/nios2/nios2.cc,
intoduced by said revision and your points probably mean this change
was misguided and flexible_array_type_p isn't the thing to fix here.
flexible-size _objects_ are clearly denoted by DECL_SIZE being
non-constant - though the case of .sdata is quite odd and the issue
fixed is probably running into a bug elsewhere ...

Sandra?

Thanks,
Richard.


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-09 10:35                                   ` Richard Biener
@ 2023-02-09 13:44                                     ` Qing Zhao
  0 siblings, 0 replies; 45+ messages in thread
From: Qing Zhao @ 2023-02-09 13:44 UTC (permalink / raw)
  To: Richard Biener; +Cc: Joseph Myers, gcc-patches, siddhesh, keescook, sandra



> On Feb 9, 2023, at 5:35 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Wed, 8 Feb 2023, Qing Zhao wrote:
> 
>> 
>> 
>>> On Feb 7, 2023, at 6:37 PM, Joseph Myers <joseph@codesourcery.com> wrote:
>>> 
>>> On Tue, 7 Feb 2023, Qing Zhao via Gcc-patches wrote:
>>> 
>>>> Then, this routine (flexible_array_type_p) is mainly for diagnostic purpose.
>>>> It cannot be used to determine whether the structure/union type recursively
>>>> include a flexible array member at the end.
>>>> 
>>>> Is my understanding correct?
>>> 
>>> My comments were about basic principles of what gets diagnosed, and the 
>>> need for different predicates in different contexts; I wasn't trying to 
>>> assert anything about how that maps onto what functions should be used in 
>>> what contexts.
>> Okay. 
>> 
>> But I noticed that “flexible_array_type_p” later was moved from FE to
>> middle-end and put into tree.cc, tree.h as a general utility routine, and to 
>> 
>> /* Determine whether TYPE is a structure with a flexible array member,
>>   or a union containing such a structure (possibly recursively).  */
>> 
>> However, since this routine does not cover the cases when the structure 
>> with flexible array member was recursively embedded into structures, (which we 
>> agreed that it should be considered as a flexible sized type). 
>> 
>> Therefore, I feel that It might not be proper to include this routine in middle end 
>> (and actually no other places In middle end use this routine so far).
>> 
>> That’s the reason I asked the previous question. 
>> 
>> It might be better to move the routine “flexible_array_type_p” back from middle-end to
>> FE for the diagnosis purpose only. 
> 
> It's always dangerous to move functions with such a descriptive name to
> a place where it suggests wider use is applicable.  Also since
> objc/objc-act.cc has a function with the same name (if that had same
> content before r10-5097-g4569f8b3652ae1 then the function should
> have been moved to c-family/ instead).
The routine “flexible_array_type_p” in objc/objc-act.cc is a little different from the one in middle-end:

It includes the ARRAY_TYPE in addition to RECORD_TYPE and UNION_TYPE.
> 
> The only "middle-end" use, btw., is in ./config/nios2/nios2.cc,
> intoduced by said revision and your points probably mean this change
> was misguided and flexible_array_type_p isn't the thing to fix here.

Yes, I guess so. 

Qing
> flexible-size _objects_ are clearly denoted by DECL_SIZE being
> non-constant - though the case of .sdata is quite odd and the issue
> fixed is probably running into a bug elsewhere ...
> 
> Sandra?
> 
> Thanks,
> Richard.


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-08 23:18                                     ` Qing Zhao
@ 2023-02-09 14:40                                       ` Qing Zhao
  2023-02-09 16:46                                         ` Kees Cook
  0 siblings, 1 reply; 45+ messages in thread
From: Qing Zhao @ 2023-02-09 14:40 UTC (permalink / raw)
  To: Richard Biener, Joseph Myers, kees Cook; +Cc: gcc-patches, siddhesh



> On Feb 8, 2023, at 6:18 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
> 
> 
>> On Feb 8, 2023, at 2:09 PM, Joseph Myers <joseph@codesourcery.com> wrote:
>> 
>> On Wed, 8 Feb 2023, Qing Zhao via Gcc-patches wrote:
>> 
>>> But I noticed that “flexible_array_type_p” later was moved from FE to
>>> middle-end and put into tree.cc, tree.h as a general utility routine, and to 
>>> 
>>> /* Determine whether TYPE is a structure with a flexible array member,
>>>  or a union containing such a structure (possibly recursively).  */
>>> 
>>> However, since this routine does not cover the cases when the structure 
>>> with flexible array member was recursively embedded into structures, (which we 
>>> agreed that it should be considered as a flexible sized type). 
>>> 
>>> Therefore, I feel that It might not be proper to include this routine in middle end 
>>> (and actually no other places In middle end use this routine so far).
>> 
>> I think we've established that diagnostics and at least some middle-end 
>> purposes need different conditions.
> 
> Yes, agreed.
> 
>> Diagnostics for nesting a structure 
>> with a flexible array member inside another structure should only count [] 
>> as a flexible array member,
> 
> Diagnostics should be consistent with the documentation. 
> The use cases that violate what is defined in documentation should be diagnostics. 
> 
> This include both C standard and GCC extension. 
> For C standard violation, -pedantic will report them.
> For GCC extension, the corresponding warning message should report them.
> 
> And both such warning can be issued either in FE or in Middle end. 
> 
> Is the above understand correct?
> 
>> whereas permitting flexible array uses in the 
>> middle end should allow [0] and [1] under some circumstances (depending on 
>> command-line options).
> 
>> 
>>> But:
>>> 
>>> struct flex0 { int n; int data[0]; };
>>> struct out_flex_end0 { int m; struct flex0 flex_data; }; 
>>> struct outer_flex_end0 { int p; struct out_flex_end0 out_flex_data; }; 
>>> 
>>> In the above, only “flex0” is flexible sized type by default. 
>>> But “out_flex_end0” and “out_flex_end0” are Not considered as flexible sized type by default? 
>> 
>> It would be OK (and I'm not saying here that this is necessarily 
>> desirable), since that's at the end of another structure rather than in 
>> the middle, to consider them flexible for the purposes of code generation.
> 
> This is the part I am still not very clear and not feel very comfortable:
> 
> In the documentation on GCC extension of embedding structure with flexible array member into another structure/union, 
> 
> Should we include [0], [1] and [n] cases as GCC extension by default? Or we only include [] for nested struct as an extension?
> 
> For example:
> 
> struct flex0  { int length; char data[0]; };
> 
> struct out_flex0 { int m; struct flex0 flex_data; };
> struct out_flex0_mid  {  struct flex0 flex_data; int m};
> 
> Should we treat the above out_flex0->flex_data as flexible array by default?
> Should we issue warning for the above out_flex9_mid with a new warning option -Wgnu-variable-sized-type-at-end?
> 
> How about the following:
> struct flex1  { int length; char data[1]; };
> 
> struct out_flex1 { int m; struct flex1 flex_data; };
> struct out_flex1_mid  {  struct flex1 flex_data; int m};
> 
> And:
> struct flexn { int length; char data[4]; };
> 
> struct out_flexn { int m; struct flexn flex_data; };
> struct out_flexn_mid  {  struct flexn flex_data; int m};
> 
> ????
> 

More thought on the above:

I think that we need to be more careful with the documentation of the GCC extension on embedding structure with flexible array member into the end of another structure/union. 
As Richard mentioned before, documentation might encourage people to use it…

So, the major question here is:

 in addition to the C99 standard flexible array member [ ], shall we include [0], [1] or even [4] into this extension, and treat the structure with a trailing [0], [1], or [4] embedded into another structure/union still as flexible-sized?

I think that we might need to limit this extension ONLY to C99 standard FAM [ ].  All other [0], [1], or [4] should be excluded from this extension. The reasons are:

1. The real usages of such GCC extension (embedding structure with FAM into another structure/union), as my understanding, the old glibc’s <_G_config.h> (https://gcc.gnu.org/legacy-ml/gcc-patches/2002-08/msg01149.html), and the bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101832, ONLY involved C99 standard FAM;

2. Embedding a structure with C99 FAM [] into the end of another structure, and still treat it flexible sized might have more usages, and as discussed with Kees, it might be reasonable to promote this into a  C standard later if needed.

So, based on this consideration, I think I should only document the following as GCC extension:

struct flex  { int length; char data[ ]; };
struct out_flex { int m; struct flex flex_data; };

Issue warnings for the following: (when the structure is not at the end)

struct out_flex_mid  {  struct flex flex_data; int m};


However, for the trailing [0], [1], or [4], when such structure embedded into the end of another structure, We should NOT treat the outer structure as flexible sized. 
Logically, we will NOT issue warnings when such structure is not at the end. 

Let me know if you have any comment or suggestions.

thanks.

Qing 
> 
>> 
>> What must be avoided is -pedantic diagnostics for
>> 
>> struct flex1 { int n; int data[1]; };
>> struct out_flex_end1 { int m; struct flex1 flex_data; };
>> 
>> regardless of whether considered flexible or not, since that's clearly 
>> valid in standard C.
> Yes, agreed.
> 
> Thanks.
> 
> Qing
>> 
>> -- 
>> Joseph S. Myers
>> joseph@codesourcery.com


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-09 14:40                                       ` Qing Zhao
@ 2023-02-09 16:46                                         ` Kees Cook
  2023-02-10 15:25                                           ` Qing Zhao
  0 siblings, 1 reply; 45+ messages in thread
From: Kees Cook @ 2023-02-09 16:46 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Biener, Joseph Myers, gcc-patches, siddhesh

On Thu, Feb 09, 2023 at 02:40:57PM +0000, Qing Zhao wrote:
> So, the major question here is:
> 
>  in addition to the C99 standard flexible array member [ ], shall we include [0], [1] or even [4] into this extension, and treat the structure with a trailing [0], [1], or [4] embedded into another structure/union still as flexible-sized?
> 
> I think that we might need to limit this extension ONLY to C99 standard FAM [ ].  All other [0], [1], or [4] should be excluded from this extension. The reasons are:
> 
> 1. The real usages of such GCC extension (embedding structure with FAM into another structure/union), as my understanding, the old glibc’s <_G_config.h> (https://gcc.gnu.org/legacy-ml/gcc-patches/2002-08/msg01149.html), and the bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101832, ONLY involved C99 standard FAM;
> 
> 2. Embedding a structure with C99 FAM [] into the end of another structure, and still treat it flexible sized might have more usages, and as discussed with Kees, it might be reasonable to promote this into a  C standard later if needed.
> 
> So, based on this consideration, I think I should only document the following as GCC extension:
> 
> struct flex  { int length; char data[ ]; };
> struct out_flex { int m; struct flex flex_data; };
> 
> Issue warnings for the following: (when the structure is not at the end)
> 
> struct out_flex_mid  {  struct flex flex_data; int m};
> 
> 
> However, for the trailing [0], [1], or [4], when such structure embedded into the end of another structure, We should NOT treat the outer structure as flexible sized. 
> Logically, we will NOT issue warnings when such structure is not at the end. 
> 
> Let me know if you have any comment or suggestions.

FWIW this all sounds correct to me.

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832]
  2023-02-09 16:46                                         ` Kees Cook
@ 2023-02-10 15:25                                           ` Qing Zhao
  0 siblings, 0 replies; 45+ messages in thread
From: Qing Zhao @ 2023-02-10 15:25 UTC (permalink / raw)
  To: Kees Cook, Richard Biener, Joseph Myers; +Cc: gcc-patches, siddhesh

Thanks, Kees.

If there is no objection, I will update my patches with this. And send the updated patches soon.

Qing

> On Feb 9, 2023, at 11:46 AM, Kees Cook <keescook@chromium.org> wrote:
> 
> On Thu, Feb 09, 2023 at 02:40:57PM +0000, Qing Zhao wrote:
>> So, the major question here is:
>> 
>> in addition to the C99 standard flexible array member [ ], shall we include [0], [1] or even [4] into this extension, and treat the structure with a trailing [0], [1], or [4] embedded into another structure/union still as flexible-sized?
>> 
>> I think that we might need to limit this extension ONLY to C99 standard FAM [ ].  All other [0], [1], or [4] should be excluded from this extension. The reasons are:
>> 
>> 1. The real usages of such GCC extension (embedding structure with FAM into another structure/union), as my understanding, the old glibc’s <_G_config.h> (https://gcc.gnu.org/legacy-ml/gcc-patches/2002-08/msg01149.html), and the bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101832, ONLY involved C99 standard FAM;
>> 
>> 2. Embedding a structure with C99 FAM [] into the end of another structure, and still treat it flexible sized might have more usages, and as discussed with Kees, it might be reasonable to promote this into a  C standard later if needed.
>> 
>> So, based on this consideration, I think I should only document the following as GCC extension:
>> 
>> struct flex  { int length; char data[ ]; };
>> struct out_flex { int m; struct flex flex_data; };
>> 
>> Issue warnings for the following: (when the structure is not at the end)
>> 
>> struct out_flex_mid  {  struct flex flex_data; int m};
>> 
>> 
>> However, for the trailing [0], [1], or [4], when such structure embedded into the end of another structure, We should NOT treat the outer structure as flexible sized. 
>> Logically, we will NOT issue warnings when such structure is not at the end. 
>> 
>> Let me know if you have any comment or suggestions.
> 
> FWIW this all sounds correct to me.
> 
> -- 
> Kees Cook


^ permalink raw reply	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2023-02-10 15:25 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-31 14:11 [PATCH 0/2]PR101832: Handle component_ref to a structure/union field including flexible array member for builtin_object_size Qing Zhao
2023-01-31 14:11 ` [PATCH 1/2] Handle component_ref to a structre/union field including flexible array member [PR101832] Qing Zhao
2023-02-01 11:41   ` Richard Biener
2023-02-01 14:19     ` Qing Zhao
2023-02-02  8:07       ` Richard Biener
2023-02-02 13:52         ` Qing Zhao
2023-02-02 13:54           ` Richard Biener
2023-02-02 14:38             ` Qing Zhao
2023-02-03  7:49               ` Richard Biener
2023-02-03 13:17                 ` Qing Zhao
2023-02-06  9:31                   ` Richard Biener
2023-02-06 14:38                     ` Qing Zhao
2023-02-06 23:14                       ` Joseph Myers
2023-02-07 14:54                         ` Qing Zhao
2023-02-07 19:17                           ` Joseph Myers
2023-02-07 19:57                             ` Qing Zhao
2023-02-07 23:37                               ` Joseph Myers
2023-02-08 15:06                                 ` Qing Zhao
2023-02-08 19:09                                   ` Joseph Myers
2023-02-08 19:20                                     ` Siddhesh Poyarekar
2023-02-08 20:51                                       ` Joseph Myers
2023-02-08 22:53                                       ` Qing Zhao
2023-02-08 23:18                                     ` Qing Zhao
2023-02-09 14:40                                       ` Qing Zhao
2023-02-09 16:46                                         ` Kees Cook
2023-02-10 15:25                                           ` Qing Zhao
2023-02-09 10:35                                   ` Richard Biener
2023-02-09 13:44                                     ` Qing Zhao
2023-02-07 15:28                         ` Siddhesh Poyarekar
2023-02-07 15:38                           ` Qing Zhao
2023-02-01 16:48   ` Siddhesh Poyarekar
2023-02-01 18:20     ` Qing Zhao
2023-01-31 14:11 ` [PATCH 2/2] Documentation Update Qing Zhao
2023-02-01 16:55   ` Siddhesh Poyarekar
2023-02-01 18:24     ` Qing Zhao
2023-02-01 18:57       ` Siddhesh Poyarekar
2023-02-01 19:19         ` Qing Zhao
2023-02-02  8:33         ` Richard Biener
2023-02-02 14:31           ` Qing Zhao
2023-02-02 17:05             ` Kees Cook
2023-02-03 15:56               ` Jeff Law
2023-02-03  4:25           ` Siddhesh Poyarekar
2023-02-03 14:52             ` Qing Zhao
2023-02-03 20:55             ` Joseph Myers
2023-02-03 22:38               ` Qing Zhao

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).