From 8c3563f392007b60a07d4c6d3c335355e19f3135 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 18 Dec 2017 08:33:26 +0000 Subject: [PATCH] re PR tree-optimization/77291 (False positive for -Warray-bounds) 2017-12-18 Richard Biener PR middle-end/77291 * tree.c (array_at_struct_end_p): Return true if the underlying object has space for at least one element in excess of what the array domain specifies. * gcc.dg/Warray-bounds-26.c: New testcase. From-SVN: r255775 --- gcc/ChangeLog | 7 ++++ gcc/testsuite/ChangeLog | 5 +++ gcc/testsuite/gcc.dg/Warray-bounds-26.c | 17 +++++++++ gcc/tree.c | 47 +++++++++++++++---------- 4 files changed, 57 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-26.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2a875d3ae7b..c9a5f2123a1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2017-12-18 Richard Biener + + PR middle-end/77291 + * tree.c (array_at_struct_end_p): Return true if the underlying + object has space for at least one element in excess of what + the array domain specifies. + 2017-12-17 Sandra Loosemore * doc/extend.texi (x86 Function Attributes): Reformat nocf_check diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5cb9c935b4d..8fe9a88b33a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-12-18 Richard Biener + + PR middle-end/77291 + * gcc.dg/Warray-bounds-26.c: New testcase. + 2017-12-17 Uros Bizjak * gcc.dg/guality/guality.h (guality_check): Cast %lli arguments diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-26.c b/gcc/testsuite/gcc.dg/Warray-bounds-26.c new file mode 100644 index 00000000000..85bdb3ea146 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-26.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -Warray-bounds" } */ + +struct Rec { + unsigned char data[1]; // actually variable length +}; + +union U { + unsigned char buf[42]; + struct Rec rec; +}; + +int Load() +{ + union U u; + return u.rec.data[1]; /* { dg-bogus "array bound" } */ +} diff --git a/gcc/tree.c b/gcc/tree.c index b43a3fd7ace..65e945afe06 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -12644,6 +12644,7 @@ array_at_struct_end_p (tree ref) if (TREE_CODE (ref) == STRING_CST) return false; + tree ref_to_array = ref; while (handled_component_p (ref)) { /* If the reference chain contains a component reference to a @@ -12682,35 +12683,43 @@ array_at_struct_end_p (tree ref) /* The array now is at struct end. Treat flexible arrays as always subject to extend, even into just padding constrained by an underlying decl. */ - if (! TYPE_SIZE (atype)) + if (! TYPE_SIZE (atype) + || ! TYPE_DOMAIN (atype) + || ! TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) return true; - tree size = NULL; - if (TREE_CODE (ref) == MEM_REF && TREE_CODE (TREE_OPERAND (ref, 0)) == ADDR_EXPR) - { - size = TYPE_SIZE (TREE_TYPE (ref)); - ref = TREE_OPERAND (TREE_OPERAND (ref, 0), 0); - } + ref = TREE_OPERAND (TREE_OPERAND (ref, 0), 0); /* If the reference is based on a declared entity, the size of the array is constrained by its given domain. (Do not trust commons PR/69368). */ if (DECL_P (ref) - /* Be sure the size of MEM_REF target match. For example: - - char buf[10]; - struct foo *str = (struct foo *)&buf; - - str->trailin_array[2] = 1; + && !(flag_unconstrained_commons + && VAR_P (ref) && DECL_COMMON (ref)) + && DECL_SIZE_UNIT (ref) + && TREE_CODE (DECL_SIZE_UNIT (ref)) == INTEGER_CST) + { + /* Check whether the array domain covers all of the available + padding. */ + HOST_WIDE_INT offset; + if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (atype))) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST + || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST) + return true; + if (! get_addr_base_and_unit_offset (ref_to_array, &offset)) + return true; - is valid because BUF allocate enough space. */ + /* If at least one extra element fits it is a flexarray. */ + if (wi::les_p ((wi::to_offset (TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) + - wi::to_offset (TYPE_MIN_VALUE (TYPE_DOMAIN (atype))) + + 2) + * wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (atype))), + wi::to_offset (DECL_SIZE_UNIT (ref)) - offset)) + return true; - && (!size || (DECL_SIZE (ref) != NULL - && operand_equal_p (DECL_SIZE (ref), size, 0))) - && !(flag_unconstrained_commons - && VAR_P (ref) && DECL_COMMON (ref))) - return false; + return false; + } return true; } -- 2.30.2