diff options
author | Martin Sebor <msebor@redhat.com> | 2019-08-28 16:43:56 +0000 |
---|---|---|
committer | Martin Sebor <msebor@gcc.gnu.org> | 2019-08-28 10:43:56 -0600 |
commit | 464969eb9b47eb2f24403c74c16769a58dbaa638 (patch) | |
tree | 821481a2cfc3a3c99c5d25b19c08cd56afef8e58 /gcc/tree-vrp.c | |
parent | e2eee239811d4335f28ccdf7c2d9c490fcf6612d (diff) | |
download | gcc-464969eb9b47eb2f24403c74c16769a58dbaa638.zip gcc-464969eb9b47eb2f24403c74c16769a58dbaa638.tar.gz gcc-464969eb9b47eb2f24403c74c16769a58dbaa638.tar.bz2 |
PR tree-optimization/91457 - inconsistent warning for writing past the end of an array member
gcc/ChangeLog:
PR tree-optimization/91457
* builtins.c (component_size): New function.
(compute_objsize): Add argument. Handle ARRAY_REF and COMPONENT_REF.
* builtins.h (compute_objsize): Add argument.
* tree-ssa-strlen.c (handle_store): Handle no-warning bit.
* tree-vrp.c (vrp_prop::check_array_ref): Return warning result.
(vrp_prop::check_mem_ref): Same.
(vrp_prop::search_for_addr_array): Set no-warning bit.
(check_array_bounds): Same.
gcc/testsuite/ChangeLog:
PR tree-optimization/91457
* c-c++-common/Wstringop-overflow-2.c: New test.
* g++.dg/warn/Warray-bounds-8.C: New test.
* g++.dg/warn/Wstringop-overflow-3.C: New test.
* gcc.dg/Wstringop-overflow-15.c: New test.
From-SVN: r274997
Diffstat (limited to 'gcc/tree-vrp.c')
-rw-r--r-- | gcc/tree-vrp.c | 57 |
1 files changed, 38 insertions, 19 deletions
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 5ec4d17..c95b5ad 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -4388,8 +4388,8 @@ class vrp_prop : public ssa_propagation_engine void vrp_initialize (void); void vrp_finalize (bool); void check_all_array_refs (void); - void check_array_ref (location_t, tree, bool); - void check_mem_ref (location_t, tree, bool); + bool check_array_ref (location_t, tree, bool); + bool check_mem_ref (location_t, tree, bool); void search_for_addr_array (tree, location_t); class vr_values vr_values; @@ -4415,9 +4415,10 @@ class vrp_prop : public ssa_propagation_engine array subscript is a constant, check if it is outside valid range. If the array subscript is a RANGE, warn if it is non-overlapping with valid range. - IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR. */ + IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR. + Returns true if a warning has been issued. */ -void +bool vrp_prop::check_array_ref (location_t location, tree ref, bool ignore_off_by_one) { @@ -4426,7 +4427,7 @@ vrp_prop::check_array_ref (location_t location, tree ref, tree low_bound, up_bound, up_bound_p1; if (TREE_NO_WARNING (ref)) - return; + return false; low_sub = up_sub = TREE_OPERAND (ref, 1); up_bound = array_ref_up_bound (ref); @@ -4541,12 +4542,16 @@ vrp_prop::check_array_ref (location_t location, tree ref, if (warned) { ref = TREE_OPERAND (ref, 0); + if (TREE_CODE (ref) == COMPONENT_REF) + ref = TREE_OPERAND (ref, 1); if (DECL_P (ref)) inform (DECL_SOURCE_LOCATION (ref), "while referencing %qD", ref); TREE_NO_WARNING (ref) = 1; } + + return warned; } /* Checks one MEM_REF in REF, located at LOCATION, for out-of-bounds @@ -4556,14 +4561,15 @@ vrp_prop::check_array_ref (location_t location, tree ref, with valid range. IGNORE_OFF_BY_ONE is true if the MEM_REF is inside an ADDR_EXPR (used to allow one-past-the-end indices for code that takes - the address of the just-past-the-end element of an array). */ + the address of the just-past-the-end element of an array). + Returns true if a warning has been issued. */ -void +bool vrp_prop::check_mem_ref (location_t location, tree ref, bool ignore_off_by_one) { if (TREE_NO_WARNING (ref)) - return; + return false; tree arg = TREE_OPERAND (ref, 0); /* The constant and variable offset of the reference. */ @@ -4615,7 +4621,7 @@ vrp_prop::check_mem_ref (location_t location, tree ref, continue; } else - return; + return false; /* VAROFF should always be a SSA_NAME here (and not even INTEGER_CST) but there's no point in taking chances. */ @@ -4677,10 +4683,10 @@ vrp_prop::check_mem_ref (location_t location, tree ref, arg = TREE_OPERAND (arg, 0); if (TREE_CODE (arg) != STRING_CST && TREE_CODE (arg) != VAR_DECL) - return; + return false; } else - return; + return false; /* 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 @@ -4695,7 +4701,7 @@ vrp_prop::check_mem_ref (location_t location, tree ref, || !COMPLETE_TYPE_P (reftype) || TREE_CODE (TYPE_SIZE_UNIT (reftype)) != INTEGER_CST || RECORD_OR_UNION_TYPE_P (reftype)) - return; + return false; offset_int eltsize; if (TREE_CODE (reftype) == ARRAY_TYPE) @@ -4797,11 +4803,11 @@ vrp_prop::check_mem_ref (location_t location, tree ref, if (warned) TREE_NO_WARNING (ref) = 1; - return; + return warned; } if (warn_array_bounds < 2) - return; + return false; /* At level 2 check also intermediate offsets. */ int i = 0; @@ -4812,8 +4818,13 @@ vrp_prop::check_mem_ref (location_t location, tree ref, if (warning_at (location, OPT_Warray_bounds, "intermediate array offset %wi is outside array bounds " "of %qT", tmpidx, reftype)) - TREE_NO_WARNING (ref) = 1; + { + TREE_NO_WARNING (ref) = 1; + return true; + } } + + return false; } /* Searches if the expr T, located at LOCATION computes @@ -4825,10 +4836,14 @@ vrp_prop::search_for_addr_array (tree t, location_t location) /* Check each ARRAY_REF and MEM_REF in the reference chain. */ do { + bool warned = false; if (TREE_CODE (t) == ARRAY_REF) - check_array_ref (location, t, true /*ignore_off_by_one*/); + warned = check_array_ref (location, t, true /*ignore_off_by_one*/); else if (TREE_CODE (t) == MEM_REF) - check_mem_ref (location, t, true /*ignore_off_by_one*/); + warned = check_mem_ref (location, t, true /*ignore_off_by_one*/); + + if (warned) + TREE_NO_WARNING (t) = true; t = TREE_OPERAND (t, 0); } @@ -4920,16 +4935,20 @@ check_array_bounds (tree *tp, int *walk_subtree, void *data) *walk_subtree = TRUE; + bool warned = false; vrp_prop *vrp_prop = (class vrp_prop *)wi->info; if (TREE_CODE (t) == ARRAY_REF) - vrp_prop->check_array_ref (location, t, false /*ignore_off_by_one*/); + warned = vrp_prop->check_array_ref (location, t, false/*ignore_off_by_one*/); else if (TREE_CODE (t) == MEM_REF) - vrp_prop->check_mem_ref (location, t, false /*ignore_off_by_one*/); + warned = vrp_prop->check_mem_ref (location, t, false /*ignore_off_by_one*/); else if (TREE_CODE (t) == ADDR_EXPR) { vrp_prop->search_for_addr_array (t, location); *walk_subtree = FALSE; } + /* Propagate the no-warning bit to the outer expression. */ + if (warned) + TREE_NO_WARNING (t) = true; return NULL_TREE; } |