diff options
author | Martin Sebor <msebor@redhat.com> | 2019-11-01 21:09:20 +0000 |
---|---|---|
committer | Martin Sebor <msebor@gcc.gnu.org> | 2019-11-01 15:09:20 -0600 |
commit | 49fb45c81f4ac068d9fb859968d8f223bc438251 (patch) | |
tree | 56f91e1dcae71841b97747d2342eacce4c35592e /gcc/tree-vrp.c | |
parent | 8dc56a2244cfe35cbdb53e0f586c16f90a2677e4 (diff) | |
download | gcc-49fb45c81f4ac068d9fb859968d8f223bc438251.zip gcc-49fb45c81f4ac068d9fb859968d8f223bc438251.tar.gz gcc-49fb45c81f4ac068d9fb859968d8f223bc438251.tar.bz2 |
PR middle-end/91679 - missing -Warray-bounds accessing a member array in a local buffer
PR middle-end/91679 - missing -Warray-bounds accessing a member array in a local buffer
PR middle-end/91647 - new FAILs for Warray-bounds-8 and Wstringop-overflow-3.C
PR middle-end/91463 - missing -Warray-bounds accessing past the end of a statically initialized flexible array member
PR middle-end/92312 - bogus -Wstringop-overflow storing into a trailing array backed by larger buffer
gcc/ChangeLog:
PR middle-end/91679
PR middle-end/91647
PR middle-end/91463
PR middle-end/92312
* c-family/c-pretty-print.c (direct_abstract_declarator): Print
bound in zero-length arrays.
* gcc/c-family/c.opt (-Wzero-length-bounds): New option.
* gcc/doc/invoke.texi (-Wzero-length-bounds): Document.
* gimple-match-head.c (try_conditional_simplification): Use memcpy
instead of a hand-rolled loop to avoid PR 92323.
* tree-vrp.c (vrp_prop::check_array_ref): Handle trailing arrays
with initializers.
(vrp_prop::check_mem_ref): Handle declared struct objects.
* tree.c (last_field): New function.
(array_at_struct_end_p): Handle MEM_REF.
(get_initializer_for): New helper.
(component_ref_size): Add argument. Rename locals. Call
get_initializer_for instead of fold_ctor_reference. Correct handling
of flexible array members.
* wide-int.h (generic_wide_int <storage>::sign_mask): Assert invariant.
gcc/testsuite/ChangeLog:
PR middle-end/91679
PR middle-end/91647
PR middle-end/91463
PR middle-end/92312
* c-c++-common/Warray-bounds-2.c: Disable VRP. Adjust expected messages.
* g++.dg/warn/Warray-bounds-8.C: Remove xfails.
* gcc.dg/Warray-bounds-48.c: New test.
* gcc.dg/Warray-bounds-49.c: New test.
* gcc.dg/Wstringop-overflow-16.c: Adjust text of expected messages.
* gcc.dg/Wstringop-overflow-21.c: New test.
* gcc.dg/Wzero-length-array-bounds.c: New test.
* gcc.dg/pr36902.c: Remove xfail.
* gcc.dg/strlenopt-57.c: Add an expected warning.
From-SVN: r277728
Diffstat (limited to 'gcc/tree-vrp.c')
-rw-r--r-- | gcc/tree-vrp.c | 108 |
1 files changed, 77 insertions, 31 deletions
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index ad9be74..3125861 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -4122,7 +4122,6 @@ bool vrp_prop::check_array_ref (location_t location, tree ref, bool ignore_off_by_one) { - const value_range *vr = NULL; tree low_sub, up_sub; tree low_bound, up_bound, up_bound_p1; @@ -4132,6 +4131,9 @@ vrp_prop::check_array_ref (location_t location, tree ref, low_sub = up_sub = TREE_OPERAND (ref, 1); up_bound = array_ref_up_bound (ref); + /* Set for accesses to interior zero-length arrays. */ + bool interior_zero_len = false; + if (!up_bound || TREE_CODE (up_bound) != INTEGER_CST || (warn_array_bounds < 2 @@ -4152,11 +4154,22 @@ vrp_prop::check_array_ref (location_t location, tree ref, } else { - tree maxbound = TYPE_MAX_VALUE (ptrdiff_type_node); + tree ptrdiff_max = TYPE_MAX_VALUE (ptrdiff_type_node); + tree maxbound = ptrdiff_max; tree arg = TREE_OPERAND (ref, 0); poly_int64 off; - if (get_addr_base_and_unit_offset (arg, &off) && known_gt (off, 0)) + if (TREE_CODE (arg) == COMPONENT_REF) + { + /* Try to determine the size of the trailing array from + its initializer (if it has one). */ + if (tree refsize = component_ref_size (arg, &interior_zero_len)) + maxbound = refsize; + } + + if (maxbound == ptrdiff_max + && get_addr_base_and_unit_offset (arg, &off) + && known_gt (off, 0)) maxbound = wide_int_to_tree (sizetype, wi::sub (wi::to_wide (maxbound), off)); @@ -4185,6 +4198,7 @@ vrp_prop::check_array_ref (location_t location, tree ref, "array subscript %E is above array bounds of %qT", low_bound, artype); + const value_range *vr = NULL; if (TREE_CODE (low_sub) == SSA_NAME) { vr = get_value_range (low_sub); @@ -4195,7 +4209,9 @@ vrp_prop::check_array_ref (location_t location, tree ref, } } - if (vr && vr->kind () == VR_ANTI_RANGE) + if (warned) + ; /* Do nothing. */ + else if (vr && vr->kind () == VR_ANTI_RANGE) { if (up_bound && TREE_CODE (up_sub) == INTEGER_CST @@ -4214,19 +4230,25 @@ vrp_prop::check_array_ref (location_t location, tree ref, && (ignore_off_by_one ? !tree_int_cst_le (up_sub, up_bound_p1) : !tree_int_cst_le (up_sub, up_bound))) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Array bound warning for "); - dump_generic_expr (MSG_NOTE, TDF_SLIM, ref); - fprintf (dump_file, "\n"); - } - warned = warning_at (location, OPT_Warray_bounds, - "array subscript %E is above array bounds of %qT", - up_sub, artype); - } + warned = warning_at (location, OPT_Warray_bounds, + "array subscript %E is above array bounds of %qT", + up_sub, artype); else if (TREE_CODE (low_sub) == INTEGER_CST && tree_int_cst_lt (low_sub, low_bound)) + warned = warning_at (location, OPT_Warray_bounds, + "array subscript %E is below array bounds of %qT", + low_sub, artype); + + if (!warned && interior_zero_len) + warned = warning_at (location, OPT_Wzero_length_bounds, + (TREE_CODE (low_sub) == INTEGER_CST + ? G_("array subscript %E is outside the bounds " + "of an interior zero-length array %qT") + : G_("array subscript %qE is outside the bounds " + "of an interior zero-length array %qT")), + low_sub, artype); + + if (warned) { if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -4234,19 +4256,25 @@ vrp_prop::check_array_ref (location_t location, tree ref, dump_generic_expr (MSG_NOTE, TDF_SLIM, ref); fprintf (dump_file, "\n"); } - warned = warning_at (location, OPT_Warray_bounds, - "array subscript %E is below array bounds of %qT", - low_sub, artype); - } - if (warned) - { ref = TREE_OPERAND (ref, 0); + + tree rec = NULL_TREE; if (TREE_CODE (ref) == COMPONENT_REF) - ref = TREE_OPERAND (ref, 1); + { + /* For a reference to a member of a struct object also mention + the object if it's known. It may be defined in a different + function than the out-of-bounds access. */ + rec = TREE_OPERAND (ref, 0); + if (!VAR_P (rec)) + rec = NULL_TREE; + ref = TREE_OPERAND (ref, 1); + } if (DECL_P (ref)) inform (DECL_SOURCE_LOCATION (ref), "while referencing %qD", ref); + if (rec && DECL_P (rec)) + inform (DECL_SOURCE_LOCATION (rec), "defined here %qD", rec); TREE_NO_WARNING (ref) = 1; } @@ -4391,16 +4419,21 @@ vrp_prop::check_mem_ref (location_t location, tree ref, /* The type of the object being referred to. It can be an array, string literal, or a non-array type when the MEM_REF represents a reference/subscript via a pointer to an object that is not - an element of an array. References to members of structs and - unions are excluded because MEM_REF doesn't make it possible - to identify the member where the reference originated. - Incomplete types are excluded as well because their size is - not known. */ + an element of an array. Incomplete types are excluded as well + because their size is not known. */ tree reftype = TREE_TYPE (arg); if (POINTER_TYPE_P (reftype) || !COMPLETE_TYPE_P (reftype) - || TREE_CODE (TYPE_SIZE_UNIT (reftype)) != INTEGER_CST - || RECORD_OR_UNION_TYPE_P (reftype)) + || TREE_CODE (TYPE_SIZE_UNIT (reftype)) != INTEGER_CST) + return false; + + /* Except in declared objects, references to trailing array members + of structs and union objects are excluded because MEM_REF doesn't + make it possible to identify the member where the reference + originated. */ + if (RECORD_OR_UNION_TYPE_P (reftype) + && (!VAR_P (arg) + || (DECL_EXTERNAL (arg) && array_at_struct_end_p (ref)))) return false; arrbounds[0] = 0; @@ -4412,7 +4445,14 @@ vrp_prop::check_mem_ref (location_t location, tree ref, if (tree dom = TYPE_DOMAIN (reftype)) { tree bnds[] = { TYPE_MIN_VALUE (dom), TYPE_MAX_VALUE (dom) }; - if (array_at_struct_end_p (arg) || !bnds[0] || !bnds[1]) + if (TREE_CODE (arg) == COMPONENT_REF) + { + offset_int size = maxobjsize; + if (tree fldsize = component_ref_size (arg)) + size = wi::to_offset (fldsize); + arrbounds[1] = wi::lrshift (size, wi::floor_log2 (eltsize)); + } + else if (array_at_struct_end_p (arg) || !bnds[0] || !bnds[1]) arrbounds[1] = wi::lrshift (maxobjsize, wi::floor_log2 (eltsize)); else arrbounds[1] = (wi::to_offset (bnds[1]) - wi::to_offset (bnds[0]) @@ -4434,7 +4474,13 @@ vrp_prop::check_mem_ref (location_t location, tree ref, else { eltsize = 1; - arrbounds[1] = wi::to_offset (TYPE_SIZE_UNIT (reftype)); + tree size = TYPE_SIZE_UNIT (reftype); + if (VAR_P (arg)) + if (tree initsize = DECL_SIZE_UNIT (arg)) + if (tree_int_cst_lt (size, initsize)) + size = initsize; + + arrbounds[1] = wi::to_offset (size); } offrange[0] += ioff; |