public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Qing Zhao <qing.zhao@oracle.com>
To: joseph@codesourcery.com, richard.guenther@gmail.com,
	jakub@redhat.com, gcc-patches@gcc.gnu.org
Cc: keescook@chromium.org, siddhesh@gotplt.org, uecker@tugraz.at,
	isanbard@gmail.com, Qing Zhao <qing.zhao@oracle.com>
Subject: [V1][PATCH 1/3] Provide element_count attribute to flexible array member field (PR108896)
Date: Thu, 25 May 2023 16:14:48 +0000	[thread overview]
Message-ID: <20230525161450.3704901-2-qing.zhao@oracle.com> (raw)
In-Reply-To: <20230525161450.3704901-1-qing.zhao@oracle.com>

'element_count ("COUNT")'
     The 'element_count' attribute may be attached to the flexible array
     member of a structure.  It indicates that the number of the
     elements of the array is given by the field named "COUNT" in the
     same structure as the flexible array member.  GCC uses this
     information to improve the results of
     '__builtin_dynamic_object_size' and array bound sanitizer.

     For instance, the following declaration:

          struct P {
            size_t count;
            int array[] __attribute__ ((element_count ("count")));
          };

     specify that 'array' is a flexible array member whose number of
     element is given by the field "'count'" in the same structure.

The number of elements information provided by this attribute can be
used by __builtin_dynamic_object_size and array bound sanitizer to detect
out-of-bound errors for flexible array member references.

2023-05-17 Qing Zhao <qing.zhao@oracle.com>

gcc/c-family/ChangeLog:

	PR C/108896
	* c-attribs.cc (handle_element_count_attribute): New function.
	* c-common.cc (c_flexible_array_member_type_p): To this.
	* c-common.h (c_flexible_array_member_type_p): New prototype.

gcc/c/ChangeLog:

	PR C/108896
	* c-decl.cc (flexible_array_member_type_p): Renamed and moved to...
	(add_flexible_array_elts_to_size): Use renamed function.
	(is_flexible_array_member_p): Use renamed function.
	(verify_element_count_attribute): New function.
	(finish_struct): Use renamed function and verify element count
	attribute.

gcc/ChangeLog:

	PR C/108896
	* doc/extend.texi: Document attribute element_count.

gcc/testsuite/ChangeLog:

	PR C/108896
	* gcc.dg/flex-array-element-count.c: New test.
---
 gcc/c-family/c-attribs.cc                     | 51 ++++++++++++++++
 gcc/c-family/c-common.cc                      | 13 ++++
 gcc/c-family/c-common.h                       |  1 +
 gcc/c/c-decl.cc                               | 61 ++++++++++++++-----
 gcc/doc/extend.texi                           | 21 +++++++
 .../gcc.dg/flex-array-element-count.c         | 27 ++++++++
 6 files changed, 158 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/flex-array-element-count.c

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 072cfb69147..d45d11077c3 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -103,6 +103,8 @@ static tree handle_warn_if_not_aligned_attribute (tree *, tree, tree,
 						  int, bool *);
 static tree handle_strict_flex_array_attribute (tree *, tree, tree,
 						 int, bool *);
+static tree handle_element_count_attribute (tree *, tree, tree,
+					   int, bool *);
 static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ;
 static tree handle_noplt_attribute (tree *, tree, tree, int, bool *) ;
 static tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *);
@@ -373,6 +375,8 @@ const struct attribute_spec c_common_attribute_table[] =
 			      handle_warn_if_not_aligned_attribute, NULL },
   { "strict_flex_array",      1, 1, true, false, false, false,
 			      handle_strict_flex_array_attribute, NULL },
+  { "element_count",	      1, 1, true, false, false, false,
+			      handle_element_count_attribute, NULL },
   { "weak",                   0, 0, true,  false, false, false,
 			      handle_weak_attribute, NULL },
   { "noplt",                   0, 0, true,  false, false, false,
@@ -2555,6 +2559,53 @@ handle_strict_flex_array_attribute (tree *node, tree name,
   return NULL_TREE;
 }
 
+/* Handle a "element_count" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_element_count_attribute (tree *node, tree name,
+				tree args, int ARG_UNUSED (flags),
+				bool *no_add_attrs)
+{
+  tree decl = *node;
+  tree argval = TREE_VALUE (args);
+
+  /* This attribute only applies to field decls of a structure.  */
+  if (TREE_CODE (decl) != FIELD_DECL)
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+		"%qE attribute may not be specified for non-field"
+		" declaration %q+D", name, decl);
+      *no_add_attrs = true;
+    }
+  /* This attribute only applies to field with array type.  */
+  else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE)
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+		"%qE attribute may not be specified for a non-array field",
+		name);
+      *no_add_attrs = true;
+    }
+  /* This attribute only applies to a C99 flexible array member type.  */
+  else if (! c_flexible_array_member_type_p (TREE_TYPE (decl)))
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+		"%qE attribute may not be specified for a non"
+		" flexible array member field",
+		name);
+      *no_add_attrs = true;
+    }
+  /* The argument of the attribute should be a string.  */
+  else if (TREE_CODE (argval) != STRING_CST)
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+		"%qE attribute argument not a string", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "weak" attribute; arguments as in
    struct attribute_spec.handler.  */
 
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 2b4c82facf7..b2bf7a230e2 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -9516,6 +9516,19 @@ c_common_finalize_early_debug (void)
       (*debug_hooks->early_global_decl) (cnode->decl);
 }
 
+/* Determine whether TYPE is a ISO C99 flexible array memeber type "[]".  */
+bool
+c_flexible_array_member_type_p (const_tree type)
+{
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && TYPE_SIZE (type) == NULL_TREE
+      && TYPE_DOMAIN (type) != NULL_TREE
+      && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
+    return true;
+
+  return false;
+}
+
 /* Get the LEVEL of the strict_flex_array for the ARRAY_FIELD based on the
    values of attribute strict_flex_array and the flag_strict_flex_arrays.  */
 unsigned int
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index f96350b64af..77f6633b862 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -907,6 +907,7 @@ extern tree fold_for_warn (tree);
 extern tree c_common_get_narrower (tree, int *);
 extern bool get_attribute_operand (tree, unsigned HOST_WIDE_INT *);
 extern void c_common_finalize_early_debug (void);
+extern bool c_flexible_array_member_type_p (const_tree);
 extern unsigned int c_strict_flex_array_level_of (tree);
 extern bool c_option_is_from_cpp_diagnostics (int);
 
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index f8ede362bfd..0f25fe0be0d 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5187,19 +5187,6 @@ set_array_declarator_inner (struct c_declarator *decl,
   return decl;
 }
 
-/* Determine whether TYPE is a ISO C99 flexible array memeber type "[]".  */
-static bool
-flexible_array_member_type_p (const_tree type)
-{
-  if (TREE_CODE (type) == ARRAY_TYPE
-      && TYPE_SIZE (type) == NULL_TREE
-      && TYPE_DOMAIN (type) != NULL_TREE
-      && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
-    return true;
-
-  return false;
-}
-
 /* Determine whether TYPE is a one-element array type "[1]".  */
 static bool
 one_element_array_type_p (const_tree type)
@@ -5236,7 +5223,7 @@ add_flexible_array_elts_to_size (tree decl, tree init)
 
   elt = CONSTRUCTOR_ELTS (init)->last ().value;
   type = TREE_TYPE (elt);
-  if (flexible_array_member_type_p (type))
+  if (c_flexible_array_member_type_p (type))
     {
       complete_array_type (&type, elt, false);
       DECL_SIZE (decl)
@@ -9087,7 +9074,7 @@ is_flexible_array_member_p (bool is_last_field,
 
   bool is_zero_length_array = zero_length_array_type_p (TREE_TYPE (x));
   bool is_one_element_array = one_element_array_type_p (TREE_TYPE (x));
-  bool is_flexible_array = flexible_array_member_type_p (TREE_TYPE (x));
+  bool is_flexible_array = c_flexible_array_member_type_p (TREE_TYPE (x));
 
   unsigned int strict_flex_array_level = c_strict_flex_array_level_of (x);
 
@@ -9117,6 +9104,45 @@ is_flexible_array_member_p (bool is_last_field,
   return false;
 }
 
+/* Verify the argument of the element_count attribute of the flexible array
+   member FIELD_DECL is a valid field of the containing structure's fieldlist,
+   FIELDLIST, Report error when it's not.  */
+static void
+verify_element_count_attribute (tree fieldlist, tree field_decl)
+{
+  tree attr_element_count = lookup_attribute ("element_count",
+					      DECL_ATTRIBUTES (field_decl));
+
+  if (!attr_element_count)
+    return;
+
+  /* If there is an element_count attribute attached to the field,
+     verify it.  */
+
+  const char *fieldname
+    = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr_element_count)));
+
+  /* Verify the argument of the attrbute is a valid field of the
+     containing structure.  */
+
+  tree element_count_field = NULL_TREE;
+  for (tree field = fieldlist; field; field = DECL_CHAIN (field))
+    if (TREE_CODE (field) == FIELD_DECL
+	&& DECL_NAME (field) != NULL
+	&& strcmp (IDENTIFIER_POINTER (DECL_NAME (field)), fieldname) == 0)
+      {
+	element_count_field = field;
+	break;
+      }
+
+  /* Error when the field is not found in the containing structure.  */
+  if (!element_count_field)
+      error_at (DECL_SOURCE_LOCATION (field_decl),
+		"%qE attribute argument not a field declaration"
+		" in the same structure",
+		(get_attribute_name (attr_element_count)));
+  return;
+}
 
 /* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T.
    LOC is the location of the RECORD_TYPE or UNION_TYPE's definition.
@@ -9237,7 +9263,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
 	DECL_PACKED (x) = 1;
 
       /* Detect flexible array member in an invalid context.  */
-      if (flexible_array_member_type_p (TREE_TYPE (x)))
+      if (c_flexible_array_member_type_p (TREE_TYPE (x)))
 	{
 	  if (TREE_CODE (t) == UNION_TYPE)
 	    {
@@ -9258,6 +9284,9 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
 			"members");
 	      TREE_TYPE (x) = error_mark_node;
 	    }
+	  /* if there is an element_count attribute attached to this field,
+	     verify it.  */
+	  verify_element_count_attribute (fieldlist, x);
 	}
 
       if (pedantic && TREE_CODE (t) == RECORD_TYPE
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 69b21a75e62..cdbe3923ef1 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7501,6 +7501,27 @@ When both the attribute and the option present at the same time, the level of
 the strictness for the specific trailing array field is determined by the
 attribute.
 
+@cindex @code{element_count} variable attribute
+@item element_count ("@var{count}")
+The @code{element_count} attribute may be attached to the flexible array
+member of a structure.  It indicates that the number of the elements of the
+array is given by the field named "@var{count}" in the same structure as the
+flexible array member.  GCC uses this information to improve the results of
+@code{__builtin_dynamic_object_size} and array bound sanitizer.
+
+For instance, the following declaration:
+
+@smallexample
+struct P @{
+  size_t count;
+  int array[] __attribute__ ((element_count ("count")));
+@};
+@end smallexample
+
+@noindent
+specify that @code{array} is a flexible array member whose number of element
+is given by the field "@code{count}" in the same structure.
+
 @cindex @code{alloc_size} variable attribute
 @item alloc_size (@var{position})
 @itemx alloc_size (@var{position-1}, @var{position-2})
diff --git a/gcc/testsuite/gcc.dg/flex-array-element-count.c b/gcc/testsuite/gcc.dg/flex-array-element-count.c
new file mode 100644
index 00000000000..988f41e9f5e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/flex-array-element-count.c
@@ -0,0 +1,27 @@
+/* testing the correct usage of attribute element_count.  */   
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+int size;
+int x __attribute ((element_count ("size"))); /* { dg-error "attribute may not be specified for non-field declaration" } */
+
+struct trailing {
+  int count;
+  int field __attribute ((element_count ("count"))); /* { dg-error "attribute may not be specified for a non-array field" } */
+};
+
+struct trailing_1 {
+  int count;
+  int array_1[0] __attribute ((element_count ("count"))); /* { dg-error "attribute may not be specified for a non flexible array member field" } */
+};
+
+int count;
+struct trailing_array_2 {
+  int count;
+  int array_2[] __attribute ((element_count (count))); /* { dg-error "attribute argument not a string" } */
+};
+
+struct trailing_array_3 {
+  int other;
+  int array_3[] __attribute ((element_count ("count"))); /* { dg-error "attribute argument not a field declaration in the same structure" } */
+};
-- 
2.31.1


  reply	other threads:[~2023-05-25 16:15 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-25 16:14 [V1][PATCH 0/3] New attribute "element_count" to annotate bounds for C99 FAM(PR108896) Qing Zhao
2023-05-25 16:14 ` Qing Zhao [this message]
2023-05-25 21:02   ` [V1][PATCH 1/3] Provide element_count attribute to flexible array member field (PR108896) Joseph Myers
2023-05-26 13:32     ` Qing Zhao
2023-05-26 18:15       ` Joseph Myers
2023-05-26 19:09         ` Qing Zhao
2023-06-07 19:59         ` Qing Zhao
2023-06-07 20:53           ` Joseph Myers
2023-06-07 21:32             ` Qing Zhao
2023-06-07 22:05               ` Joseph Myers
2023-06-08 13:06                 ` Qing Zhao
2023-06-15 15:09                 ` Qing Zhao
2023-06-15 16:55                   ` Joseph Myers
2023-06-15 19:54                     ` Qing Zhao
2023-06-15 22:48                       ` Joseph Myers
2023-06-16 15:01                         ` Qing Zhao
2023-06-16  7:21                     ` Martin Uecker
2023-06-16 15:14                       ` Qing Zhao
2023-06-16 16:21                       ` Joseph Myers
2023-06-16 17:07                         ` Martin Uecker
2023-06-16 20:20                           ` Qing Zhao
2023-06-16 21:35                             ` Joseph Myers
2023-06-20 19:40                               ` Qing Zhao
2023-06-27 15:44                                 ` Qing Zhao
2023-05-25 16:14 ` [V1][PATCH 2/3] Use the element_count atribute info in builtin object size [PR108896] Qing Zhao
2023-05-27 10:20   ` Martin Uecker
2023-05-30 16:08     ` Qing Zhao
2023-05-25 16:14 ` [V1][PATCH 3/3] Use the element_count attribute information in bound sanitizer[PR108896] Qing Zhao
2023-05-26 16:12 ` [V1][PATCH 0/3] New attribute "element_count" to annotate bounds for C99 FAM(PR108896) Kees Cook
2023-05-30 21:44   ` Qing Zhao
2023-05-26 20:40 ` Kees Cook
2023-05-30 15:43   ` Qing Zhao
2023-07-06 18:56   ` Qing Zhao
2023-07-06 21:10     ` Martin Uecker
2023-07-07 15:47       ` Qing Zhao
2023-07-07 20:21         ` Qing Zhao
2023-07-13 20:31     ` Kees Cook
2023-07-17 21:17       ` Qing Zhao
2023-07-17 23:40         ` Kees Cook
2023-07-18 15:37           ` Qing Zhao
2023-07-18 16:03             ` Martin Uecker
2023-07-18 16:25               ` Qing Zhao
2023-07-18 16:50                 ` Martin Uecker
2023-07-18 18:53             ` Qing Zhao
2023-07-19  8:41           ` Martin Uecker
2023-07-19 16:16           ` Qing Zhao
2023-07-19 18:52           ` Qing Zhao
2023-07-31 20:14             ` Qing Zhao
2023-08-01 22:45               ` Kees Cook
2023-08-02  6:25                 ` Martin Uecker
2023-08-02 15:02                   ` Qing Zhao
2023-08-02 15:09                 ` Qing Zhao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230525161450.3704901-2-qing.zhao@oracle.com \
    --to=qing.zhao@oracle.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=isanbard@gmail.com \
    --cc=jakub@redhat.com \
    --cc=joseph@codesourcery.com \
    --cc=keescook@chromium.org \
    --cc=richard.guenther@gmail.com \
    --cc=siddhesh@gotplt.org \
    --cc=uecker@tugraz.at \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).