diff options
author | Qing Zhao <qing.zhao@oracle.com> | 2024-05-28 18:30:05 +0000 |
---|---|---|
committer | Qing Zhao <qing.zhao@oracle.com> | 2024-05-31 16:40:23 +0000 |
commit | f824acd0e807546a733c122ab6340f18cef88766 (patch) | |
tree | 5c316a5e6f7bce0a6f12a92778f9ebe6b665d3e4 /gcc/c | |
parent | 0ac802064c2a018cf166c37841697e867de65a95 (diff) | |
download | gcc-f824acd0e807546a733c122ab6340f18cef88766.zip gcc-f824acd0e807546a733c122ab6340f18cef88766.tar.gz gcc-f824acd0e807546a733c122ab6340f18cef88766.tar.bz2 |
Provide counted_by attribute to flexible array member field
'counted_by (COUNT)'
The 'counted_by' attribute may be attached to the C99 flexible
array member of a structure. It indicates that the number of the
elements of the array is given by the field "COUNT" in the
same structure as the flexible array member.
GCC may use this information to improve detection of object size information
for such structures and provide better results in compile-time diagnostics
and runtime features like the array bound sanitizer and
the '__builtin_dynamic_object_size'.
For instance, the following code:
struct P {
size_t count;
char other;
char array[] __attribute__ ((counted_by (count)));
} *p;
specifies that the 'array' is a flexible array member whose number
of elements is given by the field 'count' in the same structure.
The field that represents the number of the elements should have an
integer type. Otherwise, the compiler reports an error and
ignores the attribute.
When the field that represents the number of the elements is assigned a
negative integer value, the compiler treats the value as zero.
An explicit 'counted_by' annotation defines a relationship between
two objects, 'p->array' and 'p->count', and there are the following
requirementthat on the relationship between this pair:
* 'p->count' must be initialized before the first reference to
'p->array';
* 'p->array' has _at least_ 'p->count' number of elements
available all the time. This relationship must hold even
after any of these related objects are updated during the
program.
It's the user's responsibility to make sure the above requirements
to be kept all the time. Otherwise the compiler reports
warnings, at the same time, the results of the array bound
sanitizer and the '__builtin_dynamic_object_size' is undefined.
One important feature of the attribute is, a reference to the
flexible array member field uses the latest value assigned to
the field that represents the number of the elements before that
reference. For example,
p->count = val1;
p->array[20] = 0; // ref1 to p->array
p->count = val2;
p->array[30] = 0; // ref2 to p->array
in the above, 'ref1' uses 'val1' as the number of the elements
in 'p->array', and 'ref2' uses 'val2' as the number of elements
in 'p->array'.
gcc/c-family/ChangeLog:
* c-attribs.cc (handle_counted_by_attribute): New function.
(attribute_takes_identifier_p): Add counted_by attribute to the list.
* 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:
* 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_counted_by_attribute): New function.
(finish_struct): Use renamed function and verify counted_by
attribute.
* c-tree.h (lookup_field): New prototype.
* c-typeck.cc (lookup_field): Expose as extern function.
(tagged_types_tu_compatible_p): Check counted_by attribute for
structure type.
gcc/ChangeLog:
* doc/extend.texi: Document attribute counted_by.
gcc/testsuite/ChangeLog:
* gcc.dg/flex-array-counted-by.c: New test.
* gcc.dg/flex-array-counted-by-7.c: New test.
* gcc.dg/flex-array-counted-by-8.c: New test.
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/c-decl.cc | 80 | ||||
-rw-r--r-- | gcc/c/c-tree.h | 1 | ||||
-rw-r--r-- | gcc/c/c-typeck.cc | 37 |
3 files changed, 98 insertions, 20 deletions
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 9f7d55c..64924b8 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -5303,19 +5303,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) @@ -5353,7 +5340,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); /* For a structure, add the size of the initializer to the DECL's @@ -9340,7 +9327,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); @@ -9410,6 +9397,55 @@ c_update_type_canonical (tree t) } } +/* Verify the argument of the counted_by attribute of the flexible array + member FIELD_DECL is a valid field of the containing structure, + STRUCT_TYPE, Report error and remove this attribute when it's not. */ + +static void +verify_counted_by_attribute (tree struct_type, tree field_decl) +{ + tree attr_counted_by = lookup_attribute ("counted_by", + DECL_ATTRIBUTES (field_decl)); + + if (!attr_counted_by) + return; + + /* If there is an counted_by attribute attached to the field, + verify it. */ + + tree fieldname = TREE_VALUE (TREE_VALUE (attr_counted_by)); + + /* Verify the argument of the attrbute is a valid field of the + containing structure. */ + + tree counted_by_field = lookup_field (struct_type, fieldname); + + /* Error when the field is not found in the containing structure. */ + if (!counted_by_field) + error_at (DECL_SOURCE_LOCATION (field_decl), + "argument %qE to the %qE attribute is not a field declaration" + " in the same structure as %qD", fieldname, + (get_attribute_name (attr_counted_by)), + field_decl); + + else + /* Error when the field is not with an integer type. */ + { + while (TREE_CHAIN (counted_by_field)) + counted_by_field = TREE_CHAIN (counted_by_field); + tree real_field = TREE_VALUE (counted_by_field); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (real_field))) + error_at (DECL_SOURCE_LOCATION (field_decl), + "argument %qE to the %qE attribute is not a field declaration" + " with an integer type", fieldname, + (get_attribute_name (attr_counted_by))); + + } + + 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. FIELDLIST is a chain of FIELD_DECL nodes for the fields. @@ -9470,6 +9506,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, until now.) */ bool saw_named_field = false; + tree counted_by_fam_field = NULL_TREE; for (x = fieldlist; x; x = DECL_CHAIN (x)) { /* Whether this field is the last field of the structure or union. @@ -9530,7 +9567,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) pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic, @@ -9545,6 +9582,12 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic, "flexible array member in a struct with no named " "members is a GCC extension"); + + /* If there is a counted_by attribute attached to this field, + record it here and do more verification later after the + whole structure is complete. */ + if (lookup_attribute ("counted_by", DECL_ATTRIBUTES (x))) + counted_by_fam_field = x; } if (pedantic && TREE_CODE (t) == RECORD_TYPE @@ -9559,7 +9602,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, when x is an array and is the last field. */ if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE) TYPE_INCLUDES_FLEXARRAY (t) - = is_last_field && flexible_array_member_type_p (TREE_TYPE (x)); + = is_last_field && c_flexible_array_member_type_p (TREE_TYPE (x)); /* Recursively set TYPE_INCLUDES_FLEXARRAY for the context of x, t when x is an union or record and is the last field. */ else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))) @@ -9816,6 +9859,9 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, struct_parse_info->struct_types.safe_push (t); } + if (counted_by_fam_field) + verify_counted_by_attribute (t, counted_by_fam_field); + return t; } diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 22b0009..531a7e8 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -777,6 +777,7 @@ extern struct c_expr convert_lvalue_to_rvalue (location_t, struct c_expr, extern tree decl_constant_value_1 (tree, bool); extern void mark_exp_read (tree); extern tree composite_type (tree, tree); +extern tree lookup_field (const_tree, tree); extern tree build_component_ref (location_t, tree, tree, location_t, location_t); extern tree build_array_ref (location_t, tree, tree); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 4893480..80ed599 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -101,7 +101,6 @@ static bool function_types_compatible_p (const_tree, const_tree, struct comptypes_data *); static bool type_lists_compatible_p (const_tree, const_tree, struct comptypes_data *); -static tree lookup_field (tree, tree); static int convert_arguments (location_t, vec<location_t>, tree, vec<tree, va_gc> *, vec<tree, va_gc> *, tree, tree); @@ -1691,6 +1690,38 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, && st2 && TREE_CODE (st2) == INTEGER_CST && !tree_int_cst_equal (st1, st2)) return false; + + tree counted_by1 = lookup_attribute ("counted_by", + DECL_ATTRIBUTES (s1)); + tree counted_by2 = lookup_attribute ("counted_by", + DECL_ATTRIBUTES (s2)); + /* If there is no counted_by attribute for both fields. */ + if (!counted_by1 && !counted_by2) + continue; + + /* If only one field has counted_by attribute. */ + if ((counted_by1 && !counted_by2) + || (!counted_by1 && counted_by2)) + return false; + + /* Now both s1 and s2 have counted_by attributes, check + whether they are the same. */ + + tree counted_by_field1 + = lookup_field (t1, TREE_VALUE (TREE_VALUE (counted_by1))); + tree counted_by_field2 + = lookup_field (t2, TREE_VALUE (TREE_VALUE (counted_by2))); + + gcc_assert (counted_by_field1 && counted_by_field2); + + while (TREE_CHAIN (counted_by_field1)) + counted_by_field1 = TREE_CHAIN (counted_by_field1); + while (TREE_CHAIN (counted_by_field2)) + counted_by_field2 = TREE_CHAIN (counted_by_field2); + + if (DECL_NAME (TREE_VALUE (counted_by_field1)) + != DECL_NAME (TREE_VALUE (counted_by_field2))) + return false; } return true; @@ -2449,8 +2480,8 @@ default_conversion (tree exp) the component is embedded within (nested) anonymous structures or unions, the list steps down the chain to the component. */ -static tree -lookup_field (tree type, tree component) +tree +lookup_field (const_tree type, tree component) { tree field; |