aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-vrp.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2019-11-01 21:09:20 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2019-11-01 15:09:20 -0600
commit49fb45c81f4ac068d9fb859968d8f223bc438251 (patch)
tree56f91e1dcae71841b97747d2342eacce4c35592e /gcc/tree-vrp.c
parent8dc56a2244cfe35cbdb53e0f586c16f90a2677e4 (diff)
downloadgcc-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.c108
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;