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 : }
|