diff options
author | Thomas Schwinge <thomas@codesourcery.com> | 2022-12-13 22:44:33 +0100 |
---|---|---|
committer | Thomas Schwinge <thomas@codesourcery.com> | 2022-12-13 22:44:33 +0100 |
commit | 74e16385964d6c03d99916654389edf39e768147 (patch) | |
tree | 1b0109018777011a30ed9c961ed7b00bf3ead482 /gcc/gimple-array-bounds.cc | |
parent | 62d1620c91053438399064fa4eddb15d09cbabf4 (diff) | |
parent | b4fddbe9592e9feb37ce567d90af822b75995531 (diff) | |
download | gcc-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.cc | 202 |
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; } |