gcc/c/ChangeLog: * c-typeck.cc (build_counted_by_ref): Handle pointers with counted_by. (build_access_with_size_for_counted_by): Likewise.
gcc/ChangeLog: * tree-object-size.cc (access_with_size_object_size): Handle pointers with counted_by. (collect_object_sizes_for): Likewise. gcc/testsuite/ChangeLog: * gcc.dg/pointer-counted-by-4.c: New test. * gcc.dg/pointer-counted-by-5.c: New test. * gcc.dg/pointer-counted-by-6.c: New test. * gcc.dg/pointer-counted-by-7.c: New test. * gcc.dg/pointer-counted-by-8.c: New test. --- gcc/c/c-typeck.cc | 41 ++++++++------ gcc/testsuite/gcc.dg/pointer-counted-by-4.c | 63 +++++++++++++++++++++ gcc/testsuite/gcc.dg/pointer-counted-by-5.c | 48 ++++++++++++++++ gcc/testsuite/gcc.dg/pointer-counted-by-6.c | 47 +++++++++++++++ gcc/testsuite/gcc.dg/pointer-counted-by-7.c | 30 ++++++++++ gcc/testsuite/gcc.dg/pointer-counted-by-8.c | 30 ++++++++++ gcc/tree-object-size.cc | 11 +++- 7 files changed, 251 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pointer-counted-by-4.c create mode 100644 gcc/testsuite/gcc.dg/pointer-counted-by-5.c create mode 100644 gcc/testsuite/gcc.dg/pointer-counted-by-6.c create mode 100644 gcc/testsuite/gcc.dg/pointer-counted-by-7.c create mode 100644 gcc/testsuite/gcc.dg/pointer-counted-by-8.c diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index dbb688cabaa..9302236f126 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -2911,8 +2911,8 @@ should_suggest_deref_p (tree datum_type) /* For a SUBDATUM field of a structure or union DATUM, generate a REF to the object that represents its counted_by per the attribute counted_by - attached to this field if it's a flexible array member field, otherwise - return NULL_TREE. + attached to this field if it's a flexible array member or a pointer + field, otherwise return NULL_TREE. Set COUNTED_BY_TYPE to the TYPE of the counted_by field. For example, if: @@ -2933,7 +2933,9 @@ static tree 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))) + tree sub_type = TREE_TYPE (subdatum); + if (!c_flexible_array_member_type_p (sub_type) + && TREE_CODE (sub_type) != POINTER_TYPE) return NULL_TREE; tree attr_counted_by = lookup_attribute ("counted_by", @@ -2964,8 +2966,11 @@ build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type) } /* Given a COMPONENT_REF REF with the location LOC, the corresponding - COUNTED_BY_REF, and the COUNTED_BY_TYPE, generate an INDIRECT_REF - to a call to the internal function .ACCESS_WITH_SIZE. + COUNTED_BY_REF, and the COUNTED_BY_TYPE, generate the corresponding + call to the internal function .ACCESS_WITH_SIZE. + + Generate an INDIRECT_REF to a call to the internal function + .ACCESS_WITH_SIZE. REF @@ -2975,17 +2980,15 @@ build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type) (TYPE_OF_ARRAY *)0)) NOTE: The return type of this function is the POINTER type pointing - to the original flexible array type. - Then the type of the INDIRECT_REF is the original flexible array type. - - The type of the first argument of this function is a POINTER type - to the original flexible array type. + to the original flexible array type or the original pointer type. + Then the type of the INDIRECT_REF is the original flexible array type + or the original pointer type. The 4th argument of the call is a constant 0 with the TYPE of the object pointed by COUNTED_BY_REF. - The 6th argument of the call is a constant 0 with the pointer TYPE - to the original flexible array type. + The 6th argument of the call is a constant 0 of the same TYPE as + the return type of the call. */ static tree @@ -2993,20 +2996,26 @@ build_access_with_size_for_counted_by (location_t loc, tree ref, tree counted_by_ref, tree counted_by_type) { - gcc_assert (c_flexible_array_member_type_p (TREE_TYPE (ref))); - /* The result type of the call is a pointer to the flexible array type. */ + gcc_assert (c_flexible_array_member_type_p (TREE_TYPE (ref)) + || TREE_CODE (TREE_TYPE (ref)) == POINTER_TYPE); + bool is_fam = c_flexible_array_member_type_p (TREE_TYPE (ref)); + tree first_arg = is_fam ? array_to_pointer_conversion (loc, ref) + : build_unary_op (loc, ADDR_EXPR, ref, false); + + /* The result type of the call is a pointer to the original type + of the ref. */ tree result_type = c_build_pointer_type (TREE_TYPE (ref)); tree call = build_call_expr_internal_loc (loc, IFN_ACCESS_WITH_SIZE, result_type, 6, - array_to_pointer_conversion (loc, ref), + first_arg, counted_by_ref, build_int_cst (integer_type_node, 1), build_int_cst (counted_by_type, 0), build_int_cst (integer_type_node, -1), build_int_cst (result_type, 0)); - /* Wrap the call with an INDIRECT_REF with the flexible array type. */ + /* Wrap the call with an INDIRECT_REF with the original type of the ref. */ call = build1 (INDIRECT_REF, TREE_TYPE (ref), call); SET_EXPR_LOCATION (call, loc); return call; diff --git a/gcc/testsuite/gcc.dg/pointer-counted-by-4.c b/gcc/testsuite/gcc.dg/pointer-counted-by-4.c new file mode 100644 index 00000000000..8f64e443c4b --- /dev/null +++ b/gcc/testsuite/gcc.dg/pointer-counted-by-4.c @@ -0,0 +1,63 @@ +/* Test the attribute counted_by for pointer field and its usage in + * __builtin_dynamic_object_size. */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#include "builtin-object-size-common.h" + +struct pointer_array { + int b; + int *c; +} *p_array; + +struct annotated { + int b; + int *c __attribute__ ((counted_by (b))); +} *p_array_annotated; + +struct nested_annotated { + struct { + union { + int b; + float f; + }; + int n; + }; + int *c __attribute__ ((counted_by (b))); +} *p_array_nested_annotated; + +void __attribute__((__noinline__)) setup (int normal_count, int attr_count) +{ + p_array + = (struct pointer_array *) malloc (sizeof (struct pointer_array)); + p_array->c = (int *) malloc (sizeof (int) * normal_count); + p_array->b = normal_count; + + p_array_annotated + = (struct annotated *) malloc (sizeof (struct annotated)); + p_array_annotated->c = (int *) malloc (sizeof (int) * attr_count); + p_array_annotated->b = attr_count; + + p_array_nested_annotated + = (struct nested_annotated *) malloc (sizeof (struct nested_annotated)); + p_array_nested_annotated->c = (int *) malloc (sizeof (int) * attr_count); + p_array_nested_annotated->b = attr_count; + + return; +} + +void __attribute__((__noinline__)) test () +{ + EXPECT(__builtin_dynamic_object_size(p_array->c, 1), -1); + EXPECT(__builtin_dynamic_object_size(p_array_annotated->c, 1), + p_array_annotated->b * sizeof (int)); + EXPECT(__builtin_dynamic_object_size(p_array_nested_annotated->c, 1), + p_array_nested_annotated->b * sizeof (int)); +} + +int main(int argc, char *argv[]) +{ + setup (10,10); + test (); + DONE (); +} diff --git a/gcc/testsuite/gcc.dg/pointer-counted-by-5.c b/gcc/testsuite/gcc.dg/pointer-counted-by-5.c new file mode 100644 index 00000000000..b136bbc13fb --- /dev/null +++ b/gcc/testsuite/gcc.dg/pointer-counted-by-5.c @@ -0,0 +1,48 @@ +/* Test the attribute counted_by for pointer fields and its usage in + * __builtin_dynamic_object_size: when the counted_by field is negative. */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#include "builtin-object-size-common.h" + +struct annotated { + int b; + int *c __attribute__ ((counted_by (b))); +} *array_annotated; + +struct nested_annotated { + struct { + union { + int b; + float f; + }; + int n; + }; + int *c __attribute__ ((counted_by (b))); +} *array_nested_annotated; + +void __attribute__((__noinline__)) setup (int attr_count) +{ + array_annotated + = (struct annotated *)malloc (sizeof (struct annotated)); + array_annotated->b = attr_count; + + array_nested_annotated + = (struct nested_annotated *)malloc (sizeof (struct nested_annotated)); + array_nested_annotated->b = attr_count - 1; + + return; +} + +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); +} + +int main(int argc, char *argv[]) +{ + setup (-10); + test (); + DONE (); +} diff --git a/gcc/testsuite/gcc.dg/pointer-counted-by-6.c b/gcc/testsuite/gcc.dg/pointer-counted-by-6.c new file mode 100644 index 00000000000..4a1baa41d9a --- /dev/null +++ b/gcc/testsuite/gcc.dg/pointer-counted-by-6.c @@ -0,0 +1,47 @@ +/* Test the attribute counted_by for pointer fields and its usage in + * __builtin_dynamic_object_size: when the type of the pointer + * is casting to another type. */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#include "builtin-object-size-common.h" + +typedef unsigned short u16; + +struct info { + u16 data_len; + char *data __attribute__((counted_by(data_len))); +}; + +struct foo { + int a; + int b; +}; + +static __attribute__((__noinline__)) +struct info *setup () +{ + struct info *p; + size_t bytes = 3 * sizeof(struct foo); + + p = (struct info *) malloc (sizeof (struct info)); + p->data = (char *) malloc (bytes); + p->data_len = bytes; + + return p; +} + +static void +__attribute__((__noinline__)) report (struct info *p) +{ + struct foo *bar = (struct foo *)p->data; + EXPECT(__builtin_dynamic_object_size((char *)(bar + 1), 1), 16); + EXPECT(__builtin_dynamic_object_size((char *)(bar + 2), 1), 8); +} + +int main(int argc, char *argv[]) +{ + struct info *p = setup(); + report(p); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/pointer-counted-by-7.c b/gcc/testsuite/gcc.dg/pointer-counted-by-7.c new file mode 100644 index 00000000000..01addbb857d --- /dev/null +++ b/gcc/testsuite/gcc.dg/pointer-counted-by-7.c @@ -0,0 +1,30 @@ +/* Additional test of the attribute counted_by for pointer field and its usage + in __builtin_dynamic_object_size. */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#include "builtin-object-size-common.h" + +struct annotated { + int b; + int *c __attribute__ ((counted_by (b))); +}; + +struct annotated __attribute__((__noinline__)) setup (int attr_count) +{ + struct annotated p_array_annotated; + p_array_annotated.c = (int *) malloc (sizeof (int) * attr_count); + p_array_annotated.b = attr_count; + + return p_array_annotated; +} + +int main(int argc, char *argv[]) +{ + struct annotated x = setup (10); + int *p = x.c; + x = setup (20); + EXPECT(__builtin_dynamic_object_size (p, 1), 10 * sizeof (int)); + EXPECT(__builtin_dynamic_object_size (x.c, 1), 20 * sizeof (int)); + DONE (); +} diff --git a/gcc/testsuite/gcc.dg/pointer-counted-by-8.c b/gcc/testsuite/gcc.dg/pointer-counted-by-8.c new file mode 100644 index 00000000000..3802fa1351d --- /dev/null +++ b/gcc/testsuite/gcc.dg/pointer-counted-by-8.c @@ -0,0 +1,30 @@ +/* Additional test of the attribute counted_by for pointer field and its usage + in __builtin_dynamic_object_size. */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#include "builtin-object-size-common.h" + +struct annotated { + int b; + int *c __attribute__ ((counted_by (b))); +}; + +struct annotated __attribute__((__noinline__)) setup (int attr_count) +{ + struct annotated p_array_annotated; + p_array_annotated.c = (int *) malloc (sizeof (int) * attr_count); + p_array_annotated.b = attr_count; + + return p_array_annotated; +} + +int main(int argc, char *argv[]) +{ + struct annotated x = setup (10); + int *p = x.c; + x = setup (20); + EXPECT(__builtin_dynamic_object_size (p, 1), 10 * sizeof (int)); + EXPECT(__builtin_dynamic_object_size (x.c, 1), 20 * sizeof (int)); + DONE (); +} diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc index f348673ae75..1eef66bea4d 100644 --- a/gcc/tree-object-size.cc +++ b/gcc/tree-object-size.cc @@ -773,10 +773,11 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, 4th argument TYPE_OF_SIZE: A constant 0 with its TYPE being the same as the TYPE of the object referenced by REF_TO_SIZE 6th argument: A constant 0 with the pointer TYPE to the original flexible - array type. + array type or pointer field type. The size of the element can be retrived from the TYPE of the 6th argument - of the call, which is the pointer to the array type. */ + of the call, which is the pointer to the original flexible array type or + the type of the original pointer field. */ static tree access_with_size_object_size (const gcall *call, int object_size_type) { @@ -786,7 +787,7 @@ access_with_size_object_size (const gcall *call, int object_size_type) gcc_assert (gimple_call_internal_p (call, IFN_ACCESS_WITH_SIZE)); /* The type of the 6th argument type is the pointer TYPE to the original - flexible array type. */ + flexible array type or to the original pointer type. */ tree pointer_to_array_type = TREE_TYPE (gimple_call_arg (call, 5)); gcc_assert (POINTER_TYPE_P (pointer_to_array_type)); tree element_type = TREE_TYPE (TREE_TYPE (pointer_to_array_type)); @@ -1854,6 +1855,10 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) if (TREE_CODE (rhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (rhs))) reexamine = merge_object_sizes (osi, var, rhs); + else if (TREE_CODE (rhs) == MEM_REF + && POINTER_TYPE_P (TREE_TYPE (rhs)) + && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME) + reexamine = merge_object_sizes (osi, var, TREE_OPERAND (rhs, 0)); else expr_object_size (osi, var, rhs); } -- 2.31.1