when the type is a structure with flexible array member. In tree-object-size.cc, if the size is UNKNOWN after evaluating use-def chain, We can evaluate the SIZE of the pointee TYPE ONLY when this TYPE is a structure type with flexible array member, since a structure with FAM can not be an element of an array, so, the pointer must point to a single object with this structure with FAM.
This is only available for C now. bootstrapped and regression tested on both x86 and aarch64. Okay for stage1? thanks. Qing gcc/c/ChangeLog: * c-lang.cc (LANG_HOOKS_BUILD_COUNTED_BY_REF): Define to below function. * c-tree.h (c_build_counted_by_ref): New extern function. * c-typeck.cc (build_counted_by_ref): Rename to ... (c_build_counted_by_ref): ...this. (handle_counted_by_for_component_ref): Call the renamed function. gcc/ChangeLog: * langhooks-def.h (LANG_HOOKS_BUILD_COUNTED_BY_REF): New language hook. * langhooks.h (struct lang_hooks_for_types): Add build_counted_by_ref. * tree-object-size.cc (struct object_size_info): Add a new field insert_after. (gimplify_size_expressions): Insert sequence after or before depending on the new field insert_after. (compute_builtin_object_size): Init the new field to false; (record_with_fam_object_size): New function. (collect_object_sizes_for): Call record_with_fam_object_size. gcc/testsuite/ChangeLog: * gcc.dg/flex-array-counted-by-3.c: Update test; * gcc.dg/flex-array-counted-by-4.c: Likewise. * gcc.dg/flex-array-counted-by-5.c: Likewise. --- gcc/c/c-lang.cc | 3 + gcc/c/c-tree.h | 1 + gcc/c/c-typeck.cc | 6 +- gcc/langhooks-def.h | 4 +- gcc/langhooks.h | 5 + .../gcc.dg/flex-array-counted-by-3.c | 5 + .../gcc.dg/flex-array-counted-by-4.c | 34 ++++-- .../gcc.dg/flex-array-counted-by-5.c | 4 + gcc/tree-object-size.cc | 106 +++++++++++++++++- 9 files changed, 152 insertions(+), 16 deletions(-) diff --git a/gcc/c/c-lang.cc b/gcc/c/c-lang.cc index c69077b2a93..e9ec9e6e64a 100644 --- a/gcc/c/c-lang.cc +++ b/gcc/c/c-lang.cc @@ -51,6 +51,9 @@ enum c_language_kind c_language = clk_c; #undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE #define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE c_get_sarif_source_language +#undef LANG_HOOKS_BUILD_COUNTED_BY_REF +#define LANG_HOOKS_BUILD_COUNTED_BY_REF c_build_counted_by_ref + /* Each front end provides its own lang hook initializer. */ struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 743ec5cbae6..66bec5d92fa 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -776,6 +776,7 @@ extern struct c_switch *c_switch_stack; extern bool null_pointer_constant_p (const_tree); +extern tree c_build_counted_by_ref (tree, tree, tree *); inline bool c_type_variably_modified_p (tree t) diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 19e79b554dc..6efc3fb3e5d 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -2936,8 +2936,8 @@ should_suggest_deref_p (tree datum_type) &(p->k) */ -static tree -build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type) +tree +c_build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type) { tree type = TREE_TYPE (datum); if (!c_flexible_array_member_type_p (TREE_TYPE (subdatum))) @@ -3031,7 +3031,7 @@ handle_counted_by_for_component_ref (location_t loc, tree ref) tree datum = TREE_OPERAND (ref, 0); tree subdatum = TREE_OPERAND (ref, 1); tree counted_by_type = NULL_TREE; - tree counted_by_ref = build_counted_by_ref (datum, subdatum, + tree counted_by_ref = c_build_counted_by_ref (datum, subdatum, &counted_by_type); if (counted_by_ref) ref = build_access_with_size_for_counted_by (loc, ref, diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index 6b34d324ab5..7909ea8a92c 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -221,6 +221,7 @@ extern tree lhd_unit_size_without_reusable_padding (tree); #define LANG_HOOKS_TYPE_DWARF_ATTRIBUTE lhd_type_dwarf_attribute #define LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING lhd_unit_size_without_reusable_padding #define LANG_HOOKS_CLASSTYPE_AS_BASE hook_tree_const_tree_null +#define LANG_HOOKS_BUILD_COUNTED_BY_REF NULL #define LANG_HOOKS_FOR_TYPES_INITIALIZER { \ LANG_HOOKS_MAKE_TYPE, \ @@ -248,7 +249,8 @@ extern tree lhd_unit_size_without_reusable_padding (tree); LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO, \ LANG_HOOKS_TYPE_DWARF_ATTRIBUTE, \ LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING, \ - LANG_HOOKS_CLASSTYPE_AS_BASE \ + LANG_HOOKS_CLASSTYPE_AS_BASE, \ + LANG_HOOKS_BUILD_COUNTED_BY_REF \ } /* Declaration hooks. */ diff --git a/gcc/langhooks.h b/gcc/langhooks.h index dc8d878c7fb..797c8bcc0c0 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -190,6 +190,11 @@ struct lang_hooks_for_types i.e., type without virtual base classes or tail padding. Returns NULL_TREE otherwise. */ tree (*classtype_as_base) (const_tree); + + /* Build a REF to the object that represents the counted_by per the attribute + counted_by attached to the field. Otherwise return NULL_TREE. Set the + TYPE of the counted_by field to the last parameter. */ + tree (*build_counted_by_ref) (tree, tree, tree *); }; /* Language hooks related to decls and the symbol table. */ diff --git a/gcc/testsuite/gcc.dg/flex-array-counted-by-3.c b/gcc/testsuite/gcc.dg/flex-array-counted-by-3.c index 78f50230e89..88ad50bea6b 100644 --- a/gcc/testsuite/gcc.dg/flex-array-counted-by-3.c +++ b/gcc/testsuite/gcc.dg/flex-array-counted-by-3.c @@ -53,6 +53,11 @@ void __attribute__((__noinline__)) test () array_annotated->b * sizeof (int)); EXPECT(__builtin_dynamic_object_size(array_nested_annotated->c, 1), array_nested_annotated->b * sizeof (int)); + EXPECT(__builtin_dynamic_object_size(array_annotated, 1), + sizeof (struct annotated) + array_annotated->b * sizeof (int)); + EXPECT(__builtin_dynamic_object_size(array_nested_annotated, 1), + sizeof (struct nested_annotated) + + array_nested_annotated->b * sizeof (int)); } int main(int argc, char *argv[]) diff --git a/gcc/testsuite/gcc.dg/flex-array-counted-by-4.c b/gcc/testsuite/gcc.dg/flex-array-counted-by-4.c index 20103d58ef5..6ac2be4471d 100644 --- a/gcc/testsuite/gcc.dg/flex-array-counted-by-4.c +++ b/gcc/testsuite/gcc.dg/flex-array-counted-by-4.c @@ -23,7 +23,15 @@ struct annotated { So, __builtin_object_size can not directly use the type of the pointee to decide the size of the object the pointer points to. - There are only two reliable ways: + However, if the pointer points to a strucure with FAM, and the FAM is + annotated with counted_by attribute, we can get the size of the pointee + object by the size of the structure type and the counted_by attribute + since structure with FAM cannot be an element of an array, the pointer + that points to such type must point to a single object with the type, + therefore, we can decide the size of the object from the size of the + type for the pointee. + + There are other two reliable ways: A. observed allocations (call to the allocation functions in the routine) B. observed accesses (read or write access to the location of the pointer points to) @@ -155,11 +163,13 @@ int main () EXPECT(__builtin_dynamic_object_size(p->array, 2), p->foo * sizeof(char)); EXPECT(__builtin_dynamic_object_size(p->array, 3), p->foo * sizeof(char)); /* When checking the pointer p, we have no observed allocation nor observed - access, therefore, we cannot determine the size info here. */ - EXPECT(__builtin_dynamic_object_size(p, 0), -1); - EXPECT(__builtin_dynamic_object_size(p, 1), -1); - EXPECT(__builtin_dynamic_object_size(p, 2), 0); - EXPECT(__builtin_dynamic_object_size(p, 3), 0); + access, however, since the pointer points to a strucure with FAM, and the + FAM is annotated with counted_by attribute, we can get the size of the + pointee object by the size of the TYPE and the counted_by attribute. */ + EXPECT(__builtin_dynamic_object_size(p, 0), 19); + EXPECT(__builtin_dynamic_object_size(p, 1), 19); + EXPECT(__builtin_dynamic_object_size(p, 2), 19); + EXPECT(__builtin_dynamic_object_size(p, 3), 19); /* When checking the access p->array, we only have info on the counted-by value. */ @@ -168,11 +178,13 @@ int main () EXPECT(__builtin_dynamic_object_size(q->array, 2), q->foo * sizeof(char)); EXPECT(__builtin_dynamic_object_size(q->array, 3), q->foo * sizeof(char)); /* When checking the pointer p, we have no observed allocation nor observed - access, therefore, we cannot determine the size info here. */ - EXPECT(__builtin_dynamic_object_size(q, 0), -1); - EXPECT(__builtin_dynamic_object_size(q, 1), -1); - EXPECT(__builtin_dynamic_object_size(q, 2), 0); - EXPECT(__builtin_dynamic_object_size(q, 3), 0); + access, however, since the pointer points to a strucure with FAM, and the + FAM is annotated with counted_by attribute, we can get the size of the + pointee object by the size of the TYPE and the counted_by attribute. */ + EXPECT(__builtin_dynamic_object_size(q, 0), 29); + EXPECT(__builtin_dynamic_object_size(q, 1), 29); + EXPECT(__builtin_dynamic_object_size(q, 2), 29); + EXPECT(__builtin_dynamic_object_size(q, 3), 29); DONE (); } diff --git a/gcc/testsuite/gcc.dg/flex-array-counted-by-5.c b/gcc/testsuite/gcc.dg/flex-array-counted-by-5.c index 68f9b0f7c8d..44bfce9976f 100644 --- a/gcc/testsuite/gcc.dg/flex-array-counted-by-5.c +++ b/gcc/testsuite/gcc.dg/flex-array-counted-by-5.c @@ -38,6 +38,10 @@ void __attribute__((__noinline__)) test () { EXPECT(__builtin_dynamic_object_size(array_annotated->c, 1), 0); EXPECT(__builtin_dynamic_object_size(array_nested_annotated->c, 1), 0); + EXPECT(__builtin_dynamic_object_size(array_annotated, 1), + sizeof (struct annotated)); + EXPECT(__builtin_dynamic_object_size(array_nested_annotated, 1), + sizeof (struct nested_annotated)); } int main(int argc, char *argv[]) diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc index f348673ae75..5ff2da18f50 100644 --- a/gcc/tree-object-size.cc +++ b/gcc/tree-object-size.cc @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see #include "fold-const.h" #include "tree-object-size.h" #include "gimple-iterator.h" +#include "langhooks.h" #include "gimple-fold.h" #include "tree-cfg.h" #include "tree-dfa.h" @@ -45,6 +46,7 @@ struct object_size_info int object_size_type; unsigned char pass; bool changed; + bool insert_after; bitmap visited, reexamine; unsigned int *depths; unsigned int *stack, *tos; @@ -1174,7 +1176,10 @@ gimplify_size_expressions (object_size_info *osi) gsi = gsi_for_stmt (stmt); force_gimple_operand (size_expr, &seq, true, NULL); - gsi_insert_seq_before (&gsi, seq, GSI_CONTINUE_LINKING); + if (osi->insert_after) + gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING); + else + gsi_insert_seq_before (&gsi, seq, GSI_CONTINUE_LINKING); } } @@ -1279,6 +1284,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, expression needs to be gimplified. */ osi.pass = 0; osi.changed = false; + osi.insert_after = false; collect_object_sizes_for (&osi, ptr); if (object_size_type & OST_DYNAMIC) @@ -1768,6 +1774,89 @@ phi_dynamic_object_size (struct object_size_info *osi, tree var) object_sizes_set (osi, varno, sizes, wholesizes); } +/* Compute an object size expression for VAR, whose pointee TYPE is a + structure with flexible array member. */ + +static void +record_with_fam_object_size (struct object_size_info *osi, tree var) +{ + int object_size_type = osi->object_size_type; + tree size = size_unknown (object_size_type); + + tree pointee_type = TREE_TYPE (TREE_TYPE (var)); + tree counted_by_ref = NULL_TREE; + tree counted_by_type = NULL_TREE; + tree last = NULL_TREE; + + if (TREE_CODE (pointee_type) == RECORD_TYPE + && flexible_array_type_p (pointee_type)) + { + for (tree x = TYPE_FIELDS (pointee_type); x != NULL_TREE; + x = DECL_CHAIN (x)) + if (TREE_CODE (x) == FIELD_DECL + && TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE + && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE + && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE + && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE + && DECL_CHAIN (x) == NULL_TREE) + last = x; + /* Check whether the last FAM field has a counted_by attribute. + If so, build a counted_by reference. */ + if (last + && lookup_attribute ("counted_by", DECL_ATTRIBUTES (last)) + && lang_hooks.types.build_counted_by_ref) + { + tree datum = build1 (INDIRECT_REF, pointee_type, var); + counted_by_ref + = lang_hooks.types.build_counted_by_ref (datum, last, + &counted_by_type); + } + } + + /* If the counted_by reference is available, the size of the whole structure + can be computed. */ + if (counted_by_ref) + { + tree element_type = TREE_TYPE (TREE_TYPE (last)); + tree element_size = TYPE_SIZE_UNIT (element_type); + size = fold_build2 (MEM_REF, counted_by_type, counted_by_ref, + build_int_cst (ptr_type_node, 0)); + /* If counted_by is a negative value, treat it as zero. */ + if (!TYPE_UNSIGNED (counted_by_type)) + { + tree cond_expr = fold_build2 (LT_EXPR, boolean_type_node, + unshare_expr (size), + build_zero_cst (counted_by_type)); + size = fold_build3 (COND_EXPR, integer_type_node, cond_expr, + build_zero_cst (counted_by_type), size); + } + + /* The total size of the whole object is computed as: + MAX (sizeof (pointee_type), + offsetof (pointee_type, last) + counted_by * element_size). */ + size = size_binop (MULT_EXPR, + fold_convert (sizetype, size), + fold_convert (sizetype, element_size)); + size = size_binop (PLUS_EXPR, + byte_position (last), + size); + size = size_binop (MAX_EXPR, + TYPE_SIZE_UNIT (pointee_type), + size); + if (!todo) + todo = TODO_update_ssa_only_virtuals; + + } + /* Initialize to 0 for maximum size and M1U for minimum size so that + it gets immediately overridden. */ + object_sizes_initialize (osi, SSA_NAME_VERSION (var), + size_initval (object_size_type), + size_initval (object_size_type)); + + osi->insert_after = true; + object_sizes_set (osi, SSA_NAME_VERSION (var), size, size); +} + /* Compute object sizes for VAR. For ADDR_EXPR an object size is the number of remaining bytes to the end of the object (where what is considered an object depends on @@ -1922,6 +2011,21 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) gcc_unreachable (); } + /* If the size is UNKNOWN after evaluating use-def chain, We can evaluate + * the SIZE of the pointee TYPE ONLY when this TYPE is a structure type + * with flexible array member, Since a structure with FAM can not be an + * element of an array, so, PTR must point to an single object with this + * strucure with FAM. */ + + if (object_sizes_unknown_p (object_size_type, varno) + && object_size_type & OST_DYNAMIC + && POINTER_TYPE_P (TREE_TYPE (var))) + { + const_tree pointee_type = TREE_TYPE (TREE_TYPE (var)); + if (flexible_array_type_p (pointee_type)) + record_with_fam_object_size (osi, var); + } + /* Dynamic sizes use placeholder temps to return an answer, so it is always safe to set COMPUTED for them. */ if ((object_size_type & OST_DYNAMIC) -- 2.43.5