Ping. thanks.
Qing > On May 7, 2025, at 12:59, Qing Zhao <qing.z...@oracle.com> wrote: > > Hi, > > This is the 2nd version of the patch for: > > Evaluate the object size by the size of the pointee type when the type > is a structure with flexible array member which is annotated with > counted_by. > > Per the following discussion: (Questions on replacing a structure > pointer reference to a call to .ACCESS_WITH_SIZE in C FE) > > https://gcc.gnu.org/pipermail/gcc-patches/2025-April/680540.html > https://gcc.gnu.org/pipermail/gcc-patches/2025-April/681229.html > > The summary of the above discussion: > A. It’s not safe in general to replace a structure pointer > reference to a call to .ACCESS_WITH_SIZE in C FE. > Since data-flow analysis is needed to make sure that the access > to the size member is valid, i.e, the structure is accessible > and initialized, etc. > > B. It should be safe to generate the reference to field member > when we evaluate the BDOS builtin as the 1st version of the > patch . And doing this in tree-object-size should also cover > -fsanitize=object-size. > > C. When generating the reference to the field member in tree-object-size, > we should guard this reference with a checking on the pointer to > the structure is valid. > > Compare to the 1st version, the major changes are based on the above: > > 1. Update the comments per Sid's suggestions. > 2. Reorg the code to make it easily to be understood: > Add a new routine "is_pointee_fam_struct_with_counted_by" to make > the checking easier; > 3. Add one more cond_expr to guard the size_expr as: > > (prt == NULL) ? SIZE_UNKNOWN : SIZE_EXPR > > 4. In order to gimplify the above COND_EXPR (the current > force_gimple_operand doesnot work for the new control flow), Add > one more new routine "insert_cond_and_size" to construct the > whole control flow graph for the above cond_expr. Please refer to: > https://gcc.gnu.org/pipermail/gcc-patches/2025-April/682021.html > for this discussion. > > 5. Add new testing cases for testing the prt==NULL cases. > > The patch has been bootstrapped and regression tested on both x86 and aarch64. > > Okay for trunk? > > thanks. > > Qing > > ======================================================================== > 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 which is attached a > counted_by attribute, 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. > > 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_cf. > (insert_cond_and_size): New function. > (gimplify_size_expressions): Handle new field insert_cf. > (compute_builtin_object_size): Init the new field to false; > (is_pointee_fam_struct_with_counted_by): New function. > (record_with_fam_object_size): New function. > (collect_object_sizes_for): Call record_with_fam_object_size. > (dynamic_object_sizes_execute_one): Special handling for insert_cf. > > gcc/testsuite/ChangeLog: > > * gcc.dg/flex-array-counted-by-3.c: Update test for whole object size; > * gcc.dg/flex-array-counted-by-4.c: Likewise. > * gcc.dg/flex-array-counted-by-5.c: Likewise. > * gcc.dg/flex-array-counted-by-10.c: New test. > --- > 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-10.c | 41 +++ > .../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 | 302 +++++++++++++++++- > 10 files changed, 383 insertions(+), 22 deletions(-) > create mode 100644 gcc/testsuite/gcc.dg/flex-array-counted-by-10.c > > 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 2098120de29..648fb0551e6 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 55d896e02df..dffabacc3c5 100644 > --- a/gcc/c/c-typeck.cc > +++ b/gcc/c/c-typeck.cc > @@ -2946,8 +2946,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))) > @@ -3045,7 +3045,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-10.c > b/gcc/testsuite/gcc.dg/flex-array-counted-by-10.c > new file mode 100644 > index 00000000000..27d21f214f9 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/flex-array-counted-by-10.c > @@ -0,0 +1,41 @@ > +/* Test the attribute counted_by and its usage in > + __builtin_dynamic_object_size for whole object: when the pointer to the > whole > + object is NULL. */ > +/* { dg-do run } */ > +/* { dg-options "-O2" } */ > + > +#include "builtin-object-size-common.h" > +struct annotated { > + int count; > + char array[] __attribute__((counted_by (count))); > +}; > + > +static int __attribute__((__noinline__,__noipa__)) size_of (struct annotated > * obj) > +{ > + return __builtin_dynamic_object_size (obj, 0); > +} > + > +static int __attribute__((__noinline__,__noipa__)) size_of_1 (struct > annotated * obj) > +{ > + return __builtin_dynamic_object_size (obj, 1); > +} > + > +static int __attribute__((__noinline__,__noipa__)) size_of_2 (struct > annotated * obj) > +{ > + return __builtin_dynamic_object_size (obj, 2); > +} > + > +static int __attribute__((__noinline__,__noipa__)) size_of_3 (struct > annotated * obj) > +{ > + return __builtin_dynamic_object_size (obj, 3); > +} > + > +int main() > +{ > + EXPECT (size_of (0), -1); > + EXPECT (size_of_1 (0), -1); > + EXPECT (size_of_2 (0), 0); > + EXPECT (size_of_3 (0), 0); > + return 0; > +} > + > 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..11c6ac326da 100644 > --- a/gcc/testsuite/gcc.dg/flex-array-counted-by-5.c > +++ b/gcc/testsuite/gcc.dg/flex-array-counted-by-5.c > @@ -36,6 +36,10 @@ void __attribute__((__noinline__)) setup (int attr_count) > > void __attribute__((__noinline__)) test () > { > + EXPECT(__builtin_dynamic_object_size(array_annotated, 1), > + sizeof (struct annotated)); > + EXPECT(__builtin_dynamic_object_size(array_nested_annotated, 1), > + sizeof (struct nested_annotated)); > EXPECT(__builtin_dynamic_object_size(array_annotated->c, 1), 0); > EXPECT(__builtin_dynamic_object_size(array_nested_annotated->c, 1), 0); > } > diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc > index f348673ae75..a0b440b4700 100644 > --- a/gcc/tree-object-size.cc > +++ b/gcc/tree-object-size.cc > @@ -24,12 +24,15 @@ along with GCC; see the file COPYING3. If not see > #include "backend.h" > #include "tree.h" > #include "gimple.h" > +#include "cfghooks.h" > #include "tree-pass.h" > #include "ssa.h" > #include "gimple-pretty-print.h" > #include "fold-const.h" > +#include "cfgloop.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 +48,7 @@ struct object_size_info > int object_size_type; > unsigned char pass; > bool changed; > + bool insert_cf; > bitmap visited, reexamine; > unsigned int *depths; > unsigned int *stack, *tos; > @@ -1086,6 +1090,153 @@ propagate_unknowns (object_size_info *osi, tree expr, > bitmap unknowns) > } > } > > +/* Given a DEF_STMT, which is the DEF_STMT of the SSA_NAME whose > + object size is queried, and COND, SIZE_UNKNOWN, SIZE, the final > + RESULT. > + > + Generate the gimple sequence for the following: > + > + result = COND ? SIZE_UNKNOWN : SIZE; > + > + and then insert this new sequence in the proper position based on > + DEF_STMT: > + > + A. If DEF_STMT is valid, the generated gimple sequence should be > + inserted AFTER the DEF_STMT; > + > + B. If DEF_STMT is GIMPLE_NOP, i.e., no def is available, such as > + the parameter case. Under such situation, the new generated > + gimple sequence should be inserted in the very beginning of the > + current basic block. > + > + The following is the new generated IR if DEF_STMT is valid: > + > + OLD: > + cur_bb: > + DEF_STMT; > + > + NEW: > + cur_bb: > + DEF_STMT; > + if (COND) then goto then_bb > + else goto else_bb > + > + then_bb: (very likely) > + tmp_size_1 = SIZE; > + goto cur_bb_post; > + > + else_bb: (unlikely) > + tmp_size_2 = SIZE_UNKNOWN; > + goto cur_bb_post; > + > + cur_bb_post: > + tmp_size_3 = PHI (tmp_size_1, tmp_size_2); > + result = tmp_size_3; > + */ > + > +static void > +insert_cond_and_size (gimple *def_stmt, tree cond, > + tree size_unknown, tree size, > + tree result) > +{ > + enum gimple_code code = gimple_code (def_stmt); > + basic_block cur_bb; > + edge e; > + gimple_stmt_iterator gsi; > + /* Split the cur_bb to cur_bb and cur_bb_post based on DEF_STMT. > + if DEF_STMT is NOT GIMPLE_NOP, split it after DEF_STMT, otherwise, > + split it after the label of the block. */ > + if (code == GIMPLE_NOP) > + { > + cur_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)); > + e = split_block (cur_bb, (gimple *) NULL); > + gsi = gsi_end_bb (cur_bb); > + } > + else > + { > + cur_bb = gimple_bb (def_stmt); > + e = split_block (cur_bb, def_stmt); > + gsi = gsi_for_stmt (def_stmt); > + } > + > + basic_block cur_bb_post = e->dest; > + > + /* Create new basic blocks then_bb and else_bb. */ > + basic_block then_bb = create_empty_bb (cur_bb); > + basic_block else_bb = create_empty_bb (then_bb); > + add_bb_to_loop (then_bb, cur_bb->loop_father); > + add_bb_to_loop (else_bb, cur_bb->loop_father); > + loops_state_set (LOOPS_NEED_FIXUP); > + > + /* Set up the edges between cur_bb, then_bb, else_bb, and cur_bb_post. > + OLD: > + cur_bb > + |e > + V > + cur_bb_post > + > + NEW: > + cur_bb > + /e0 \e1 > + V V > + then_bb else_bb > + \e2 /e3 > + V > + cur_bb_post > + */ > + cur_bb_post->count = e->count (); > + remove_edge (e); > + edge e0 = make_edge (cur_bb, then_bb, EDGE_TRUE_VALUE); > + e0->probability = profile_probability::very_likely (); > + then_bb->count = e0->count (); > + edge e1 = make_edge (cur_bb, else_bb, EDGE_FALSE_VALUE); > + e1->probability = profile_probability::very_unlikely (); > + else_bb->count = e1->count (); > + edge e2 = make_single_succ_edge (then_bb, cur_bb_post, EDGE_FALLTHRU); > + edge e3 = make_single_succ_edge (else_bb, cur_bb_post, EDGE_FALLTHRU); > + > + /* Update dominance info for the newly created blocks. */ > + if (dom_info_available_p (CDI_DOMINATORS)) > + { > + set_immediate_dominator (CDI_DOMINATORS, then_bb, cur_bb); > + set_immediate_dominator (CDI_DOMINATORS, else_bb, cur_bb); > + set_immediate_dominator (CDI_DOMINATORS, cur_bb_post, cur_bb); > + } > + > + /* Insert new gimples into corresponding blocks. */ > + > + /* Insert the new COND gimple into cur_bb after GSI. */ > + gcond *cond_stmt = gimple_build_cond_from_tree (cond, NULL_TREE, > NULL_TREE); > + gsi_insert_after (&gsi, cond_stmt, GSI_NEW_STMT); > + > + /* Insert the new assign gimple tmp_size_1 = SIZE into then_bb. */ > + tree tmp_size = create_tmp_var (TREE_TYPE (result), "tmp_size"); > + gimple_seq seq = NULL; > + tree tmp_size_1 = force_gimple_operand (size, &seq, true, tmp_size); > + gimple_stmt_iterator new_gsi = gsi_start_bb (then_bb); > + gsi_insert_seq_after (&new_gsi, seq, GSI_LAST_NEW_STMT); > + > + /* Insert the new assign gimple tmp_size_2 = SIZE_UNKNOWN into else_bb. */ > + tree tmp_size_2 = make_ssa_name (tmp_size); > + gassign *assign_stmt = gimple_build_assign (tmp_size_2, size_unknown); > + gimple_set_location (assign_stmt, UNKNOWN_LOCATION); > + new_gsi = gsi_start_bb (else_bb); > + gsi_insert_after (&new_gsi, assign_stmt, GSI_LAST_NEW_STMT); > + > + /* Insert the new phi gimple tmp_size_3 = phi (tmp_size_1, tmp_size_2) > + into cur_bb_post. */ > + tree tmp_size_3 = make_ssa_name (tmp_size); > + gphi *phi = create_phi_node (tmp_size_3, cur_bb_post); > + add_phi_arg (phi, tmp_size_1, e2, UNKNOWN_LOCATION); > + add_phi_arg (phi, tmp_size_2, e3, UNKNOWN_LOCATION); > + /* Then insert a new assign gimple result = tmp_size_3 into cur_bb_post. > */ > + assign_stmt = gimple_build_assign (result, tmp_size_3); > + new_gsi = gsi_start_bb (cur_bb_post); > + gsi_insert_before (&new_gsi, assign_stmt, GSI_NEW_STMT); > + > + return; > +} > + > /* Walk through size expressions that need reexamination and generate > statements for them. */ > > @@ -1167,14 +1318,30 @@ gimplify_size_expressions (object_size_info *osi) > > if (size_expr) > { > - gimple_stmt_iterator gsi; > - if (code == GIMPLE_NOP) > - gsi = gsi_start_bb (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun))); > + if (osi->insert_cf) > + { > + gcc_assert (TREE_CODE (size_expr) == MODIFY_EXPR); > + tree result = TREE_OPERAND (size_expr, 0); > + size_expr = TREE_OPERAND (size_expr, 1); > + > + gcc_assert (TREE_CODE (size_expr) == COND_EXPR); > + tree cond = COND_EXPR_COND (size_expr); > + tree size = COND_EXPR_THEN (size_expr); > + tree size_unknown = COND_EXPR_ELSE (size_expr); > + insert_cond_and_size (stmt, cond, > + size_unknown, size, result); > + } > else > - gsi = gsi_for_stmt (stmt); > - > - force_gimple_operand (size_expr, &seq, true, NULL); > - gsi_insert_seq_before (&gsi, seq, GSI_CONTINUE_LINKING); > + { > + gimple_stmt_iterator gsi; > + if (code == GIMPLE_NOP) > + gsi = gsi_start_bb (single_succ > + (ENTRY_BLOCK_PTR_FOR_FN (cfun))); > + else > + gsi = gsi_for_stmt (stmt); > + force_gimple_operand (size_expr, &seq, true, NULL); > + gsi_insert_seq_before (&gsi, seq, GSI_CONTINUE_LINKING); > + } > } > } > > @@ -1279,6 +1446,7 @@ compute_builtin_object_size (tree ptr, int > object_size_type, > expression needs to be gimplified. */ > osi.pass = 0; > osi.changed = false; > + osi.insert_cf = false; > collect_object_sizes_for (&osi, ptr); > > if (object_size_type & OST_DYNAMIC) > @@ -1403,6 +1571,109 @@ expr_object_size (struct object_size_info *osi, tree > ptr, tree value) > object_sizes_set (osi, varno, bytes, wholesize); > } > > +/* Check whether the pointee type of the VAR is a structure with flexible > + array member attached a counted_by attribute. */ > + > +static bool > +is_pointee_fam_struct_with_counted_by (tree var) > +{ > + if (!POINTER_TYPE_P (TREE_TYPE (var))) > + return false; > + > + const_tree pointee_type = TREE_TYPE (TREE_TYPE (var)); > + if (!flexible_array_type_p (pointee_type)) > + return false; > + > + if (TREE_CODE (pointee_type) != RECORD_TYPE) > + return false; > + > + tree last = last_field (pointee_type); > + /* Check whether the last FAM field has a counted_by attribute. */ > + if (last && lookup_attribute ("counted_by", DECL_ATTRIBUTES (last))) > + return true; > + > + return false; > +} > + > +/* 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); > + gcc_assert (is_pointee_fam_struct_with_counted_by (var)); > + > + tree pointee_type = TREE_TYPE (TREE_TYPE (var)); > + tree counted_by_ref = NULL_TREE; > + tree counted_by_type = NULL_TREE; > + tree last = last_field (pointee_type); > + > + /* build a counted_by reference. */ > + if (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); > + > + /* We should guard the size expression with the check to see whether > the > + original pointer is NULL or not since a NULL pointer might be passed > + and this is valid. */ > + tree cond_expr = fold_build2 (EQ_EXPR, boolean_type_node, var, > + build_zero_cst (TREE_TYPE (var))); > + size = fold_build3 (COND_EXPR, integer_type_node, cond_expr, > + size_unknown (object_size_type), size); > + size = fold_convert (sizetype, size); > + > + if (!todo) > + todo = TODO_update_ssa | TODO_cleanup_cfg; > + } > + /* 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)); > + > + /* The size expression should be put into a new block in the new added > + conditional control flow. */ > + osi->insert_cf = true; > + object_sizes_set (osi, SSA_NAME_VERSION (var), size, size); > + return; > +} > > /* Compute object_sizes for PTR, defined to the result of a call. */ > > @@ -1922,6 +2193,16 @@ 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 that is attached by a counted_by attribute, > + 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 > + && is_pointee_fam_struct_with_counted_by (var)) > + 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) > @@ -2188,6 +2469,13 @@ dynamic_object_sizes_execute_one (gimple_stmt_iterator > *i, gimple *call) > /* fold_builtin_call_array may wrap the result inside a > NOP_EXPR. */ > STRIP_NOPS (result); > + > + /* when insert_cf is true, the cfg is changed, and the ogiginal basic block > + * associted with the iterator i might be different than the new basic > + * block associated with the corresponding stmt. */ > + if (gsi_stmt (*i)->bb != gsi_bb (*i)) > + i->bb = gsi_stmt (*i)->bb; > + > gimplify_and_update_call_from_tree (i, result); > > if (dump_file && (dump_flags & TDF_DETAILS)) > -- > 2.31.1 >