Use TYPE_INCLUDES_FLEXARRAY in __builtin_object_size [PR tree-optimization/101832]

__builtin_object_size should treat struct with TYPE_INCLUDES_FLEXARRAY as
flexible size.

gcc/ChangeLog:

	PR tree-optimization/101832
	* tree-object-size.cc (addr_object_size): Handle structure/union type
	when it has flexible size.

gcc/testsuite/ChangeLog:

	PR tree-optimization/101832
	* gcc.dg/builtin-object-size-pr101832.c: New test.
This commit is contained in:
Qing Zhao 2023-06-30 18:24:34 +00:00
parent db5d70632a
commit e050ce7c3a
2 changed files with 156 additions and 1 deletions

View file

@ -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;
}

View file

@ -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)))