From 91eb5fa8e1fae57f6d69b2b973ffdf1988d18ca1 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Wed, 6 Nov 2019 01:25:09 +0000 Subject: [PATCH] PR tree-optimization/92373 - ICE in -Warray-bounds on access to member array in an initialized char buffer gcc/testsuite/ChangeLog: PR tree-optimization/92373 * gcc.dg/Warray-bounds-55.c: New test. * gcc.dg/Wzero-length-array-bounds-2.c: New test. gcc/ChangeLog: PR tree-optimization/92373 * tree.c (component_ref_size): Only consider initializers of objects of matching struct types. Return null for instances of interior zero-length arrays. From-SVN: r277871 --- gcc/ChangeLog | 7 + gcc/testsuite/ChangeLog | 6 + gcc/testsuite/gcc.dg/Warray-bounds-55.c | 28 ++++ .../gcc.dg/Wzero-length-array-bounds-2.c | 125 ++++++++++++++++++ gcc/tree.c | 49 ++++--- 5 files changed, 193 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-55.c create mode 100644 gcc/testsuite/gcc.dg/Wzero-length-array-bounds-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 63ef7114b68..e666a0ccf27 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-11-05 Martin Sebor + + PR tree-optimization/92373 + * tree.c (component_ref_size): Only consider initializers of objects + of matching struct types. + Return null for instances of interior zero-length arrays. + 2019-11-05 Segher Boessenkool * doc/md.texi (Insn Splitting): Fix combiner documentation. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f34ed0873f8..6b5a444ee8f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2019-11-05 Martin Sebor + + PR tree-optimization/92373 + * gcc.dg/Warray-bounds-55.c: New test. + * gcc.dg/Wzero-length-array-bounds-2.c: New test. + 2019-11-05 Jim Wilson PR middle-end/92263 diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-55.c b/gcc/testsuite/gcc.dg/Warray-bounds-55.c new file mode 100644 index 00000000000..b7dfe706852 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-55.c @@ -0,0 +1,28 @@ +/* PR middle-end/92373 - ICE in -Warray-bounds on access to member array + in an initialized char buffer + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +void sink (void*); + +struct S +{ + char data[1]; +}; + +char a[6] = { }; + +int f (void) +{ + struct S *p = (struct S*)a; + return p->data[4]; + +} + +void g (void) +{ + char b[6] = { }; + struct S *p = (struct S*)b; + p->data[4] = 0; + sink (p); +} diff --git a/gcc/testsuite/gcc.dg/Wzero-length-array-bounds-2.c b/gcc/testsuite/gcc.dg/Wzero-length-array-bounds-2.c new file mode 100644 index 00000000000..841b2bfa122 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wzero-length-array-bounds-2.c @@ -0,0 +1,125 @@ +/* Test to verify that -Wzero-length-bounds and not -Warray-bounds is + issued for accesses to interior zero-length array members that are + within the bounds of the enclosing struct. + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +void sink (void*); + +struct A { int i; }; +struct B { int j; struct A a[0]; }; + +struct C +{ + struct B b1; + struct B b2; +}; + + +void test_B_ref (struct B *p) +{ + // References with negative indices are always diagnosed by -Warray-bounds + // even though they could be considered the same as past the end accesses + // to trailing zero-length arrays. + p->a[-1].i = 0; // { dg-warning "\\\[-Warray-bounds" } + p->a[ 0].i = 0; + p->a[ 1].i = 0; + sink (p); + + p[1].a[-1].i = 0; // { dg-warning "\\\[-Warray-bounds" } + p[1].a[ 0].i = 0; + p[1].a[ 1].i = 0; +} + + +void test_C_ref (struct C *p) +{ + p->b1.a[-1].i = 0; // { dg-warning "\\\[-Warray-bounds" } + p->b1.a[ 0].i = 0; // { dg-warning "\\\[-Wzero-length-bounds" } + p->b1.a[ 1].i = 0; // { dg-warning "\\\[-Wzero-length-bounds" } + + // Accesses to trailing zero-length arrays are not diagnosed (should + // they be?) + p->b2.a[ 0].i = 0; + p->b2.a[ 9].i = 0; +} + + +void test_C_decl (void) +{ + struct C c, *p = &c; + + p->b1.a[-1].i = 0; // { dg-warning "\\\[-Warray-bounds" } + + // c.b1.a[0].i overlaps c.b2.j. + p->b1.a[ 0].i = 0; // { dg-warning "\\\[-Wzero-length-bounds" } + + // c.b1.a[1].i is past the end of c... + p->b1.a[ 1].i = 0; // { dg-warning "\\\[-Warray-bounds" } + sink (p); + + // ...and so are references to all elements of c.b2.a + p->b2.a[ 0].i = 0; // { dg-warning "\\\[-Warray-bounds" } + p->b2.a[ 1].i = 0; // { dg-warning "\\\[-Warray-bounds" } + sink (p); +} + + +char cbuf1[1 * sizeof (struct C)]; +char cbuf2[2 * sizeof (struct C)] = { }; + +void test_C_global_buf (void) +{ + struct C *p = (struct C*)&cbuf1; + + p->b1.a[-1].i = 0; // { dg-warning "\\\[-Warray-bounds" } + p->b1.a[ 0].i = 0; // { dg-warning "\\\[-Wzero-length-bounds" } + p->b1.a[ 1].i = 0; // { dg-warning "\\\[-Warray-bounds" } + sink (p); + + p->b2.a[ 0].i = 0; // { dg-warning "\\\[-Warray-bounds" } + p->b2.a[ 1].i = 0; // { dg-warning "\\\[-Warray-bounds" } + sink (p); + + p = (struct C*)&cbuf2; + p->b1.a[-1].i = 0; // { dg-warning "\\\[-Warray-bounds" } + p->b1.a[ 0].i = 0; // { dg-warning "\\\[-Wzero-length-bounds" } + p->b1.a[ 1].i = 0; // { dg-warning "\\\[-Wzero-length-bounds" } + sink (p); + + p->b2.a[ 0].i = 0; + p->b2.a[ 1].i = 0; + p->b2.a[ 2].i = 0; // { dg-warning "\\\[-Warray-bounds" } + p->b2.a[ 3].i = 0; // { dg-warning "\\\[-Warray-bounds" } + sink (p); +} + + +void test_C_local_buf (void) +{ + char cbuf1[1 * sizeof (struct C)] = ""; + char cbuf2[2 * sizeof (struct C)] = { }; + + struct C *p = (struct C*)&cbuf1; + + p->b1.a[-1].i = 1; // { dg-warning "\\\[-Warray-bounds" } + p->b1.a[ 0].i = 2; // { dg-warning "\\\[-Wzero-length-bounds" } + p->b1.a[ 1].i = 3; // { dg-warning "\\\[-Warray-bounds" } + sink (p); + + p->b2.a[ 0].i = 4; // { dg-warning "\\\[-Warray-bounds" } + p->b2.a[ 1].i = 5; // { dg-warning "\\\[-Warray-bounds" } + sink (p); + + p = (struct C*)&cbuf2; + p->b1.a[-1].i = 6; // { dg-warning "\\\[-Warray-bounds" } + p->b1.a[ 0].i = 7; // { dg-warning "\\\[-Wzero-length-bounds" } + p->b1.a[ 1].i = 8; // { dg-warning "\\\[-Wzero-length-bounds" } + sink (p); + + p->b2.a[ 0].i = 9; + p->b2.a[ 1].i = 10; + p->b2.a[ 2].i = 11; // { dg-warning "\\\[-Warray-bounds" } + p->b2.a[ 3].i = 12; // { dg-warning "\\\[-Warray-bounds" } + sink (p); +} diff --git a/gcc/tree.c b/gcc/tree.c index 3299b344ea6..d08141bcfc2 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -13635,6 +13635,8 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */) return NULL_TREE; base = TREE_OPERAND (ref, 0); + while (TREE_CODE (base) == COMPONENT_REF) + base = TREE_OPERAND (base, 0); baseoff = tree_to_poly_int64 (byte_position (TREE_OPERAND (ref, 1))); } @@ -13656,27 +13658,28 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */) memsize = NULL_TREE; - /* MEMBER is a true flexible array member. Compute its size from - the initializer of the BASE object if it has one. */ - if (tree init = DECL_P (base) ? DECL_INITIAL (base) : NULL_TREE) - { - init = get_initializer_for (init, member); - if (init) - { - memsize = TYPE_SIZE_UNIT (TREE_TYPE (init)); - if (tree refsize = TYPE_SIZE_UNIT (reftype)) - { - /* Use the larger of the initializer size and the tail - padding in the enclosing struct. */ - poly_int64 rsz = tree_to_poly_int64 (refsize); - rsz -= baseoff; - if (known_lt (tree_to_poly_int64 (memsize), rsz)) - memsize = wide_int_to_tree (TREE_TYPE (memsize), rsz); - } + if (typematch) + /* MEMBER is a true flexible array member. Compute its size from + the initializer of the BASE object if it has one. */ + if (tree init = DECL_P (base) ? DECL_INITIAL (base) : NULL_TREE) + { + init = get_initializer_for (init, member); + if (init) + { + memsize = TYPE_SIZE_UNIT (TREE_TYPE (init)); + if (tree refsize = TYPE_SIZE_UNIT (reftype)) + { + /* Use the larger of the initializer size and the tail + padding in the enclosing struct. */ + poly_int64 rsz = tree_to_poly_int64 (refsize); + rsz -= baseoff; + if (known_lt (tree_to_poly_int64 (memsize), rsz)) + memsize = wide_int_to_tree (TREE_TYPE (memsize), rsz); + } - baseoff = 0; - } - } + baseoff = 0; + } + } if (!memsize) { @@ -13689,17 +13692,19 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */) /* The size of a flexible array member of an extern struct with no initializer cannot be determined (it's defined in another translation unit and can have an initializer - witth an arbitrary number of elements). */ + with an arbitrary number of elements). */ return NULL_TREE; /* Use the size of the base struct or, for interior zero-length arrays, the size of the enclosing type. */ memsize = TYPE_SIZE_UNIT (bt); } - else + else if (DECL_P (base)) /* Use the size of the BASE object (possibly an array of some other type such as char used to store the struct). */ memsize = DECL_SIZE_UNIT (base); + else + return NULL_TREE; } /* If the flexible array member has a known size use the greater -- 2.30.2