Skip to content

Commit

Permalink
Handle component_ref to a structre/union field including flexible arr…
Browse files Browse the repository at this point in the history
…ay member [PR101832]

GCC extension accepts the case when a struct with a C99 flexible array member
is embedded into another struct or union (possibly recursively) as the last
field.
__builtin_object_size should treat such struct as flexible size.

gcc/c/ChangeLog:

	PR tree-optimization/101832
	* c-decl.cc (finish_struct): Set TYPE_INCLUDES_FLEXARRAY for
	struct/union type.

gcc/lto/ChangeLog:

	PR tree-optimization/101832
	* lto-common.cc (compare_tree_sccs_1): Compare bit
	TYPE_NO_NAMED_ARGS_STDARG_P or TYPE_INCLUDES_FLEXARRAY properly
	for its corresponding type.

gcc/ChangeLog:

	PR tree-optimization/101832
	* print-tree.cc (print_node): Print new bit type_includes_flexarray.
	* tree-core.h (struct tree_type_common): Use bit no_named_args_stdarg_p
	as type_includes_flexarray for RECORD_TYPE or UNION_TYPE.
	* tree-object-size.cc (addr_object_size): Handle structure/union type
	when it has flexible size.
	* tree-streamer-in.cc (unpack_ts_type_common_value_fields): Stream
	in bit no_named_args_stdarg_p properly for its corresponding type.
	* tree-streamer-out.cc (pack_ts_type_common_value_fields): Stream
	out bit no_named_args_stdarg_p properly for its corresponding type.
	* tree.h (TYPE_INCLUDES_FLEXARRAY): New macro TYPE_INCLUDES_FLEXARRAY.

gcc/testsuite/ChangeLog:

	PR tree-optimization/101832
	* gcc.dg/builtin-object-size-pr101832.c: New test.
  • Loading branch information
qingzhao69 authored and ouuleilei-bot committed May 25, 2023
1 parent c2d62cd commit 61957ae
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 5 deletions.
11 changes: 11 additions & 0 deletions gcc/c/c-decl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9265,6 +9265,17 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
/* Set DECL_NOT_FLEXARRAY flag for FIELD_DECL x. */
DECL_NOT_FLEXARRAY (x) = !is_flexible_array_member_p (is_last_field, x);

/* Set TYPE_INCLUDES_FLEXARRAY for the context of x, t.
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));
/* 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)))
TYPE_INCLUDES_FLEXARRAY (t)
= is_last_field && TYPE_INCLUDES_FLEXARRAY (TREE_TYPE (x));

if (DECL_NAME (x)
|| RECORD_OR_UNION_TYPE_P (TREE_TYPE (x)))
saw_named_field = true;
Expand Down
5 changes: 4 additions & 1 deletion gcc/lto/lto-common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1275,7 +1275,10 @@ compare_tree_sccs_1 (tree t1, tree t2, tree **map)
if (AGGREGATE_TYPE_P (t1))
compare_values (TYPE_TYPELESS_STORAGE);
compare_values (TYPE_EMPTY_P);
compare_values (TYPE_NO_NAMED_ARGS_STDARG_P);
if (FUNC_OR_METHOD_TYPE_P (t1))
compare_values (TYPE_NO_NAMED_ARGS_STDARG_P);
if (RECORD_OR_UNION_TYPE_P (t1))
compare_values (TYPE_INCLUDES_FLEXARRAY);
compare_values (TYPE_PACKED);
compare_values (TYPE_RESTRICT);
compare_values (TYPE_USER_ALIGN);
Expand Down
5 changes: 5 additions & 0 deletions gcc/print-tree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,11 @@ print_node (FILE *file, const char *prefix, tree node, int indent,
&& TYPE_CXX_ODR_P (node))
fputs (" cxx-odr-p", file);

if ((code == RECORD_TYPE
|| code == UNION_TYPE)
&& TYPE_INCLUDES_FLEXARRAY (node))
fputs (" includes-flexarray", file);

/* The transparent-union flag is used for different things in
different nodes. */
if ((code == UNION_TYPE || code == RECORD_TYPE)
Expand Down
134 changes: 134 additions & 0 deletions gcc/testsuite/gcc.dg/builtin-object-size-pr101832.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/* PR 101832:
GCC extension accepts the case when a struct with a C99 flexible array
member is embedded into another struct (possibly recursively).
__builtin_object_size will treat such struct as flexible size.
However, when a structure with non-C99 flexible array member, i.e, trailing
[0], [1], or [4], is embedded into anther struct, the stucture will not
be treated as flexible size. */
/* { dg-do run } */
/* { dg-options "-O2" } */

#include "builtin-object-size-common.h"

#define expect(p, _v) do { \
size_t v = _v; \
if (p == v) \
__builtin_printf ("ok: %s == %zd\n", #p, p); \
else {\
__builtin_printf ("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
FAIL (); \
} \
} while (0);


struct A {
int n;
char data[];
};

struct B {
int m;
struct A a;
};

struct C {
int q;
struct B b;
};

struct A0 {
int n;
char data[0];
};

struct B0 {
int m;
struct A0 a;
};

struct C0 {
int q;
struct B0 b;
};

struct A1 {
int n;
char data[1];
};

struct B1 {
int m;
struct A1 a;
};

struct C1 {
int q;
struct B1 b;
};

struct An {
int n;
char data[8];
};

struct Bn {
int m;
struct An a;
};

struct Cn {
int q;
struct Bn b;
};

volatile void *magic1, *magic2;

int main (int argc, char *argv[])
{
struct B *outer;
struct C *outest;

/* Make sure optimization can't find some other object size. */
outer = (void *)magic1;
outest = (void *)magic2;

expect (__builtin_object_size (&outer->a, 1), -1);
expect (__builtin_object_size (&outest->b, 1), -1);
expect (__builtin_object_size (&outest->b.a, 1), -1);

struct B0 *outer0;
struct C0 *outest0;

/* Make sure optimization can't find some other object size. */
outer0 = (void *)magic1;
outest0 = (void *)magic2;

expect (__builtin_object_size (&outer0->a, 1), sizeof (outer0->a));
expect (__builtin_object_size (&outest0->b, 1), sizeof (outest0->b));
expect (__builtin_object_size (&outest0->b.a, 1), sizeof (outest0->b.a));

struct B1 *outer1;
struct C1 *outest1;

/* Make sure optimization can't find some other object size. */
outer1 = (void *)magic1;
outest1 = (void *)magic2;

expect (__builtin_object_size (&outer1->a, 1), sizeof (outer1->a));
expect (__builtin_object_size (&outest1->b, 1), sizeof (outest1->b));
expect (__builtin_object_size (&outest1->b.a, 1), sizeof (outest1->b.a));

struct Bn *outern;
struct Cn *outestn;

/* Make sure optimization can't find some other object size. */
outern = (void *)magic1;
outestn = (void *)magic2;

expect (__builtin_object_size (&outern->a, 1), sizeof (outern->a));
expect (__builtin_object_size (&outestn->b, 1), sizeof (outestn->b));
expect (__builtin_object_size (&outestn->b.a, 1), sizeof (outestn->b.a));

DONE ();
return 0;
}
2 changes: 2 additions & 0 deletions gcc/tree-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1711,6 +1711,8 @@ struct GTY(()) tree_type_common {
unsigned typeless_storage : 1;
unsigned empty_flag : 1;
unsigned indivisible_p : 1;
/* TYPE_NO_NAMED_ARGS_STDARG_P for a stdarg function.
Or TYPE_INCLUDES_FLEXARRAY for RECORD_TYPE and UNION_TYPE. */
unsigned no_named_args_stdarg_p : 1;
unsigned spare : 9;

Expand Down
23 changes: 22 additions & 1 deletion gcc/tree-object-size.cc
Original file line number Diff line number Diff line change
Expand Up @@ -633,11 +633,32 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
v = NULL_TREE;
break;
case COMPONENT_REF:
if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
/* When the ref is not to an aggregate type, i.e, an array,
a record or a union, it will not have flexible size,
compute the object size directly. */
if (!AGGREGATE_TYPE_P (TREE_TYPE (v)))
{
v = NULL_TREE;
break;
}
/* if the ref is to a record or union type, but the type
does not include a flexible array recursively, compute
the object size directly. */
if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (v)))
{
if (!TYPE_INCLUDES_FLEXARRAY (TREE_TYPE (v)))
{
v = NULL_TREE;
break;
}
else
{
v = TREE_OPERAND (v, 0);
break;
}
}
/* Now the ref is to an array type. */
gcc_assert (TREE_CODE (TREE_TYPE (v)) == ARRAY_TYPE);
is_flexible_array_mem_ref = array_ref_flexible_size_p (v);
while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
Expand Down
5 changes: 4 additions & 1 deletion gcc/tree-streamer-in.cc
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,10 @@ unpack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
if (AGGREGATE_TYPE_P (expr))
TYPE_TYPELESS_STORAGE (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_EMPTY_P (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_NO_NAMED_ARGS_STDARG_P (expr) = (unsigned) bp_unpack_value (bp, 1);
if (FUNC_OR_METHOD_TYPE_P (expr))
TYPE_NO_NAMED_ARGS_STDARG_P (expr) = (unsigned) bp_unpack_value (bp, 1);
if (RECORD_OR_UNION_TYPE_P (expr))
TYPE_INCLUDES_FLEXARRAY (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_PRECISION (expr) = bp_unpack_var_len_unsigned (bp);
SET_TYPE_ALIGN (expr, bp_unpack_var_len_unsigned (bp));
#ifdef ACCEL_COMPILER
Expand Down
5 changes: 4 additions & 1 deletion gcc/tree-streamer-out.cc
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,10 @@ pack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
if (AGGREGATE_TYPE_P (expr))
bp_pack_value (bp, TYPE_TYPELESS_STORAGE (expr), 1);
bp_pack_value (bp, TYPE_EMPTY_P (expr), 1);
bp_pack_value (bp, TYPE_NO_NAMED_ARGS_STDARG_P (expr), 1);
if (FUNC_OR_METHOD_TYPE_P (expr))
bp_pack_value (bp, TYPE_NO_NAMED_ARGS_STDARG_P (expr), 1);
if (RECORD_OR_UNION_TYPE_P (expr))
bp_pack_value (bp, TYPE_INCLUDES_FLEXARRAY (expr), 1);
bp_pack_var_len_unsigned (bp, TYPE_PRECISION (expr));
bp_pack_var_len_unsigned (bp, TYPE_ALIGN (expr));
}
Expand Down
7 changes: 6 additions & 1 deletion gcc/tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,12 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
(...) prototype, where arguments can be accessed with va_start and
va_arg), as opposed to an unprototyped function. */
#define TYPE_NO_NAMED_ARGS_STDARG_P(NODE) \
(TYPE_CHECK (NODE)->type_common.no_named_args_stdarg_p)
(FUNC_OR_METHOD_CHECK (NODE)->type_common.no_named_args_stdarg_p)

/* True if this RECORD_TYPE or UNION_TYPE includes a flexible array member
as the last field recursively. */
#define TYPE_INCLUDES_FLEXARRAY(NODE) \
(RECORD_OR_UNION_CHECK (NODE)->type_common.no_named_args_stdarg_p)

/* In an IDENTIFIER_NODE, this means that assemble_name was called with
this string as an argument. */
Expand Down

0 comments on commit 61957ae

Please sign in to comment.