1 /* Array bounds checking.
2    Copyright (C) 2005-2022 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 "intl.h"
35 #include "tree-vrp.h"
36 #include "alloc-pool.h"
37 #include "vr-values.h"
38 #include "domwalk.h"
39 #include "tree-cfg.h"
40 #include "attribs.h"
41 
array_bounds_checker(struct function * func,range_query * qry)42 array_bounds_checker::array_bounds_checker (struct function *func,
43 					    range_query *qry)
44   : fun (func), m_ptr_qry (qry)
45 {
46   /* No-op.  */
47 }
48 
49 // This purposely returns a value_range, not a value_range_equiv, to
50 // break the dependency on equivalences for this pass.
51 
52 const value_range *
get_value_range(const_tree op,gimple * stmt)53 array_bounds_checker::get_value_range (const_tree op, gimple *stmt)
54 {
55   return m_ptr_qry.rvals->get_value_range (op, stmt);
56 }
57 
58 /* Try to determine the DECL that REF refers to.  Return the DECL or
59    the expression closest to it.  Used in informational notes pointing
60    to referenced objects or function parameters.  */
61 
62 static tree
get_base_decl(tree ref)63 get_base_decl (tree ref)
64 {
65   tree base = get_base_address (ref);
66   if (DECL_P (base))
67     return base;
68 
69   if (TREE_CODE (base) == MEM_REF)
70     base = TREE_OPERAND (base, 0);
71 
72   if (TREE_CODE (base) != SSA_NAME)
73     return base;
74 
75   do
76     {
77       gimple *def = SSA_NAME_DEF_STMT (base);
78       if (gimple_assign_single_p (def))
79 	{
80 	  base = gimple_assign_rhs1 (def);
81 	  if (TREE_CODE (base) != ASSERT_EXPR)
82 	    return base;
83 
84 	  base = TREE_OPERAND (base, 0);
85 	  if (TREE_CODE (base) != SSA_NAME)
86 	    return base;
87 
88 	  continue;
89 	}
90 
91       if (!gimple_nop_p (def))
92 	return base;
93 
94       break;
95     } while (true);
96 
97   tree var = SSA_NAME_VAR (base);
98   if (TREE_CODE (var) != PARM_DECL)
99     return base;
100 
101   return var;
102 }
103 
104 /* Return the constant byte size of the object or type referenced by
105    the MEM_REF ARG.  On success, set *PREF to the DECL or expression
106    ARG refers to.  Otherwise return null.  */
107 
108 static tree
get_ref_size(tree arg,tree * pref)109 get_ref_size (tree arg, tree *pref)
110 {
111   if (TREE_CODE (arg) != MEM_REF)
112     return NULL_TREE;
113 
114   arg = TREE_OPERAND (arg, 0);
115   tree type = TREE_TYPE (arg);
116   if (!POINTER_TYPE_P (type))
117     return NULL_TREE;
118 
119   type = TREE_TYPE (type);
120   if (TREE_CODE (type) != ARRAY_TYPE)
121     return NULL_TREE;
122 
123   tree nbytes = TYPE_SIZE_UNIT (type);
124   if (!nbytes || TREE_CODE (nbytes) != INTEGER_CST)
125     return NULL_TREE;
126 
127   *pref = get_base_decl (arg);
128   return nbytes;
129 }
130 
131 /* Return true if REF is (likely) an ARRAY_REF to a trailing array member
132    of a struct.  It refines array_at_struct_end_p by detecting a pointer
133    to an array and an array parameter declared using the [N] syntax (as
134    opposed to a pointer) and returning false.  Set *PREF to the decl or
135    expression REF refers to.  */
136 
137 static bool
trailing_array(tree arg,tree * pref)138 trailing_array (tree arg, tree *pref)
139 {
140   tree ref = arg;
141   tree base = get_base_decl (arg);
142   while (TREE_CODE (ref) == ARRAY_REF || TREE_CODE (ref) == MEM_REF)
143     ref = TREE_OPERAND (ref, 0);
144 
145   if (TREE_CODE (ref) == COMPONENT_REF)
146     {
147       *pref = TREE_OPERAND (ref, 1);
148       tree type = TREE_TYPE (*pref);
149       if (TREE_CODE (type) == ARRAY_TYPE)
150 	{
151 	  /* A multidimensional trailing array is not considered special
152 	     no matter what its major bound is.  */
153 	  type = TREE_TYPE (type);
154 	  if (TREE_CODE (type) == ARRAY_TYPE)
155 	    return false;
156 	}
157     }
158   else
159     *pref = base;
160 
161   tree basetype = TREE_TYPE (base);
162   if (TREE_CODE (base) == PARM_DECL
163       && POINTER_TYPE_P (basetype))
164     {
165       tree ptype = TREE_TYPE (basetype);
166       if (TREE_CODE (ptype) == ARRAY_TYPE)
167 	return false;
168     }
169 
170   return array_at_struct_end_p (arg);
171 }
172 
173 /* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible
174    arrays and "struct" hacks. If VRP can determine that the array
175    subscript is a constant, check if it is outside valid range.  If
176    the array subscript is a RANGE, warn if it is non-overlapping with
177    valid range.  IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside
178    a ADDR_EXPR.  Return  true if a warning has been issued or if
179    no-warning is set.  */
180 
181 bool
check_array_ref(location_t location,tree ref,gimple * stmt,bool ignore_off_by_one)182 array_bounds_checker::check_array_ref (location_t location, tree ref,
183 				       gimple *stmt, bool ignore_off_by_one)
184 {
185   if (warning_suppressed_p (ref, OPT_Warray_bounds))
186     /* Return true to have the caller prevent warnings for enclosing
187        refs.  */
188     return true;
189 
190   tree low_sub = TREE_OPERAND (ref, 1);
191   tree up_sub = low_sub;
192   tree up_bound = array_ref_up_bound (ref);
193 
194   /* Referenced decl if one can be determined.  */
195   tree decl = NULL_TREE;
196 
197   /* Set for accesses to interior zero-length arrays.  */
198   special_array_member sam{ };
199 
200   tree up_bound_p1;
201 
202   if (!up_bound
203       || TREE_CODE (up_bound) != INTEGER_CST
204       || (warn_array_bounds < 2 && trailing_array (ref, &decl)))
205     {
206       /* Accesses to trailing arrays via pointers may access storage
207 	 beyond the types array bounds.  For such arrays, or for flexible
208 	 array members, as well as for other arrays of an unknown size,
209 	 replace the upper bound with a more permissive one that assumes
210 	 the size of the largest object is PTRDIFF_MAX.  */
211       tree eltsize = array_ref_element_size (ref);
212 
213       if (TREE_CODE (eltsize) != INTEGER_CST
214 	  || integer_zerop (eltsize))
215 	{
216 	  up_bound = NULL_TREE;
217 	  up_bound_p1 = NULL_TREE;
218 	}
219       else
220 	{
221 	  tree ptrdiff_max = TYPE_MAX_VALUE (ptrdiff_type_node);
222 	  tree maxbound = ptrdiff_max;
223 	  tree arg = TREE_OPERAND (ref, 0);
224 
225 	  const bool compref = TREE_CODE (arg) == COMPONENT_REF;
226 	  if (compref)
227 	    {
228 	      /* Try to determine the size of the trailing array from
229 		 its initializer (if it has one).  */
230 	      if (tree refsize = component_ref_size (arg, &sam))
231 		if (TREE_CODE (refsize) == INTEGER_CST)
232 		  maxbound = refsize;
233 	    }
234 
235 	  if (maxbound == ptrdiff_max)
236 	    {
237 	      /* Try to determine the size of the base object.  Avoid
238 		 COMPONENT_REF already tried above.  Using its DECL_SIZE
239 		 size wouldn't necessarily be correct if the reference is
240 		 to its flexible array member initialized in a different
241 		 translation unit.  */
242 	      poly_int64 off;
243 	      if (tree base = get_addr_base_and_unit_offset (arg, &off))
244 		{
245 		  if (TREE_CODE (base) == MEM_REF)
246 		    {
247 		      /* Try to determine the size from a pointer to
248 			 an array if BASE is one.  */
249 		      if (tree size = get_ref_size (base, &decl))
250 			maxbound = size;
251 		    }
252 		  else if (!compref && DECL_P (base))
253 		    if (tree basesize = DECL_SIZE_UNIT (base))
254 		      if (TREE_CODE (basesize) == INTEGER_CST)
255 			{
256 			  maxbound = basesize;
257 			  decl = base;
258 			}
259 
260 		  if (known_gt (off, 0))
261 		    maxbound = wide_int_to_tree (sizetype,
262 						 wi::sub (wi::to_wide (maxbound),
263 							  off));
264 		}
265 	    }
266 	  else
267 	    maxbound = fold_convert (sizetype, maxbound);
268 
269 	  up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
270 
271 	  if (up_bound_p1 != NULL_TREE)
272 	    up_bound = int_const_binop (MINUS_EXPR, up_bound_p1,
273 					build_int_cst (ptrdiff_type_node, 1));
274 	  else
275 	    up_bound = NULL_TREE;
276 	}
277     }
278   else
279     up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound,
280 				   build_int_cst (TREE_TYPE (up_bound), 1));
281 
282   tree low_bound = array_ref_low_bound (ref);
283 
284   tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
285 
286   bool warned = false;
287 
288   /* Empty array.  */
289   if (up_bound && tree_int_cst_equal (low_bound, up_bound_p1))
290     warned = warning_at (location, OPT_Warray_bounds,
291 			 "array subscript %E is outside array bounds of %qT",
292 			 low_sub, artype);
293 
294   const value_range *vr = NULL;
295   if (TREE_CODE (low_sub) == SSA_NAME)
296     {
297       vr = get_value_range (low_sub, stmt);
298       if (!vr->undefined_p () && !vr->varying_p ())
299 	{
300 	  low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
301 	  up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
302 	}
303     }
304 
305   if (warned)
306     ; /* Do nothing.  */
307   else if (vr && vr->kind () == VR_ANTI_RANGE)
308     {
309       if (up_bound
310 	  && TREE_CODE (up_sub) == INTEGER_CST
311 	  && (ignore_off_by_one
312 	      ? tree_int_cst_lt (up_bound, up_sub)
313 	      : tree_int_cst_le (up_bound, up_sub))
314 	  && TREE_CODE (low_sub) == INTEGER_CST
315 	  && tree_int_cst_le (low_sub, low_bound))
316 	warned = warning_at (location, OPT_Warray_bounds,
317 			     "array subscript [%E, %E] is outside "
318 			     "array bounds of %qT",
319 			     low_sub, up_sub, artype);
320     }
321   else if (up_bound
322 	   && TREE_CODE (up_sub) == INTEGER_CST
323 	   && (ignore_off_by_one
324 	       ? !tree_int_cst_le (up_sub, up_bound_p1)
325 	       : !tree_int_cst_le (up_sub, up_bound)))
326     warned = warning_at (location, OPT_Warray_bounds,
327 			 "array subscript %E is above array bounds of %qT",
328 			 up_sub, artype);
329   else if (TREE_CODE (low_sub) == INTEGER_CST
330 	   && tree_int_cst_lt (low_sub, low_bound))
331     warned = warning_at (location, OPT_Warray_bounds,
332 			 "array subscript %E is below array bounds of %qT",
333 			 low_sub, artype);
334 
335   if (!warned && sam == special_array_member::int_0)
336     warned = warning_at (location, OPT_Wzero_length_bounds,
337 			 (TREE_CODE (low_sub) == INTEGER_CST
338 			  ? G_("array subscript %E is outside the bounds "
339 			       "of an interior zero-length array %qT")
340 			  : G_("array subscript %qE is outside the bounds "
341 			       "of an interior zero-length array %qT")),
342 			 low_sub, artype);
343 
344   if (warned)
345     {
346       if (dump_file && (dump_flags & TDF_DETAILS))
347 	{
348 	  fprintf (dump_file, "Array bound warning for ");
349 	  dump_generic_expr (MSG_NOTE, TDF_SLIM, ref);
350 	  fprintf (dump_file, "\n");
351 	}
352 
353       /* Avoid more warnings when checking more significant subscripts
354 	 of the same expression.  */
355       ref = TREE_OPERAND (ref, 0);
356       suppress_warning (ref, OPT_Warray_bounds);
357 
358       if (decl)
359 	ref = decl;
360 
361       tree rec = NULL_TREE;
362       if (TREE_CODE (ref) == COMPONENT_REF)
363 	{
364 	  /* For a reference to a member of a struct object also mention
365 	     the object if it's known.  It may be defined in a different
366 	     function than the out-of-bounds access.  */
367 	  rec = TREE_OPERAND (ref, 0);
368 	  if (!VAR_P (rec))
369 	    rec = NULL_TREE;
370 	  ref = TREE_OPERAND (ref, 1);
371 	}
372 
373       if (DECL_P (ref))
374 	inform (DECL_SOURCE_LOCATION (ref), "while referencing %qD", ref);
375       if (rec && DECL_P (rec))
376 	inform (DECL_SOURCE_LOCATION (rec), "defined here %qD", rec);
377     }
378 
379   return warned;
380 }
381 
382 /* Checks one MEM_REF in REF, located at LOCATION, for out-of-bounds
383    references to string constants.  If VRP can determine that the array
384    subscript is a constant, check if it is outside valid range.
385    If the array subscript is a RANGE, warn if it is non-overlapping
386    with valid range.
387    IGNORE_OFF_BY_ONE is true if the MEM_REF is inside an ADDR_EXPR
388    (used to allow one-past-the-end indices for code that takes
389    the address of the just-past-the-end element of an array).
390    Returns true if a warning has been issued.  */
391 
392 bool
check_mem_ref(location_t location,tree ref,bool ignore_off_by_one)393 array_bounds_checker::check_mem_ref (location_t location, tree ref,
394 				     bool ignore_off_by_one)
395 {
396   if (warning_suppressed_p (ref, OPT_Warray_bounds))
397     return false;
398 
399   /* The statement used to allocate the array or null.  */
400   gimple *alloc_stmt = NULL;
401   /* For an allocation statement, the low bound of the size range.  */
402   offset_int minbound = 0;
403   /* The type and size of the access.  */
404   tree axstype = TREE_TYPE (ref);
405   offset_int axssize = 0;
406   if (tree access_size = TYPE_SIZE_UNIT (axstype))
407     if (TREE_CODE (access_size) == INTEGER_CST)
408       axssize = wi::to_offset (access_size);
409 
410   access_ref aref;
411   if (!m_ptr_qry.get_ref (ref, m_stmt, &aref, 0))
412     return false;
413 
414   if (aref.offset_in_range (axssize))
415     return false;
416 
417   if (TREE_CODE (aref.ref) == SSA_NAME)
418     {
419       gimple *def = SSA_NAME_DEF_STMT (aref.ref);
420       if (is_gimple_call (def))
421 	{
422 	  /* Save the allocation call and the low bound on the size.  */
423 	  alloc_stmt = def;
424 	  minbound = aref.sizrng[0];
425 	}
426     }
427 
428   /* The range of the byte offset into the reference.  Adjusted below.  */
429   offset_int offrange[2] = { aref.offrng[0], aref.offrng[1] };
430 
431   /* The type of the referenced object.  */
432   tree reftype = TREE_TYPE (aref.ref);
433   /* The size of the referenced array element.  */
434   offset_int eltsize = 1;
435   if (POINTER_TYPE_P (reftype))
436     reftype = TREE_TYPE (reftype);
437 
438   if (TREE_CODE (reftype) == FUNCTION_TYPE)
439     /* Restore the original (pointer) type and avoid trying to create
440        an array of functions (done below).  */
441     reftype = TREE_TYPE (aref.ref);
442   else
443     {
444       /* The byte size of the array has already been determined above
445 	 based on a pointer ARG.  Set ELTSIZE to the size of the type
446 	 it points to and REFTYPE to the array with the size, rounded
447 	 down as necessary.  */
448       if (TREE_CODE (reftype) == ARRAY_TYPE)
449 	reftype = TREE_TYPE (reftype);
450       if (tree refsize = TYPE_SIZE_UNIT (reftype))
451 	if (TREE_CODE (refsize) == INTEGER_CST)
452 	  eltsize = wi::to_offset (refsize);
453 
454       const offset_int nelts = aref.sizrng[1] / eltsize;
455       reftype = build_printable_array_type (reftype, nelts.to_uhwi ());
456     }
457 
458   /* Compute the more permissive upper bound when IGNORE_OFF_BY_ONE
459      is set (when taking the address of the one-past-last element
460      of an array) but always use the stricter bound in diagnostics. */
461   offset_int ubound = aref.sizrng[1];
462   if (ignore_off_by_one)
463     ubound += eltsize;
464 
465   /* Set if the lower bound of the subscript is out of bounds.  */
466   const bool lboob = (aref.sizrng[1] == 0
467 		      || offrange[0] >= ubound
468 		      || offrange[1] < 0);
469   /* Set if only the upper bound of the subscript is out of bounds.
470      This can happen when using a bigger type to index into an array
471      of a smaller type, as is common with unsigned char.  */
472   const bool uboob = !lboob && offrange[0] + axssize > ubound;
473   if (lboob || uboob)
474     {
475       /* Treat a reference to a non-array object as one to an array
476 	 of a single element.  */
477       if (TREE_CODE (reftype) != ARRAY_TYPE)
478 	reftype = build_printable_array_type (reftype, 1);
479 
480       /* Extract the element type out of MEM_REF and use its size
481 	 to compute the index to print in the diagnostic; arrays
482 	 in MEM_REF don't mean anything.  A type with no size like
483 	 void is as good as having a size of 1.  */
484       tree type = strip_array_types (TREE_TYPE (ref));
485       if (tree size = TYPE_SIZE_UNIT (type))
486 	{
487 	  offrange[0] = offrange[0] / wi::to_offset (size);
488 	  offrange[1] = offrange[1] / wi::to_offset (size);
489 	}
490     }
491 
492   bool warned = false;
493   if (lboob)
494     {
495       if (offrange[0] == offrange[1])
496 	warned = warning_at (location, OPT_Warray_bounds,
497 			     "array subscript %wi is outside array bounds "
498 			     "of %qT",
499 			     offrange[0].to_shwi (), reftype);
500       else
501 	warned = warning_at (location, OPT_Warray_bounds,
502 			     "array subscript [%wi, %wi] is outside "
503 			     "array bounds of %qT",
504 			     offrange[0].to_shwi (),
505 			     offrange[1].to_shwi (), reftype);
506     }
507   else if (uboob && !ignore_off_by_one)
508     {
509       tree backtype = reftype;
510       if (alloc_stmt)
511 	/* If the memory was dynamically allocated refer to it as if
512 	   it were an untyped array of bytes.  */
513 	backtype = build_array_type_nelts (unsigned_char_type_node,
514 					   aref.sizrng[1].to_uhwi ());
515 
516       warned = warning_at (location, OPT_Warray_bounds,
517 			   "array subscript %<%T[%wi]%> is partly "
518 			   "outside array bounds of %qT",
519 			   axstype, offrange[0].to_shwi (), backtype);
520     }
521 
522   if (warned)
523     {
524       /* TODO: Determine the access from the statement and use it.  */
525       aref.inform_access (access_none);
526       suppress_warning (ref, OPT_Warray_bounds);
527       return true;
528     }
529 
530   if (warn_array_bounds < 2)
531     return false;
532 
533   /* At level 2 check also intermediate offsets.  */
534   int i = 0;
535   if (aref.offmax[i] < -aref.sizrng[1] || aref.offmax[i = 1] > ubound)
536     {
537       HOST_WIDE_INT tmpidx = (aref.offmax[i] / eltsize).to_shwi ();
538 
539       if (warning_at (location, OPT_Warray_bounds,
540 		      "intermediate array offset %wi is outside array bounds "
541 		      "of %qT", tmpidx, reftype))
542 	{
543 	  suppress_warning (ref, OPT_Warray_bounds);
544 	  return true;
545 	}
546     }
547 
548   return false;
549 }
550 
551 /* Searches if the expr T, located at LOCATION computes
552    address of an ARRAY_REF, and call check_array_ref on it.  */
553 
554 void
check_addr_expr(location_t location,tree t,gimple * stmt)555 array_bounds_checker::check_addr_expr (location_t location, tree t,
556 				       gimple *stmt)
557 {
558   /* For the most significant subscript only, accept taking the address
559      of the just-past-the-end element.  */
560   bool ignore_off_by_one = true;
561 
562   /* Check each ARRAY_REF and MEM_REF in the reference chain. */
563   do
564     {
565       bool warned = false;
566       if (TREE_CODE (t) == ARRAY_REF)
567 	{
568 	  warned = check_array_ref (location, t, stmt, ignore_off_by_one);
569 	  ignore_off_by_one = false;
570 	}
571       else if (TREE_CODE (t) == MEM_REF)
572 	warned = check_mem_ref (location, t, ignore_off_by_one);
573 
574       if (warned)
575 	suppress_warning (t, OPT_Warray_bounds);
576 
577       t = TREE_OPERAND (t, 0);
578     }
579   while (handled_component_p (t) || TREE_CODE (t) == MEM_REF);
580 
581   if (TREE_CODE (t) != MEM_REF
582       || TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR
583       || warning_suppressed_p (t, OPT_Warray_bounds))
584     return;
585 
586   tree tem = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
587   tree low_bound, up_bound, el_sz;
588   if (TREE_CODE (TREE_TYPE (tem)) != ARRAY_TYPE
589       || TREE_CODE (TREE_TYPE (TREE_TYPE (tem))) == ARRAY_TYPE
590       || !TYPE_DOMAIN (TREE_TYPE (tem)))
591     return;
592 
593   low_bound = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (tem)));
594   up_bound = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (tem)));
595   el_sz = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (tem)));
596   if (!low_bound
597       || TREE_CODE (low_bound) != INTEGER_CST
598       || !up_bound
599       || TREE_CODE (up_bound) != INTEGER_CST
600       || !el_sz
601       || TREE_CODE (el_sz) != INTEGER_CST)
602     return;
603 
604   offset_int idx;
605   if (!mem_ref_offset (t).is_constant (&idx))
606     return;
607 
608   bool warned = false;
609   idx = wi::sdiv_trunc (idx, wi::to_offset (el_sz));
610   if (idx < 0)
611     {
612       if (dump_file && (dump_flags & TDF_DETAILS))
613 	{
614 	  fprintf (dump_file, "Array bound warning for ");
615 	  dump_generic_expr (MSG_NOTE, TDF_SLIM, t);
616 	  fprintf (dump_file, "\n");
617 	}
618       warned = warning_at (location, OPT_Warray_bounds,
619 			   "array subscript %wi is below "
620 			   "array bounds of %qT",
621 			   idx.to_shwi (), TREE_TYPE (tem));
622     }
623   else if (idx > (wi::to_offset (up_bound)
624 		  - wi::to_offset (low_bound) + 1))
625     {
626       if (dump_file && (dump_flags & TDF_DETAILS))
627 	{
628 	  fprintf (dump_file, "Array bound warning for ");
629 	  dump_generic_expr (MSG_NOTE, TDF_SLIM, t);
630 	  fprintf (dump_file, "\n");
631 	}
632       warned = warning_at (location, OPT_Warray_bounds,
633 			   "array subscript %wu is above "
634 			   "array bounds of %qT",
635 			   idx.to_uhwi (), TREE_TYPE (tem));
636     }
637 
638   if (warned)
639     {
640       if (DECL_P (t))
641 	inform (DECL_SOURCE_LOCATION (t), "while referencing %qD", t);
642 
643       suppress_warning (t, OPT_Warray_bounds);
644     }
645 }
646 
647 /* Return true if T is a reference to a member of a base class that's within
648    the bounds of the enclosing complete object.  The function "hacks" around
649    problems discussed in pr98266 and pr97595.  */
650 
651 static bool
inbounds_memaccess_p(tree t,gimple * stmt)652 inbounds_memaccess_p (tree t, gimple *stmt)
653 {
654   if (TREE_CODE (t) != COMPONENT_REF)
655     return false;
656 
657   tree mref = TREE_OPERAND (t, 0);
658   if (TREE_CODE (mref) != MEM_REF)
659     return false;
660 
661   /* Consider the access if its type is a derived class.  */
662   tree mreftype = TREE_TYPE (mref);
663   if (!RECORD_OR_UNION_TYPE_P (mreftype)
664       || !TYPE_BINFO (mreftype))
665     return false;
666 
667   /* Compute the size of the referenced object (it could be dynamically
668      allocated).  */
669   access_ref aref;   // unused
670   tree refop = TREE_OPERAND (mref, 0);
671   tree refsize = compute_objsize (refop, stmt, 1, &aref);
672   if (!refsize || TREE_CODE (refsize) != INTEGER_CST)
673     return false;
674 
675   /* Compute the byte offset of the member within its enclosing class.  */
676   tree fld = TREE_OPERAND (t, 1);
677   tree fldpos = byte_position (fld);
678   if (TREE_CODE (fldpos) != INTEGER_CST)
679     return false;
680 
681   /* Compute the byte offset of the member with the outermost complete
682      object by adding its offset computed above to the MEM_REF offset.  */
683   tree refoff = TREE_OPERAND (mref, 1);
684   tree fldoff = int_const_binop (PLUS_EXPR, fldpos, refoff);
685   /* Return false if the member offset is greater or equal to the size
686      of the complete object.  */
687   if (!tree_int_cst_lt (fldoff, refsize))
688     return false;
689 
690   tree fldsiz = DECL_SIZE_UNIT (fld);
691   if (!fldsiz || TREE_CODE (fldsiz) != INTEGER_CST)
692     return false;
693 
694   /* Return true if the offset just past the end of the member is less
695      than or equal to the size of the complete object.  */
696   tree fldend = int_const_binop (PLUS_EXPR, fldoff, fldsiz);
697   return tree_int_cst_le (fldend, refsize);
698 }
699 
700 /* Callback for walk_tree to check a tree for out of bounds array
701    accesses.  The array_bounds_checker class is passed in DATA.  */
702 
703 tree
check_array_bounds(tree * tp,int * walk_subtree,void * data)704 array_bounds_checker::check_array_bounds (tree *tp, int *walk_subtree,
705 					  void *data)
706 {
707   tree t = *tp;
708   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
709 
710   location_t location;
711 
712   if (EXPR_HAS_LOCATION (t))
713     location = EXPR_LOCATION (t);
714   else
715     location = gimple_location (wi->stmt);
716 
717   *walk_subtree = TRUE;
718 
719   bool warned = false;
720   array_bounds_checker *checker = (array_bounds_checker *) wi->info;
721   gcc_assert (checker->m_stmt == wi->stmt);
722 
723   if (TREE_CODE (t) == ARRAY_REF)
724     warned = checker->check_array_ref (location, t, wi->stmt,
725 				       false/*ignore_off_by_one*/);
726   else if (TREE_CODE (t) == MEM_REF)
727     warned = checker->check_mem_ref (location, t,
728 				     false /*ignore_off_by_one*/);
729   else if (TREE_CODE (t) == ADDR_EXPR)
730     {
731       checker->check_addr_expr (location, t, wi->stmt);
732       *walk_subtree = false;
733     }
734   else if (inbounds_memaccess_p (t, wi->stmt))
735     /* Hack: Skip MEM_REF checks in accesses to a member of a base class
736        at an offset that's within the bounds of the enclosing object.
737        See pr98266 and pr97595.  */
738     *walk_subtree = false;
739 
740   /* Propagate the no-warning bit to the outer statement to avoid also
741      issuing -Wstringop-overflow/-overread for the out-of-bounds accesses.  */
742   if (warned)
743     suppress_warning (wi->stmt, OPT_Warray_bounds);
744 
745   return NULL_TREE;
746 }
747 
748 /* A dom_walker subclass for use by check_all_array_refs, to walk over
749    all statements of all reachable BBs and call check_array_bounds on
750    them.  */
751 
752 class check_array_bounds_dom_walker : public dom_walker
753 {
754 public:
check_array_bounds_dom_walker(array_bounds_checker * checker)755   check_array_bounds_dom_walker (array_bounds_checker *checker)
756     : dom_walker (CDI_DOMINATORS,
757 		  /* Discover non-executable edges, preserving EDGE_EXECUTABLE
758 		     flags, so that we can merge in information on
759 		     non-executable edges from vrp_folder .  */
760 		  REACHABLE_BLOCKS_PRESERVING_FLAGS),
761     checker (checker) { }
~check_array_bounds_dom_walker()762   ~check_array_bounds_dom_walker () {}
763 
764   edge before_dom_children (basic_block) FINAL OVERRIDE;
765 
766 private:
767   array_bounds_checker *checker;
768 };
769 
770 /* Implementation of dom_walker::before_dom_children.
771 
772    Walk over all statements of BB and call check_array_bounds on them,
773    and determine if there's a unique successor edge.  */
774 
775 edge
before_dom_children(basic_block bb)776 check_array_bounds_dom_walker::before_dom_children (basic_block bb)
777 {
778   gimple_stmt_iterator si;
779   for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
780     {
781       gimple *stmt = gsi_stmt (si);
782       if (!gimple_has_location (stmt)
783 	  || is_gimple_debug (stmt))
784 	continue;
785 
786       struct walk_stmt_info wi{ };
787       wi.info = checker;
788       checker->m_stmt = stmt;
789 
790       walk_gimple_op (stmt, array_bounds_checker::check_array_bounds, &wi);
791     }
792 
793   /* Determine if there's a unique successor edge, and if so, return
794      that back to dom_walker, ensuring that we don't visit blocks that
795      became unreachable during the VRP propagation
796      (PR tree-optimization/83312).  */
797   return find_taken_edge (bb, NULL_TREE);
798 }
799 
800 void
check()801 array_bounds_checker::check ()
802 {
803   check_array_bounds_dom_walker w (this);
804   w.walk (ENTRY_BLOCK_PTR_FOR_FN (fun));
805 }
806