LCOV - code coverage report
Current view: top level - gcc - gimple-array-bounds.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 87.2 % 398 347
Test Date: 2026-02-28 14:20:25 Functions: 94.4 % 18 17
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Array bounds checking.
       2              :    Copyright (C) 2005-2026 Free Software Foundation, Inc.
       3              : 
       4              : This file is part of GCC.
       5              : 
       6              : GCC is free software; you can redistribute it and/or modify
       7              : it under the terms of the GNU General Public License as published by
       8              : the Free Software Foundation; either version 3, or (at your option)
       9              : any later version.
      10              : 
      11              : GCC is distributed in the hope that it will be useful,
      12              : but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14              : GNU General Public License for more details.
      15              : 
      16              : You should have received a copy of the GNU General Public License
      17              : along with GCC; see the file COPYING3.  If not see
      18              : <http://www.gnu.org/licenses/>.  */
      19              : 
      20              : #include "config.h"
      21              : #include "system.h"
      22              : #include "coretypes.h"
      23              : #include "backend.h"
      24              : #include "tree.h"
      25              : #include "gimple.h"
      26              : #include "ssa.h"
      27              : #include "pointer-query.h"
      28              : #include "gimple-array-bounds.h"
      29              : #include "gimple-iterator.h"
      30              : #include "gimple-walk.h"
      31              : #include "tree-dfa.h"
      32              : #include "fold-const.h"
      33              : #include "diagnostic-core.h"
      34              : #include "diagnostic-context-rich-location.h"
      35              : #include "intl.h"
      36              : #include "tree-vrp.h"
      37              : #include "alloc-pool.h"
      38              : #include "vr-values.h"
      39              : #include "domwalk.h"
      40              : #include "tree-cfg.h"
      41              : #include "attribs.h"
      42              : #include "tree-pass.h"
      43              : #include "gimple-range.h"
      44              : 
      45              : // Always use the current range query for the bounds checker.
      46       109180 : array_bounds_checker::array_bounds_checker (struct function *func)
      47       218360 :   : fun (func), m_ptr_qry (get_range_query (func))
      48              : {
      49              :   /* No-op.  */
      50       109180 : }
      51              : 
      52              : void
      53       133921 : array_bounds_checker::get_value_range (irange &r, const_tree op, gimple *stmt)
      54              : {
      55       133921 :   if (m_ptr_qry.rvals->range_of_expr (r, const_cast<tree> (op), stmt))
      56              :     return;
      57            0 :   r.set_varying (TREE_TYPE (op));
      58              : }
      59              : 
      60              : /* Try to determine the DECL that REF refers to.  Return the DECL or
      61              :    the expression closest to it.  Used in informational notes pointing
      62              :    to referenced objects or function parameters.  */
      63              : 
      64              : static tree
      65       164205 : get_base_decl (tree ref)
      66              : {
      67       164205 :   tree base = get_base_address (ref);
      68       164205 :   if (DECL_P (base))
      69              :     return base;
      70              : 
      71        14401 :   if (TREE_CODE (base) == MEM_REF)
      72        13815 :     base = TREE_OPERAND (base, 0);
      73              : 
      74        14401 :   if (TREE_CODE (base) != SSA_NAME)
      75              :     return base;
      76              : 
      77        13854 :   do
      78              :     {
      79        13854 :       gimple *def = SSA_NAME_DEF_STMT (base);
      80        13854 :       if (gimple_assign_single_p (def))
      81              :         {
      82         1989 :           base = gimple_assign_rhs1 (def);
      83         1989 :           return base;
      84              :         }
      85              : 
      86        11865 :       if (!gimple_nop_p (def))
      87              :         return base;
      88              : 
      89         8107 :       break;
      90              :     } while (true);
      91              : 
      92         8107 :   tree var = SSA_NAME_VAR (base);
      93         8107 :   if (TREE_CODE (var) != PARM_DECL)
      94            0 :     return base;
      95              : 
      96              :   return var;
      97              : }
      98              : 
      99              : /* Return the constant byte size of the object or type referenced by
     100              :    the MEM_REF ARG.  On success, set *PREF to the DECL or expression
     101              :    ARG refers to.  Otherwise return null.  */
     102              : 
     103              : static tree
     104        65606 : get_ref_size (tree arg, tree *pref)
     105              : {
     106        65606 :   if (TREE_CODE (arg) != MEM_REF)
     107              :     return NULL_TREE;
     108              : 
     109        65606 :   arg = TREE_OPERAND (arg, 0);
     110        65606 :   tree type = TREE_TYPE (arg);
     111        65606 :   if (!POINTER_TYPE_P (type))
     112              :     return NULL_TREE;
     113              : 
     114        65606 :   type = TREE_TYPE (type);
     115        65606 :   if (TREE_CODE (type) != ARRAY_TYPE)
     116              :     return NULL_TREE;
     117              : 
     118          587 :   tree nbytes = TYPE_SIZE_UNIT (type);
     119          587 :   if (!nbytes || TREE_CODE (nbytes) != INTEGER_CST)
     120              :     return NULL_TREE;
     121              : 
     122           39 :   *pref = get_base_decl (arg);
     123           39 :   return nbytes;
     124              : }
     125              : 
     126              : /* Return true if REF is (likely) an ARRAY_REF to a trailing array member
     127              :    of a struct.  It refines array_ref_flexible_size_p by detecting a pointer
     128              :    to an array and an array parameter declared using the [N] syntax (as
     129              :    opposed to a pointer) and returning false.  Set *PREF to the decl or
     130              :    expression REF refers to.  */
     131              : 
     132              : static bool
     133       164166 : trailing_array (tree arg, tree *pref)
     134              : {
     135       164166 :   tree ref = arg;
     136       164166 :   tree base = get_base_decl (arg);
     137       499365 :   while (TREE_CODE (ref) == ARRAY_REF || TREE_CODE (ref) == MEM_REF)
     138       171033 :     ref = TREE_OPERAND (ref, 0);
     139              : 
     140       164166 :   if (TREE_CODE (ref) == COMPONENT_REF)
     141              :     {
     142        36396 :       *pref = TREE_OPERAND (ref, 1);
     143        36396 :       tree type = TREE_TYPE (*pref);
     144        36396 :       if (TREE_CODE (type) == ARRAY_TYPE)
     145              :         {
     146              :           /* A multidimensional trailing array is not considered special
     147              :              no matter what its major bound is.  */
     148        36396 :           type = TREE_TYPE (type);
     149        36396 :           if (TREE_CODE (type) == ARRAY_TYPE)
     150              :             return false;
     151              :         }
     152              :     }
     153              :   else
     154       127770 :     *pref = base;
     155              : 
     156       160182 :   tree basetype = TREE_TYPE (base);
     157       160182 :   if (TREE_CODE (base) == PARM_DECL
     158        11194 :       && POINTER_TYPE_P (basetype))
     159              :     {
     160         7579 :       tree ptype = TREE_TYPE (basetype);
     161         7579 :       if (TREE_CODE (ptype) == ARRAY_TYPE)
     162              :         return false;
     163              :     }
     164              : 
     165       159957 :   return array_ref_flexible_size_p (arg);
     166              : }
     167              : 
     168              : /* Acquire the upper bound and upper bound plus one for the array
     169              :    reference REF and record them into UP_BOUND and UP_BOUND_P1.
     170              :    Set *DECL to the decl or expresssion REF refers to.  */
     171              : 
     172              : static void
     173       238066 : get_up_bounds_for_array_ref (tree ref, tree *decl,
     174              :                              tree *up_bound, tree *up_bound_p1)
     175              : {
     176       238066 :   if (!(*up_bound)
     177       165633 :       || TREE_CODE (*up_bound) != INTEGER_CST
     178       402232 :       || trailing_array (ref, decl))
     179              :     {
     180              :       /* Accesses to trailing arrays via pointers may access storage
     181              :          beyond the types array bounds.  For such arrays, or for flexible
     182              :          array members, as well as for other arrays of an unknown size,
     183              :          replace the upper bound with a more permissive one that assumes
     184              :          the size of the largest object is PTRDIFF_MAX.  */
     185        80359 :       tree eltsize = array_ref_element_size (ref);
     186              : 
     187        80359 :       if (TREE_CODE (eltsize) != INTEGER_CST
     188        80359 :           || integer_zerop (eltsize))
     189              :         {
     190          577 :           *up_bound = NULL_TREE;
     191          577 :           *up_bound_p1 = NULL_TREE;
     192              :         }
     193              :       else
     194              :         {
     195        79782 :           tree ptrdiff_max = TYPE_MAX_VALUE (ptrdiff_type_node);
     196        79782 :           tree maxbound = ptrdiff_max;
     197        79782 :           tree arg = TREE_OPERAND (ref, 0);
     198              : 
     199        79782 :           const bool compref = TREE_CODE (arg) == COMPONENT_REF;
     200        79782 :           if (compref)
     201              :             {
     202              :               /* Try to determine the size of the trailing array from
     203              :                  its initializer (if it has one).  */
     204        71016 :               if (tree refsize = component_ref_size (arg))
     205         5943 :                 if (TREE_CODE (refsize) == INTEGER_CST)
     206        79782 :                   maxbound = refsize;
     207              :             }
     208              : 
     209        79782 :           if (maxbound == ptrdiff_max)
     210              :             {
     211              :               /* Try to determine the size of the base object.  Avoid
     212              :                  COMPONENT_REF already tried above.  Using its DECL_SIZE
     213              :                  size wouldn't necessarily be correct if the reference is
     214              :                  to its flexible array member initialized in a different
     215              :                  translation unit.  */
     216        73842 :               poly_int64 off;
     217        73842 :               if (tree base = get_addr_base_and_unit_offset (arg, &off))
     218              :                 {
     219        73534 :                   if (TREE_CODE (base) == MEM_REF)
     220              :                     {
     221              :                       /* Try to determine the size from a pointer to
     222              :                          an array if BASE is one.  */
     223        65606 :                       if (tree size = get_ref_size (base, decl))
     224        73534 :                         maxbound = size;
     225              :                     }
     226         7928 :                   else if (!compref && DECL_P (base))
     227         7885 :                     if (tree basesize = DECL_SIZE_UNIT (base))
     228          128 :                       if (TREE_CODE (basesize) == INTEGER_CST)
     229              :                         {
     230          128 :                           maxbound = basesize;
     231          128 :                           *decl = base;
     232              :                         }
     233              : 
     234        73534 :                   if (known_gt (off, 0))
     235        64880 :                     maxbound = wide_int_to_tree (sizetype,
     236       129760 :                                                  wi::sub (wi::to_wide (maxbound),
     237              :                                                           off));
     238              :                 }
     239              :             }
     240              :           else
     241         5940 :             maxbound = fold_convert (sizetype, maxbound);
     242              : 
     243        79782 :           *up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
     244              : 
     245        79782 :           if (*up_bound_p1 != NULL_TREE)
     246        79782 :             *up_bound = int_const_binop (MINUS_EXPR, *up_bound_p1,
     247       159564 :                                         build_int_cst (ptrdiff_type_node, 1));
     248              :           else
     249            0 :             *up_bound = NULL_TREE;
     250              :         }
     251              :     }
     252              :   else
     253       157707 :     *up_bound_p1 = int_const_binop (PLUS_EXPR, *up_bound,
     254       315414 :                                    build_int_cst (TREE_TYPE (*up_bound), 1));
     255       238066 :   return;
     256              : }
     257              : 
     258              : /* Given the LOW_SUB_ORG, LOW_SUB and UP_SUB, and the computed UP_BOUND
     259              :    and UP_BOUND_P1, check whether the array reference REF is out of bound.
     260              :    When out of bounds, set OUT_OF_BOUND to true.
     261              :    Issue warnings if FOR_ARRAY_BOUND is true.
     262              :    return TRUE if warnings are issued.  */
     263              : 
     264              : static bool
     265       238066 : check_out_of_bounds_and_warn (location_t location, tree ref,
     266              :                               gimple *stmt,
     267              :                               tree low_sub_org, tree low_sub, tree up_sub,
     268              :                               tree up_bound, tree up_bound_p1,
     269              :                               const irange *vr,
     270              :                               bool ignore_off_by_one, bool for_array_bound,
     271              :                               bool *out_of_bound)
     272              : {
     273       238066 :   tree min, max;
     274       238066 :   tree low_bound = array_ref_low_bound (ref);
     275       238066 :   tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
     276              : 
     277       238066 :   bool warned = false;
     278       238066 :   *out_of_bound = false;
     279              : 
     280       238066 :   rich_location_with_details richloc (location, stmt);
     281              :   /* Empty array.  */
     282       238066 :   if (up_bound && tree_int_cst_equal (low_bound, up_bound_p1))
     283              :     {
     284          225 :       *out_of_bound = true;
     285          225 :       if (for_array_bound)
     286          224 :         warned = warning_at (&richloc, OPT_Warray_bounds_,
     287              :                              "array subscript %E is outside array"
     288              :                              " bounds of %qT", low_sub_org, artype);
     289              :     }
     290              : 
     291          224 :   if (warned)
     292              :     ; /* Do nothing.  */
     293       237842 :   else if (get_legacy_range (*vr, min, max) == VR_ANTI_RANGE)
     294              :     {
     295         1224 :       if (up_bound
     296         1224 :           && TREE_CODE (up_sub) == INTEGER_CST
     297           75 :           && (ignore_off_by_one
     298         1224 :               ? tree_int_cst_lt (up_bound, up_sub)
     299         1149 :               : tree_int_cst_le (up_bound, up_sub))
     300          695 :           && TREE_CODE (low_sub) == INTEGER_CST
     301         3143 :           && tree_int_cst_le (low_sub, low_bound))
     302              :         {
     303            3 :           *out_of_bound = true;
     304            3 :           if (for_array_bound)
     305            3 :             warned = warning_at (&richloc, OPT_Warray_bounds_,
     306              :                                  "array subscript [%E, %E] is outside "
     307              :                                  "array bounds of %qT",
     308              :                                  low_sub, up_sub, artype);
     309              :         }
     310              :     }
     311       236618 :   else if (up_bound
     312       236041 :            && TREE_CODE (up_sub) == INTEGER_CST
     313       478412 :            && (ignore_off_by_one
     314       233261 :                ? !tree_int_cst_le (up_sub, up_bound_p1)
     315       224728 :                : !tree_int_cst_le (up_sub, up_bound)))
     316              :     {
     317          650 :       *out_of_bound = true;
     318          650 :       if (for_array_bound)
     319          645 :         warned = warning_at (&richloc, OPT_Warray_bounds_,
     320              :                              "array subscript %E is above array bounds of %qT",
     321              :                              up_sub, artype);
     322              :     }
     323       235968 :   else if (TREE_CODE (low_sub) == INTEGER_CST
     324       235968 :            && tree_int_cst_lt (low_sub, low_bound))
     325              :     {
     326          267 :       *out_of_bound = true;
     327          267 :       if (for_array_bound)
     328          267 :         warned = warning_at (&richloc, OPT_Warray_bounds_,
     329              :                              "array subscript %E is below array bounds of %qT",
     330              :                              low_sub, artype);
     331              :     }
     332       476132 :   return warned;
     333       238066 : }
     334              : 
     335              : /* Checks one ARRAY_REF in REF, located at LOCUS.  Ignores flexible
     336              :    arrays and "struct" hacks.  If VRP can determine that the array
     337              :    subscript is a constant, check if it is outside valid range.  If
     338              :    the array subscript is a RANGE, warn if it is non-overlapping with
     339              :    valid range.  IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside
     340              :    a ADDR_EXPR.  Return  true if a warning has been issued or if
     341              :    no-warning is set.  */
     342              : 
     343              : bool
     344       238153 : array_bounds_checker::check_array_ref (location_t location, tree ref,
     345              :                                        gimple *stmt, bool ignore_off_by_one)
     346              : {
     347       238153 :   if (warning_suppressed_p (ref, OPT_Warray_bounds_))
     348              :     /* Return true to have the caller prevent warnings for enclosing
     349              :        refs.  */
     350              :     return true;
     351              : 
     352              :   /* Upper bound and Upper bound plus one for -Warray-bounds.  */
     353       238066 :   tree up_bound = array_ref_up_bound (ref);
     354       238066 :   tree up_bound_p1 = NULL_TREE;
     355              : 
     356              :   /* Referenced decl if one can be determined.  */
     357       238066 :   tree decl = NULL_TREE;
     358              : 
     359              :   /* Set to the type of the special array member for a COMPONENT_REF.  */
     360       238066 :   special_array_member sam{ };
     361       238066 :   tree afield_decl = NULL_TREE;
     362       238066 :   tree arg = TREE_OPERAND (ref, 0);
     363              : 
     364       238066 :   if (TREE_CODE (arg) == COMPONENT_REF)
     365              :     {
     366              :       /* Try to determine special array member type for this COMPONENT_REF.  */
     367        99086 :       sam = component_ref_sam_type (arg);
     368        99086 :       afield_decl = TREE_OPERAND (arg, 1);
     369              :     }
     370              : 
     371       238066 :   get_up_bounds_for_array_ref (ref, &decl, &up_bound, &up_bound_p1);
     372              : 
     373       238066 :   bool warned = false;
     374       238066 :   bool out_of_bound = false;
     375              : 
     376       238066 :   tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
     377       238066 :   tree low_sub_org = TREE_OPERAND (ref, 1);
     378       238066 :   tree up_sub = low_sub_org;
     379       238066 :   tree low_sub = low_sub_org;
     380              : 
     381       238066 :   int_range_max vr;
     382       238066 :   if (TREE_CODE (low_sub_org) == SSA_NAME)
     383              :     {
     384       133921 :       get_value_range (vr, low_sub_org, stmt);
     385       133921 :       if (!vr.undefined_p () && !vr.varying_p ())
     386              :         {
     387       131088 :           tree min, max;
     388       131088 :           value_range_kind kind = get_legacy_range (vr, min, max);
     389       131088 :           low_sub = kind == VR_RANGE ? max : min;
     390       131088 :           up_sub = kind == VR_RANGE ? min : max;
     391              :         }
     392              :     }
     393              : 
     394       476132 :   warned = check_out_of_bounds_and_warn (location, ref, stmt,
     395              :                                          low_sub_org, low_sub, up_sub,
     396              :                                          up_bound, up_bound_p1, &vr,
     397       238066 :                                          ignore_off_by_one, warn_array_bounds,
     398              :                                          &out_of_bound);
     399              : 
     400       238066 :   rich_location_with_details richloc (location, stmt);
     401              : 
     402       238066 :   if (!warned && sam == special_array_member::int_0)
     403           39 :     warned = warning_at (&richloc, OPT_Wzero_length_bounds,
     404           39 :                          (TREE_CODE (low_sub) == INTEGER_CST
     405              :                           ? G_("array subscript %E is outside the bounds "
     406              :                                "of an interior zero-length array %qT")
     407              :                           : G_("array subscript %qE is outside the bounds "
     408              :                                "of an interior zero-length array %qT")),
     409              :                          low_sub, artype);
     410              : 
     411       238066 :   if (warned && dump_file && (dump_flags & TDF_DETAILS))
     412              :     {
     413            0 :       fprintf (dump_file, "Array bound warning for ");
     414            0 :       dump_generic_expr (MSG_NOTE, TDF_SLIM, ref);
     415            0 :       fprintf (dump_file, "\n");
     416              :     }
     417              : 
     418              :    /* Issue warnings for -Wstrict-flex-arrays according to the level of
     419              :       flag_strict_flex_arrays.  */
     420         1145 :   if (out_of_bound && warn_strict_flex_arrays
     421           18 :       && (sam == special_array_member::trail_0
     422              :           || sam == special_array_member::trail_1
     423           18 :           || sam == special_array_member::trail_n)
     424       238084 :       && DECL_NOT_FLEXARRAY (afield_decl))
     425              :     {
     426           18 :       bool warned1
     427           18 :         = warning_at (&richloc, OPT_Wstrict_flex_arrays,
     428              :                       "trailing array %qT should not be used as "
     429              :                       "a flexible array member",
     430              :                       artype);
     431              : 
     432           18 :       if (warned1 && dump_file && (dump_flags & TDF_DETAILS))
     433              :         {
     434            0 :           fprintf (dump_file, "Trailing non flexible-like array bound warning for ");
     435            0 :           dump_generic_expr (MSG_NOTE, TDF_SLIM, ref);
     436            0 :           fprintf (dump_file, "\n");
     437              :         }
     438           18 :       warned |= warned1;
     439              :     }
     440              : 
     441       238066 :   if (warned)
     442              :     {
     443              :       /* Avoid more warnings when checking more significant subscripts
     444              :          of the same expression.  */
     445         1182 :       ref = TREE_OPERAND (ref, 0);
     446         1182 :       suppress_warning (ref, OPT_Warray_bounds_);
     447         1182 :       suppress_warning (ref, OPT_Wstrict_flex_arrays);
     448              : 
     449         1182 :       if (decl)
     450          800 :         ref = decl;
     451              : 
     452         1182 :       tree rec = NULL_TREE;
     453         1182 :       if (TREE_CODE (ref) == COMPONENT_REF)
     454              :         {
     455              :           /* For a reference to a member of a struct object also mention
     456              :              the object if it's known.  It may be defined in a different
     457              :              function than the out-of-bounds access.  */
     458          257 :           rec = TREE_OPERAND (ref, 0);
     459          257 :           if (!VAR_P (rec))
     460          185 :             rec = NULL_TREE;
     461          257 :           ref = TREE_OPERAND (ref, 1);
     462              :         }
     463              : 
     464         1182 :       if (DECL_P (ref))
     465         1082 :         inform (DECL_SOURCE_LOCATION (ref), "while referencing %qD", ref);
     466         1182 :       if (rec && DECL_P (rec))
     467           72 :         inform (DECL_SOURCE_LOCATION (rec), "defined here %qD", rec);
     468              :     }
     469              : 
     470       238066 :   return warned;
     471       238066 : }
     472              : 
     473              : /* Checks one MEM_REF in REF, located at LOCATION, for out-of-bounds
     474              :    references to string constants.  If VRP can determine that the array
     475              :    subscript is a constant, check if it is outside valid range.
     476              :    If the array subscript is a RANGE, warn if it is non-overlapping
     477              :    with valid range.
     478              :    IGNORE_OFF_BY_ONE is true if the MEM_REF is inside an ADDR_EXPR
     479              :    (used to allow one-past-the-end indices for code that takes
     480              :    the address of the just-past-the-end element of an array).
     481              :    Returns true if a warning has been issued.  */
     482              : 
     483              : bool
     484       607842 : array_bounds_checker::check_mem_ref (location_t location, tree ref,
     485              :                                      gimple *stmt,
     486              :                                      bool ignore_off_by_one)
     487              : {
     488       607842 :   if (warning_suppressed_p (ref, OPT_Warray_bounds_))
     489              :     return false;
     490              : 
     491              :   /* The statement used to allocate the array or null.  */
     492       607769 :   gimple *alloc_stmt = NULL;
     493              :   /* For an allocation statement, the low bound of the size range.  */
     494       607769 :   offset_int minbound = 0;
     495              :   /* The type and size of the access.  */
     496       607769 :   tree axstype = TREE_TYPE (ref);
     497       607769 :   offset_int axssize = 0;
     498       607769 :   if (tree access_size = TYPE_SIZE_UNIT (axstype))
     499       606976 :     if (TREE_CODE (access_size) == INTEGER_CST)
     500       606080 :       axssize = wi::to_offset (access_size);
     501              : 
     502       607769 :   access_ref aref;
     503       607769 :   if (!m_ptr_qry.get_ref (ref, m_stmt, &aref, 0))
     504              :     return false;
     505              : 
     506       607765 :   if (aref.offset_in_range (axssize))
     507              :     return false;
     508              : 
     509        10912 :   if (TREE_CODE (aref.ref) == SSA_NAME)
     510              :     {
     511          546 :       gimple *def = SSA_NAME_DEF_STMT (aref.ref);
     512          546 :       if (is_gimple_call (def))
     513              :         {
     514              :           /* Save the allocation call and the low bound on the size.  */
     515        10912 :           alloc_stmt = def;
     516              :           minbound = aref.sizrng[0];
     517              :         }
     518              :     }
     519              : 
     520              :   /* The range of the byte offset into the reference.  Adjusted below.  */
     521        10912 :   offset_int offrange[2] = { aref.offrng[0], aref.offrng[1] };
     522              : 
     523              :   /* The type of the referenced object.  */
     524        10912 :   tree reftype = TREE_TYPE (aref.ref);
     525              :   /* The size of the referenced array element.  */
     526        10912 :   offset_int eltsize = 1;
     527        10912 :   if (POINTER_TYPE_P (reftype))
     528          567 :     reftype = TREE_TYPE (reftype);
     529              : 
     530        10912 :   if (TREE_CODE (reftype) == FUNCTION_TYPE)
     531              :     /* Restore the original (pointer) type and avoid trying to create
     532              :        an array of functions (done below).  */
     533            9 :     reftype = TREE_TYPE (aref.ref);
     534              :   else
     535              :     {
     536              :       /* The byte size of the array has already been determined above
     537              :          based on a pointer ARG.  Set ELTSIZE to the size of the type
     538              :          it points to and REFTYPE to the array with the size, rounded
     539              :          down as necessary.  */
     540        10903 :       if (TREE_CODE (reftype) == ARRAY_TYPE)
     541        10076 :         reftype = TREE_TYPE (reftype);
     542        10903 :       if (tree refsize = TYPE_SIZE_UNIT (reftype))
     543        10630 :         if (TREE_CODE (refsize) == INTEGER_CST)
     544        10614 :           eltsize = wi::to_offset (refsize);
     545              : 
     546        10903 :       const offset_int nelts = aref.sizrng[1] / eltsize;
     547        10903 :       reftype = build_printable_array_type (reftype, nelts.to_uhwi ());
     548              :     }
     549              : 
     550              :   /* Compute the more permissive upper bound when IGNORE_OFF_BY_ONE
     551              :      is set (when taking the address of the one-past-last element
     552              :      of an array) but always use the stricter bound in diagnostics. */
     553        10912 :   offset_int ubound = aref.sizrng[1];
     554        10912 :   if (ignore_off_by_one)
     555         9747 :     ubound += eltsize;
     556              : 
     557              :   /* Set if the lower bound of the subscript is out of bounds.  */
     558        10912 :   const bool lboob = (aref.sizrng[1] == 0
     559        10687 :                       || offrange[0] >= ubound
     560        21250 :                       || offrange[1] < 0);
     561              :   /* Set if only the upper bound of the subscript is out of bounds.
     562              :      This can happen when using a bigger type to index into an array
     563              :      of a smaller type, as is common with unsigned char.  */
     564        10912 :   const bool uboob = !lboob && offrange[0] + axssize > ubound;
     565        10912 :   if (lboob || uboob)
     566              :     {
     567              :       /* Treat a reference to a non-array object as one to an array
     568              :          of a single element.  */
     569        10182 :       if (TREE_CODE (reftype) != ARRAY_TYPE)
     570            9 :         reftype = build_printable_array_type (reftype, 1);
     571              : 
     572              :       /* Extract the element type out of MEM_REF and use its size
     573              :          to compute the index to print in the diagnostic; arrays
     574              :          in MEM_REF don't mean anything.  A type with no size like
     575              :          void is as good as having a size of 1.  */
     576        10182 :       tree type = strip_array_types (TREE_TYPE (ref));
     577        10182 :       if (tree size = TYPE_SIZE_UNIT (type))
     578              :         {
     579        10181 :           offrange[0] = offrange[0] / wi::to_offset (size);
     580        10181 :           offrange[1] = offrange[1] / wi::to_offset (size);
     581              :         }
     582              :     }
     583              : 
     584        10912 :   rich_location_with_details richloc (location, stmt);
     585        10912 :   bool warned = false;
     586        10912 :   if (lboob)
     587              :     {
     588          768 :       if (offrange[0] == offrange[1])
     589          654 :         warned = warning_at (&richloc, OPT_Warray_bounds_,
     590              :                              "array subscript %wi is outside array bounds "
     591              :                              "of %qT",
     592              :                              offrange[0].to_shwi (), reftype);
     593              :       else
     594          114 :         warned = warning_at (&richloc, OPT_Warray_bounds_,
     595              :                              "array subscript [%wi, %wi] is outside "
     596              :                              "array bounds of %qT",
     597              :                              offrange[0].to_shwi (),
     598              :                              offrange[1].to_shwi (), reftype);
     599              :     }
     600        10144 :   else if (uboob && !ignore_off_by_one)
     601              :     {
     602          470 :       tree backtype = reftype;
     603          470 :       if (alloc_stmt)
     604              :         /* If the memory was dynamically allocated refer to it as if
     605              :            it were an untyped array of bytes.  */
     606          305 :         backtype = build_array_type_nelts (unsigned_char_type_node,
     607          305 :                                            aref.sizrng[1].to_uhwi ());
     608          470 :       warned = warning_at (&richloc, OPT_Warray_bounds_,
     609              :                            "array subscript %<%T[%wi]%> is partly "
     610              :                            "outside array bounds of %qT",
     611              :                            axstype, offrange[0].to_shwi (), backtype);
     612              :     }
     613              : 
     614         1238 :   if (warned)
     615              :     {
     616              :       /* TODO: Determine the access from the statement and use it.  */
     617         1233 :       aref.inform_access (access_none);
     618         1233 :       suppress_warning (ref, OPT_Warray_bounds_);
     619         1233 :       return true;
     620              :     }
     621              : 
     622         9679 :   if (warn_array_bounds < 2)
     623              :     return false;
     624              : 
     625              :   /* At level 2 check also intermediate offsets.  */
     626           20 :   int i = 0;
     627           20 :   if (aref.offmax[i] < -aref.sizrng[1] || aref.offmax[i = 1] > ubound)
     628              :     {
     629            4 :       HOST_WIDE_INT tmpidx = (aref.offmax[i] / eltsize).to_shwi ();
     630              : 
     631            4 :       if (warning_at (&richloc, OPT_Warray_bounds_,
     632              :                       "intermediate array offset %wi is outside array bounds "
     633              :                       "of %qT", tmpidx, reftype))
     634              :         {
     635            3 :           suppress_warning (ref, OPT_Warray_bounds_);
     636            3 :           return true;
     637              :         }
     638              :     }
     639              : 
     640              :   return false;
     641        10912 : }
     642              : 
     643              : /* Searches if the expr T, located at LOCATION computes
     644              :    address of an ARRAY_REF, and call check_array_ref on it.  */
     645              : 
     646              : void
     647       882050 : array_bounds_checker::check_addr_expr (location_t location, tree t,
     648              :                                        gimple *stmt)
     649              : {
     650              :   /* For the most significant subscript only, accept taking the address
     651              :      of the just-past-the-end element.  */
     652       882050 :   bool ignore_off_by_one = true;
     653              : 
     654              :   /* Check each ARRAY_REF and MEM_REF in the reference chain. */
     655      1034535 :   do
     656              :     {
     657      1034535 :       bool warned = false;
     658      1034535 :       if (TREE_CODE (t) == ARRAY_REF)
     659              :         {
     660        14584 :           warned = check_array_ref (location, t, stmt, ignore_off_by_one);
     661        14584 :           ignore_off_by_one = false;
     662              :         }
     663      1019951 :       else if (TREE_CODE (t) == MEM_REF)
     664        59521 :         warned = check_mem_ref (location, t, stmt, ignore_off_by_one);
     665              : 
     666        74105 :       if (warned)
     667          181 :         suppress_warning (t, OPT_Warray_bounds_);
     668              : 
     669      1034535 :       t = TREE_OPERAND (t, 0);
     670              :     }
     671      1187020 :   while (handled_component_p (t) || TREE_CODE (t) == MEM_REF);
     672              : 
     673       882050 :   if (TREE_CODE (t) != MEM_REF
     674            0 :       || TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR
     675       882050 :       || warning_suppressed_p (t, OPT_Warray_bounds_))
     676       882050 :     return;
     677              : 
     678            0 :   tree tem = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
     679            0 :   tree low_bound, up_bound, el_sz;
     680            0 :   if (TREE_CODE (TREE_TYPE (tem)) != ARRAY_TYPE
     681            0 :       || TREE_CODE (TREE_TYPE (TREE_TYPE (tem))) == ARRAY_TYPE
     682            0 :       || !TYPE_DOMAIN (TREE_TYPE (tem)))
     683              :     return;
     684              : 
     685            0 :   low_bound = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (tem)));
     686            0 :   up_bound = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (tem)));
     687            0 :   el_sz = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (tem)));
     688            0 :   if (!low_bound
     689            0 :       || TREE_CODE (low_bound) != INTEGER_CST
     690            0 :       || !up_bound
     691            0 :       || TREE_CODE (up_bound) != INTEGER_CST
     692            0 :       || !el_sz
     693            0 :       || TREE_CODE (el_sz) != INTEGER_CST)
     694              :     return;
     695              : 
     696            0 :   offset_int idx;
     697            0 :   if (!mem_ref_offset (t).is_constant (&idx))
     698              :     return;
     699              : 
     700            0 :   rich_location_with_details richloc (location, stmt);
     701            0 :   bool warned = false;
     702            0 :   idx = wi::sdiv_trunc (idx, wi::to_offset (el_sz));
     703            0 :   if (idx < 0)
     704              :     {
     705            0 :       if (dump_file && (dump_flags & TDF_DETAILS))
     706              :         {
     707            0 :           fprintf (dump_file, "Array bound warning for ");
     708            0 :           dump_generic_expr (MSG_NOTE, TDF_SLIM, t);
     709            0 :           fprintf (dump_file, "\n");
     710              :         }
     711            0 :       warned = warning_at (&richloc, OPT_Warray_bounds_,
     712              :                            "array subscript %wi is below "
     713              :                            "array bounds of %qT",
     714            0 :                            idx.to_shwi (), TREE_TYPE (tem));
     715              :     }
     716            0 :   else if (idx > (wi::to_offset (up_bound)
     717            0 :                   - wi::to_offset (low_bound) + 1))
     718              :     {
     719            0 :       if (dump_file && (dump_flags & TDF_DETAILS))
     720              :         {
     721            0 :           fprintf (dump_file, "Array bound warning for ");
     722            0 :           dump_generic_expr (MSG_NOTE, TDF_SLIM, t);
     723            0 :           fprintf (dump_file, "\n");
     724              :         }
     725            0 :       warned = warning_at (&richloc, OPT_Warray_bounds_,
     726              :                            "array subscript %wu is above "
     727              :                            "array bounds of %qT",
     728            0 :                            idx.to_uhwi (), TREE_TYPE (tem));
     729              :     }
     730              : 
     731            0 :   if (warned)
     732              :     {
     733            0 :       if (DECL_P (t))
     734            0 :         inform (DECL_SOURCE_LOCATION (t), "while referencing %qD", t);
     735              : 
     736            0 :       suppress_warning (t, OPT_Warray_bounds_);
     737              :     }
     738            0 : }
     739              : 
     740              : /* Return true if T is a reference to a member of a base class that's within
     741              :    the bounds of the enclosing complete object.  The function "hacks" around
     742              :    problems discussed in pr98266 and pr97595.  */
     743              : 
     744              : static bool
     745     10086275 : inbounds_memaccess_p (tree t, gimple *stmt)
     746              : {
     747     10086275 :   if (TREE_CODE (t) != COMPONENT_REF)
     748              :     return false;
     749              : 
     750       680936 :   tree mref = TREE_OPERAND (t, 0);
     751       680936 :   if (TREE_CODE (mref) != MEM_REF)
     752              :     return false;
     753              : 
     754              :   /* Consider the access if its type is a derived class.  */
     755       394910 :   tree mreftype = TREE_TYPE (mref);
     756       394910 :   if (!RECORD_OR_UNION_TYPE_P (mreftype)
     757       394910 :       || !TYPE_BINFO (mreftype))
     758              :     return false;
     759              : 
     760              :   /* Compute the size of the referenced object (it could be dynamically
     761              :      allocated).  */
     762       196045 :   access_ref aref;   // unused
     763       196045 :   tree refop = TREE_OPERAND (mref, 0);
     764       196045 :   tree refsize = compute_objsize (refop, stmt, 1, &aref);
     765       196045 :   if (!refsize || TREE_CODE (refsize) != INTEGER_CST)
     766              :     return false;
     767              : 
     768              :   /* Compute the byte offset of the member within its enclosing class.  */
     769       196045 :   tree fld = TREE_OPERAND (t, 1);
     770       196045 :   tree fldpos = byte_position (fld);
     771       196045 :   if (TREE_CODE (fldpos) != INTEGER_CST)
     772              :     return false;
     773              : 
     774              :   /* Compute the byte offset of the member with the outermost complete
     775              :      object by adding its offset computed above to the MEM_REF offset.  */
     776       196045 :   tree refoff = TREE_OPERAND (mref, 1);
     777       196045 :   tree fldoff = int_const_binop (PLUS_EXPR, fldpos, refoff);
     778              :   /* Return false if the member offset is greater or equal to the size
     779              :      of the complete object.  */
     780       196045 :   if (!tree_int_cst_lt (fldoff, refsize))
     781              :     return false;
     782              : 
     783       192924 :   tree fldsiz = DECL_SIZE_UNIT (fld);
     784       192924 :   if (!fldsiz || TREE_CODE (fldsiz) != INTEGER_CST)
     785              :     return false;
     786              : 
     787              :   /* Return true if the offset just past the end of the member is less
     788              :      than or equal to the size of the complete object.  */
     789       192768 :   tree fldend = int_const_binop (PLUS_EXPR, fldoff, fldsiz);
     790       192768 :   return tree_int_cst_le (fldend, refsize);
     791              : }
     792              : 
     793              : /* Callback for walk_tree to check a tree for out of bounds array
     794              :    accesses.  The array_bounds_checker class is passed in DATA.  */
     795              : 
     796              : tree
     797     11740215 : array_bounds_checker::check_array_bounds (tree *tp, int *walk_subtree,
     798              :                                           void *data)
     799              : {
     800     11740215 :   tree t = *tp;
     801     11740215 :   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
     802              : 
     803     11740215 :   location_t location;
     804              : 
     805     11740215 :   if (EXPR_HAS_LOCATION (t))
     806      1652369 :     location = EXPR_LOCATION (t);
     807              :   else
     808     10087846 :     location = gimple_location (wi->stmt);
     809              : 
     810     11740215 :   *walk_subtree = true;
     811              : 
     812     11740215 :   bool warned = false;
     813     11740215 :   array_bounds_checker *checker = (array_bounds_checker *) wi->info;
     814     11740215 :   gcc_assert (checker->m_stmt == wi->stmt);
     815              : 
     816     11740215 :   if (TREE_CODE (t) == ARRAY_REF)
     817       223569 :     warned = checker->check_array_ref (location, t, wi->stmt,
     818              :                                        false/*ignore_off_by_one*/);
     819     11516646 :   else if (TREE_CODE (t) == MEM_REF)
     820       548321 :     warned = checker->check_mem_ref (location, t, wi->stmt,
     821              :                                      false /*ignore_off_by_one*/);
     822     10968325 :   else if (TREE_CODE (t) == ADDR_EXPR)
     823              :     {
     824       882050 :       checker->check_addr_expr (location, t, wi->stmt);
     825       882050 :       *walk_subtree = false;
     826              :     }
     827     10086275 :   else if (inbounds_memaccess_p (t, wi->stmt))
     828              :     /* Hack: Skip MEM_REF checks in accesses to a member of a base class
     829              :        at an offset that's within the bounds of the enclosing object.
     830              :        See pr98266 and pr97595.  */
     831       192687 :     *walk_subtree = false;
     832              : 
     833              :   /* Propagate the no-warning bit to the outer statement to avoid also
     834              :      issuing -Wstringop-overflow/-overread for the out-of-bounds accesses.  */
     835      1846627 :   if (warned)
     836         2324 :     suppress_warning (wi->stmt, OPT_Warray_bounds_);
     837              : 
     838     11740215 :   return NULL_TREE;
     839              : }
     840              : 
     841              : /* A dom_walker subclass for use by check_all_array_refs, to walk over
     842              :    all statements of all reachable BBs and call check_array_bounds on
     843              :    them.  */
     844              : 
     845              : class check_array_bounds_dom_walker : public dom_walker
     846              : {
     847              : public:
     848       109180 :   check_array_bounds_dom_walker (array_bounds_checker *checker)
     849       109180 :     : dom_walker (CDI_DOMINATORS, REACHABLE_BLOCKS),
     850       218360 :     checker (checker) { }
     851       218360 :   ~check_array_bounds_dom_walker () {}
     852              : 
     853              :   edge before_dom_children (basic_block) final override;
     854              : 
     855              : private:
     856              :   array_bounds_checker *checker;
     857              : };
     858              : 
     859              : /* Implementation of dom_walker::before_dom_children.
     860              : 
     861              :    Walk over all statements of BB and call check_array_bounds on them,
     862              :    and determine if there's a unique successor edge.  */
     863              : 
     864              : edge
     865      1055547 : check_array_bounds_dom_walker::before_dom_children (basic_block bb)
     866              : {
     867      1055547 :   gimple_stmt_iterator si;
     868     10903734 :   for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
     869              :     {
     870      8792640 :       gimple *stmt = gsi_stmt (si);
     871      8792640 :       if (!gimple_has_location (stmt)
     872      8792640 :           || is_gimple_debug (stmt))
     873      5111324 :         continue;
     874              : 
     875      3681316 :       struct walk_stmt_info wi{ };
     876      3681316 :       wi.info = checker;
     877      3681316 :       checker->m_stmt = stmt;
     878              : 
     879      3681316 :       walk_gimple_op (stmt, array_bounds_checker::check_array_bounds, &wi);
     880              :     }
     881              : 
     882              :   /* Determine if there's a unique successor edge, and if so, return
     883              :      that back to dom_walker, ensuring that we don't visit blocks that
     884              :      became unreachable during the VRP propagation
     885              :      (PR tree-optimization/83312).  */
     886      1055547 :   return find_taken_edge (bb, NULL_TREE);
     887              : }
     888              : 
     889              : void
     890       109180 : array_bounds_checker::check ()
     891              : {
     892       109180 :   check_array_bounds_dom_walker w (this);
     893       109180 :   w.walk (ENTRY_BLOCK_PTR_FOR_FN (fun));
     894       109180 : }
     895              : 
     896              : const pass_data pass_data_array_bounds =
     897              : {
     898              :   GIMPLE_PASS, /* type */
     899              :   "bounds", /* name */
     900              :   OPTGROUP_NONE, /* optinfo_flags */
     901              :   TV_TREE_ARRAY_BOUNDS, /* tv_id */
     902              :   PROP_ssa, /* properties_required */
     903              :   0, /* properties_provided */
     904              :   0, /* properties_destroyed */
     905              :   0, /* todo_flags_start */
     906              :   ( 0 ),  /* No TODOs */
     907              : };
     908              : 
     909              : class pass_array_bounds : public gimple_opt_pass
     910              : {
     911              : public:
     912       285722 :   pass_array_bounds (gcc::context *ctxt, const pass_data &data_)
     913       571444 :     : gimple_opt_pass (data_, ctxt), data (data_)
     914              :     { }
     915              : 
     916              :   /* opt_pass methods: */
     917            0 :   opt_pass * clone () final override
     918            0 :     { return new pass_array_bounds (m_ctxt, data); }
     919      1041484 :   bool gate (function *) final override
     920              :     {
     921              :       // Gate on the VRP pass to preserve previous behavior.
     922      1041484 :       return flag_tree_vrp && (warn_array_bounds || warn_strict_flex_arrays);
     923              :     }
     924       109180 :   unsigned int execute (function *fun) final override
     925              :     {
     926       109180 :       calculate_dominance_info (CDI_DOMINATORS);
     927              :       // Enable ranger as the current range query.
     928       109180 :       enable_ranger (fun, false);
     929       109180 :       array_bounds_checker array_checker (fun);
     930       109180 :       array_checker.check ();
     931       109180 :       disable_ranger (fun);
     932       109180 :       return 0;
     933       109180 :     }
     934              : 
     935              :  private:
     936              :   const pass_data &data;
     937              : }; // class pass_array_bounds
     938              : 
     939              : gimple_opt_pass *
     940       285722 : make_pass_array_bounds (gcc::context *ctxt)
     941              : {
     942       285722 :   return new pass_array_bounds (ctxt, pass_data_array_bounds);
     943              : }
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.