aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-array-bounds.cc
diff options
context:
space:
mode:
authorThomas Schwinge <thomas@codesourcery.com>2022-12-13 22:44:33 +0100
committerThomas Schwinge <thomas@codesourcery.com>2022-12-13 22:44:33 +0100
commit74e16385964d6c03d99916654389edf39e768147 (patch)
tree1b0109018777011a30ed9c961ed7b00bf3ead482 /gcc/gimple-array-bounds.cc
parent62d1620c91053438399064fa4eddb15d09cbabf4 (diff)
parentb4fddbe9592e9feb37ce567d90af822b75995531 (diff)
downloadgcc-74e16385964d6c03d99916654389edf39e768147.zip
gcc-74e16385964d6c03d99916654389edf39e768147.tar.gz
gcc-74e16385964d6c03d99916654389edf39e768147.tar.bz2
Merge commit 'b4fddbe9592e9feb37ce567d90af822b75995531' into HEAD
Diffstat (limited to 'gcc/gimple-array-bounds.cc')
-rw-r--r--gcc/gimple-array-bounds.cc202
1 files changed, 117 insertions, 85 deletions
diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
index e190b93..59bd9eb 100644
--- a/gcc/gimple-array-bounds.cc
+++ b/gcc/gimple-array-bounds.cc
@@ -46,9 +46,6 @@ array_bounds_checker::array_bounds_checker (struct function *func,
/* No-op. */
}
-// This purposely returns a value_range, not a value_range_equiv, to
-// break the dependency on equivalences for this pass.
-
const value_range *
array_bounds_checker::get_value_range (const_tree op, gimple *stmt)
{
@@ -78,14 +75,7 @@ get_base_decl (tree ref)
if (gimple_assign_single_p (def))
{
base = gimple_assign_rhs1 (def);
- if (TREE_CODE (base) != ASSERT_EXPR)
- return base;
-
- base = TREE_OPERAND (base, 0);
- if (TREE_CODE (base) != SSA_NAME)
- return base;
-
- continue;
+ return base;
}
if (!gimple_nop_p (def))
@@ -129,7 +119,7 @@ get_ref_size (tree arg, tree *pref)
}
/* Return true if REF is (likely) an ARRAY_REF to a trailing array member
- of a struct. It refines array_at_struct_end_p by detecting a pointer
+ of a struct. It refines array_ref_flexible_size_p by detecting a pointer
to an array and an array parameter declared using the [N] syntax (as
opposed to a pointer) and returning false. Set *PREF to the decl or
expression REF refers to. */
@@ -167,41 +157,20 @@ trailing_array (tree arg, tree *pref)
return false;
}
- return array_at_struct_end_p (arg);
+ return array_ref_flexible_size_p (arg);
}
-/* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible
- arrays and "struct" hacks. If VRP can determine that the 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. Return true if a warning has been issued or if
- no-warning is set. */
+/* Acquire the upper bound and upper bound plus one for the array
+ reference REF and record them into UP_BOUND and UP_BOUND_P1.
+ Set *DECL to the decl or expresssion REF refers to. */
-bool
-array_bounds_checker::check_array_ref (location_t location, tree ref,
- gimple *stmt, bool ignore_off_by_one)
+static void
+get_up_bounds_for_array_ref (tree ref, tree *decl,
+ tree *up_bound, tree *up_bound_p1)
{
- if (warning_suppressed_p (ref, OPT_Warray_bounds))
- /* Return true to have the caller prevent warnings for enclosing
- refs. */
- return true;
-
- tree low_sub = TREE_OPERAND (ref, 1);
- tree up_sub = low_sub;
- tree up_bound = array_ref_up_bound (ref);
-
- /* Referenced decl if one can be determined. */
- tree decl = NULL_TREE;
-
- /* Set for accesses to interior zero-length arrays. */
- special_array_member sam{ };
-
- tree up_bound_p1;
-
- if (!up_bound
- || TREE_CODE (up_bound) != INTEGER_CST
- || (warn_array_bounds < 2 && trailing_array (ref, &decl)))
+ if (!(*up_bound)
+ || TREE_CODE (*up_bound) != INTEGER_CST
+ || trailing_array (ref, decl))
{
/* Accesses to trailing arrays via pointers may access storage
beyond the types array bounds. For such arrays, or for flexible
@@ -213,8 +182,8 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
if (TREE_CODE (eltsize) != INTEGER_CST
|| integer_zerop (eltsize))
{
- up_bound = NULL_TREE;
- up_bound_p1 = NULL_TREE;
+ *up_bound = NULL_TREE;
+ *up_bound_p1 = NULL_TREE;
}
else
{
@@ -227,7 +196,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
{
/* Try to determine the size of the trailing array from
its initializer (if it has one). */
- if (tree refsize = component_ref_size (arg, &sam))
+ if (tree refsize = component_ref_size (arg))
if (TREE_CODE (refsize) == INTEGER_CST)
maxbound = refsize;
}
@@ -246,7 +215,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
{
/* Try to determine the size from a pointer to
an array if BASE is one. */
- if (tree size = get_ref_size (base, &decl))
+ if (tree size = get_ref_size (base, decl))
maxbound = size;
}
else if (!compref && DECL_P (base))
@@ -254,7 +223,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
if (TREE_CODE (basesize) == INTEGER_CST)
{
maxbound = basesize;
- decl = base;
+ *decl = base;
}
if (known_gt (off, 0))
@@ -266,41 +235,42 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
else
maxbound = fold_convert (sizetype, maxbound);
- up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
+ *up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
- if (up_bound_p1 != NULL_TREE)
- up_bound = int_const_binop (MINUS_EXPR, up_bound_p1,
+ if (*up_bound_p1 != NULL_TREE)
+ *up_bound = int_const_binop (MINUS_EXPR, *up_bound_p1,
build_int_cst (ptrdiff_type_node, 1));
else
- up_bound = NULL_TREE;
+ *up_bound = NULL_TREE;
}
}
else
- up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound,
- build_int_cst (TREE_TYPE (up_bound), 1));
+ *up_bound_p1 = int_const_binop (PLUS_EXPR, *up_bound,
+ build_int_cst (TREE_TYPE (*up_bound), 1));
+ return;
+}
- tree low_bound = array_ref_low_bound (ref);
+/* Given the LOW_SUB_ORG, LOW_SUB and UP_SUB, and the computed UP_BOUND
+ and UP_BOUND_P1, check whether the array reference REF is out of bound.
+ Issue warnings if out of bound, return TRUE if warnings are issued. */
+static bool
+check_out_of_bounds_and_warn (location_t location, tree ref,
+ tree low_sub_org, tree low_sub, tree up_sub,
+ tree up_bound, tree up_bound_p1,
+ const value_range *vr,
+ bool ignore_off_by_one)
+{
+ tree low_bound = array_ref_low_bound (ref);
tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
bool warned = false;
/* Empty array. */
if (up_bound && tree_int_cst_equal (low_bound, up_bound_p1))
- warned = warning_at (location, OPT_Warray_bounds,
+ warned = warning_at (location, OPT_Warray_bounds_,
"array subscript %E is outside array bounds of %qT",
- low_sub, artype);
-
- const value_range *vr = NULL;
- if (TREE_CODE (low_sub) == SSA_NAME)
- {
- vr = get_value_range (low_sub, stmt);
- if (!vr->undefined_p () && !vr->varying_p ())
- {
- low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
- up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
- }
- }
+ low_sub_org, artype);
if (warned)
; /* Do nothing. */
@@ -313,7 +283,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
: tree_int_cst_le (up_bound, up_sub))
&& TREE_CODE (low_sub) == INTEGER_CST
&& tree_int_cst_le (low_sub, low_bound))
- warned = warning_at (location, OPT_Warray_bounds,
+ warned = warning_at (location, OPT_Warray_bounds_,
"array subscript [%E, %E] is outside "
"array bounds of %qT",
low_sub, up_sub, artype);
@@ -323,14 +293,76 @@ array_bounds_checker::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)))
- warned = warning_at (location, OPT_Warray_bounds,
+ 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,
+ warned = warning_at (location, OPT_Warray_bounds_,
"array subscript %E is below array bounds of %qT",
low_sub, artype);
+ return warned;
+}
+
+/* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible
+ arrays and "struct" hacks. If VRP can determine that the 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. Return true if a warning has been issued or if
+ no-warning is set. */
+
+bool
+array_bounds_checker::check_array_ref (location_t location, tree ref,
+ gimple *stmt, bool ignore_off_by_one)
+{
+ if (warning_suppressed_p (ref, OPT_Warray_bounds_))
+ /* Return true to have the caller prevent warnings for enclosing
+ refs. */
+ return true;
+
+ /* Upper bound and Upper bound plus one for -Warray-bounds. */
+ tree up_bound = array_ref_up_bound (ref);
+ tree up_bound_p1 = NULL_TREE;
+
+ /* Referenced decl if one can be determined. */
+ tree decl = NULL_TREE;
+
+ /* Set to the type of the special array member for a COMPONENT_REF. */
+ special_array_member sam{ };
+
+ tree arg = TREE_OPERAND (ref, 0);
+ const bool compref = TREE_CODE (arg) == COMPONENT_REF;
+
+ if (compref)
+ /* Try to determine special array member type for this COMPONENT_REF. */
+ sam = component_ref_sam_type (arg);
+
+ get_up_bounds_for_array_ref (ref, &decl, &up_bound, &up_bound_p1);
+
+ bool warned = false;
+
+ tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
+ tree low_sub_org = TREE_OPERAND (ref, 1);
+ tree up_sub = low_sub_org;
+ tree low_sub = low_sub_org;
+
+ const value_range *vr = NULL;
+ if (TREE_CODE (low_sub_org) == SSA_NAME)
+ {
+ vr = get_value_range (low_sub_org, stmt);
+ if (!vr->undefined_p () && !vr->varying_p ())
+ {
+ low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
+ up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
+ }
+ }
+
+ warned = check_out_of_bounds_and_warn (location, ref,
+ low_sub_org, low_sub, up_sub,
+ up_bound, up_bound_p1, vr,
+ ignore_off_by_one);
+
if (!warned && sam == special_array_member::int_0)
warned = warning_at (location, OPT_Wzero_length_bounds,
@@ -353,7 +385,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
/* Avoid more warnings when checking more significant subscripts
of the same expression. */
ref = TREE_OPERAND (ref, 0);
- suppress_warning (ref, OPT_Warray_bounds);
+ suppress_warning (ref, OPT_Warray_bounds_);
if (decl)
ref = decl;
@@ -393,7 +425,7 @@ bool
array_bounds_checker::check_mem_ref (location_t location, tree ref,
bool ignore_off_by_one)
{
- if (warning_suppressed_p (ref, OPT_Warray_bounds))
+ if (warning_suppressed_p (ref, OPT_Warray_bounds_))
return false;
/* The statement used to allocate the array or null. */
@@ -493,12 +525,12 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref,
if (lboob)
{
if (offrange[0] == offrange[1])
- warned = warning_at (location, OPT_Warray_bounds,
+ warned = warning_at (location, OPT_Warray_bounds_,
"array subscript %wi is outside array bounds "
"of %qT",
offrange[0].to_shwi (), reftype);
else
- warned = warning_at (location, OPT_Warray_bounds,
+ warned = warning_at (location, OPT_Warray_bounds_,
"array subscript [%wi, %wi] is outside "
"array bounds of %qT",
offrange[0].to_shwi (),
@@ -513,7 +545,7 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref,
backtype = build_array_type_nelts (unsigned_char_type_node,
aref.sizrng[1].to_uhwi ());
- warned = warning_at (location, OPT_Warray_bounds,
+ warned = warning_at (location, OPT_Warray_bounds_,
"array subscript %<%T[%wi]%> is partly "
"outside array bounds of %qT",
axstype, offrange[0].to_shwi (), backtype);
@@ -523,7 +555,7 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref,
{
/* TODO: Determine the access from the statement and use it. */
aref.inform_access (access_none);
- suppress_warning (ref, OPT_Warray_bounds);
+ suppress_warning (ref, OPT_Warray_bounds_);
return true;
}
@@ -536,11 +568,11 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref,
{
HOST_WIDE_INT tmpidx = (aref.offmax[i] / eltsize).to_shwi ();
- if (warning_at (location, OPT_Warray_bounds,
+ if (warning_at (location, OPT_Warray_bounds_,
"intermediate array offset %wi is outside array bounds "
"of %qT", tmpidx, reftype))
{
- suppress_warning (ref, OPT_Warray_bounds);
+ suppress_warning (ref, OPT_Warray_bounds_);
return true;
}
}
@@ -572,7 +604,7 @@ array_bounds_checker::check_addr_expr (location_t location, tree t,
warned = check_mem_ref (location, t, ignore_off_by_one);
if (warned)
- suppress_warning (t, OPT_Warray_bounds);
+ suppress_warning (t, OPT_Warray_bounds_);
t = TREE_OPERAND (t, 0);
}
@@ -580,7 +612,7 @@ array_bounds_checker::check_addr_expr (location_t location, tree t,
if (TREE_CODE (t) != MEM_REF
|| TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR
- || warning_suppressed_p (t, OPT_Warray_bounds))
+ || warning_suppressed_p (t, OPT_Warray_bounds_))
return;
tree tem = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
@@ -615,7 +647,7 @@ array_bounds_checker::check_addr_expr (location_t location, tree t,
dump_generic_expr (MSG_NOTE, TDF_SLIM, t);
fprintf (dump_file, "\n");
}
- warned = warning_at (location, OPT_Warray_bounds,
+ warned = warning_at (location, OPT_Warray_bounds_,
"array subscript %wi is below "
"array bounds of %qT",
idx.to_shwi (), TREE_TYPE (tem));
@@ -629,7 +661,7 @@ array_bounds_checker::check_addr_expr (location_t location, tree t,
dump_generic_expr (MSG_NOTE, TDF_SLIM, t);
fprintf (dump_file, "\n");
}
- warned = warning_at (location, OPT_Warray_bounds,
+ warned = warning_at (location, OPT_Warray_bounds_,
"array subscript %wu is above "
"array bounds of %qT",
idx.to_uhwi (), TREE_TYPE (tem));
@@ -640,7 +672,7 @@ array_bounds_checker::check_addr_expr (location_t location, tree t,
if (DECL_P (t))
inform (DECL_SOURCE_LOCATION (t), "while referencing %qD", t);
- suppress_warning (t, OPT_Warray_bounds);
+ suppress_warning (t, OPT_Warray_bounds_);
}
}
@@ -740,7 +772,7 @@ array_bounds_checker::check_array_bounds (tree *tp, int *walk_subtree,
/* Propagate the no-warning bit to the outer statement to avoid also
issuing -Wstringop-overflow/-overread for the out-of-bounds accesses. */
if (warned)
- suppress_warning (wi->stmt, OPT_Warray_bounds);
+ suppress_warning (wi->stmt, OPT_Warray_bounds_);
return NULL_TREE;
}