]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/gimple-array-bounds.cc
[Ada] Remove Determine_License
[thirdparty/gcc.git] / gcc / gimple-array-bounds.cc
CommitLineData
62efd1c4
AH
1/* Array bounds checking.
2 Copyright (C) 2005-2020 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 3, or (at your option)
9any later version.
10
11GCC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along 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 "gimple-array-bounds.h"
28#include "gimple-iterator.h"
29#include "gimple-walk.h"
30#include "tree-dfa.h"
31#include "fold-const.h"
32#include "diagnostic-core.h"
33#include "intl.h"
34#include "tree-vrp.h"
35#include "alloc-pool.h"
36#include "vr-values.h"
37#include "domwalk.h"
38#include "tree-cfg.h"
39
40// This purposely returns a value_range, not a value_range_equiv, to
41// break the dependency on equivalences for this pass.
42
43const value_range *
44array_bounds_checker::get_value_range (const_tree op)
45{
46 return ranges->get_value_range (op);
47}
48
49/* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible
50 arrays and "struct" hacks. If VRP can determine that the array
51 subscript is a constant, check if it is outside valid range. If
52 the array subscript is a RANGE, warn if it is non-overlapping with
53 valid range. IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside
54 a ADDR_EXPR. Returns true if a warning has been issued. */
55
56bool
57array_bounds_checker::check_array_ref (location_t location, tree ref,
58 bool ignore_off_by_one)
59{
60 if (TREE_NO_WARNING (ref))
61 return false;
62
63 tree low_sub = TREE_OPERAND (ref, 1);
64 tree up_sub = low_sub;
65 tree up_bound = array_ref_up_bound (ref);
66
67 /* Referenced decl if one can be determined. */
68 tree decl = NULL_TREE;
69
70 /* Set for accesses to interior zero-length arrays. */
71 bool interior_zero_len = false;
72
73 tree up_bound_p1;
74
75 if (!up_bound
76 || TREE_CODE (up_bound) != INTEGER_CST
77 || (warn_array_bounds < 2
78 && array_at_struct_end_p (ref)))
79 {
80 /* Accesses to trailing arrays via pointers may access storage
81 beyond the types array bounds. For such arrays, or for flexible
82 array members, as well as for other arrays of an unknown size,
83 replace the upper bound with a more permissive one that assumes
84 the size of the largest object is PTRDIFF_MAX. */
85 tree eltsize = array_ref_element_size (ref);
86
87 if (TREE_CODE (eltsize) != INTEGER_CST
88 || integer_zerop (eltsize))
89 {
90 up_bound = NULL_TREE;
91 up_bound_p1 = NULL_TREE;
92 }
93 else
94 {
95 tree ptrdiff_max = TYPE_MAX_VALUE (ptrdiff_type_node);
96 tree maxbound = ptrdiff_max;
97 tree arg = TREE_OPERAND (ref, 0);
98
99 const bool compref = TREE_CODE (arg) == COMPONENT_REF;
100 if (compref)
101 {
102 /* Try to determine the size of the trailing array from
103 its initializer (if it has one). */
104 if (tree refsize = component_ref_size (arg, &interior_zero_len))
105 if (TREE_CODE (refsize) == INTEGER_CST)
106 maxbound = refsize;
107 }
108
109 if (maxbound == ptrdiff_max)
110 {
111 /* Try to determine the size of the base object. Avoid
112 COMPONENT_REF already tried above. Using its DECL_SIZE
113 size wouldn't necessarily be correct if the reference is
114 to its flexible array member initialized in a different
115 translation unit. */
116 poly_int64 off;
117 if (tree base = get_addr_base_and_unit_offset (arg, &off))
118 {
119 if (!compref && DECL_P (base))
120 if (tree basesize = DECL_SIZE_UNIT (base))
121 if (TREE_CODE (basesize) == INTEGER_CST)
122 {
123 maxbound = basesize;
124 decl = base;
125 }
126
127 if (known_gt (off, 0))
128 maxbound = wide_int_to_tree (sizetype,
129 wi::sub (wi::to_wide (maxbound),
130 off));
131 }
132 }
133 else
134 maxbound = fold_convert (sizetype, maxbound);
135
136 up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
137
138 if (up_bound_p1 != NULL_TREE)
139 up_bound = int_const_binop (MINUS_EXPR, up_bound_p1,
140 build_int_cst (ptrdiff_type_node, 1));
141 else
142 up_bound = NULL_TREE;
143 }
144 }
145 else
146 up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound,
147 build_int_cst (TREE_TYPE (up_bound), 1));
148
149 tree low_bound = array_ref_low_bound (ref);
150
151 tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
152
153 bool warned = false;
154
155 /* Empty array. */
156 if (up_bound && tree_int_cst_equal (low_bound, up_bound_p1))
157 warned = warning_at (location, OPT_Warray_bounds,
158 "array subscript %E is outside array bounds of %qT",
159 low_sub, artype);
160
161 const value_range *vr = NULL;
162 if (TREE_CODE (low_sub) == SSA_NAME)
163 {
164 vr = get_value_range (low_sub);
165 if (!vr->undefined_p () && !vr->varying_p ())
166 {
167 low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
168 up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
169 }
170 }
171
172 if (warned)
173 ; /* Do nothing. */
174 else if (vr && vr->kind () == VR_ANTI_RANGE)
175 {
176 if (up_bound
177 && TREE_CODE (up_sub) == INTEGER_CST
178 && (ignore_off_by_one
179 ? tree_int_cst_lt (up_bound, up_sub)
180 : tree_int_cst_le (up_bound, up_sub))
181 && TREE_CODE (low_sub) == INTEGER_CST
182 && tree_int_cst_le (low_sub, low_bound))
183 warned = warning_at (location, OPT_Warray_bounds,
184 "array subscript [%E, %E] is outside "
185 "array bounds of %qT",
186 low_sub, up_sub, artype);
187 }
188 else if (up_bound
189 && TREE_CODE (up_sub) == INTEGER_CST
190 && (ignore_off_by_one
191 ? !tree_int_cst_le (up_sub, up_bound_p1)
192 : !tree_int_cst_le (up_sub, up_bound)))
193 warned = warning_at (location, OPT_Warray_bounds,
194 "array subscript %E is above array bounds of %qT",
195 up_sub, artype);
196 else if (TREE_CODE (low_sub) == INTEGER_CST
197 && tree_int_cst_lt (low_sub, low_bound))
198 warned = warning_at (location, OPT_Warray_bounds,
199 "array subscript %E is below array bounds of %qT",
200 low_sub, artype);
201
202 if (!warned && interior_zero_len)
203 warned = warning_at (location, OPT_Wzero_length_bounds,
204 (TREE_CODE (low_sub) == INTEGER_CST
205 ? G_("array subscript %E is outside the bounds "
206 "of an interior zero-length array %qT")
207 : G_("array subscript %qE is outside the bounds "
208 "of an interior zero-length array %qT")),
209 low_sub, artype);
210
211 if (warned)
212 {
213 if (dump_file && (dump_flags & TDF_DETAILS))
214 {
215 fprintf (dump_file, "Array bound warning for ");
216 dump_generic_expr (MSG_NOTE, TDF_SLIM, ref);
217 fprintf (dump_file, "\n");
218 }
219
220 ref = decl ? decl : TREE_OPERAND (ref, 0);
221
222 tree rec = NULL_TREE;
223 if (TREE_CODE (ref) == COMPONENT_REF)
224 {
225 /* For a reference to a member of a struct object also mention
226 the object if it's known. It may be defined in a different
227 function than the out-of-bounds access. */
228 rec = TREE_OPERAND (ref, 0);
229 if (!VAR_P (rec))
230 rec = NULL_TREE;
231 ref = TREE_OPERAND (ref, 1);
232 }
233
234 if (DECL_P (ref))
235 inform (DECL_SOURCE_LOCATION (ref), "while referencing %qD", ref);
236 if (rec && DECL_P (rec))
237 inform (DECL_SOURCE_LOCATION (rec), "defined here %qD", rec);
238
239 TREE_NO_WARNING (ref) = 1;
240 }
241
242 return warned;
243}
244
245/* Checks one MEM_REF in REF, located at LOCATION, for out-of-bounds
246 references to string constants. If VRP can determine that the array
247 subscript is a constant, check if it is outside valid range.
248 If the array subscript is a RANGE, warn if it is non-overlapping
249 with valid range.
250 IGNORE_OFF_BY_ONE is true if the MEM_REF is inside an ADDR_EXPR
251 (used to allow one-past-the-end indices for code that takes
252 the address of the just-past-the-end element of an array).
253 Returns true if a warning has been issued. */
254
255bool
256array_bounds_checker::check_mem_ref (location_t location, tree ref,
257 bool ignore_off_by_one)
258{
259 if (TREE_NO_WARNING (ref))
260 return false;
261
262 tree arg = TREE_OPERAND (ref, 0);
263 /* The constant and variable offset of the reference. */
264 tree cstoff = TREE_OPERAND (ref, 1);
265 tree varoff = NULL_TREE;
266
267 const offset_int maxobjsize = tree_to_shwi (max_object_size ());
268
269 /* The array or string constant bounds in bytes. Initially set
270 to [-MAXOBJSIZE - 1, MAXOBJSIZE] until a tighter bound is
271 determined. */
272 offset_int arrbounds[2] = { -maxobjsize - 1, maxobjsize };
273
274 /* The minimum and maximum intermediate offset. For a reference
275 to be valid, not only does the final offset/subscript must be
276 in bounds but all intermediate offsets should be as well.
277 GCC may be able to deal gracefully with such out-of-bounds
278 offsets so the checking is only enbaled at -Warray-bounds=2
279 where it may help detect bugs in uses of the intermediate
280 offsets that could otherwise not be detectable. */
281 offset_int ioff = wi::to_offset (fold_convert (ptrdiff_type_node, cstoff));
282 offset_int extrema[2] = { 0, wi::abs (ioff) };
283
284 /* The range of the byte offset into the reference. */
285 offset_int offrange[2] = { 0, 0 };
286
287 const value_range *vr = NULL;
288
289 /* Determine the offsets and increment OFFRANGE for the bounds of each.
290 The loop computes the range of the final offset for expressions such
291 as (A + i0 + ... + iN)[CSTOFF] where i0 through iN are SSA_NAMEs in
292 some range. */
293 const unsigned limit = param_ssa_name_def_chain_limit;
294 for (unsigned n = 0; TREE_CODE (arg) == SSA_NAME && n < limit; ++n)
295 {
296 gimple *def = SSA_NAME_DEF_STMT (arg);
297 if (!is_gimple_assign (def))
298 break;
299
300 tree_code code = gimple_assign_rhs_code (def);
301 if (code == POINTER_PLUS_EXPR)
302 {
303 arg = gimple_assign_rhs1 (def);
304 varoff = gimple_assign_rhs2 (def);
305 }
306 else if (code == ASSERT_EXPR)
307 {
308 arg = TREE_OPERAND (gimple_assign_rhs1 (def), 0);
309 continue;
310 }
311 else
312 return false;
313
314 /* VAROFF should always be a SSA_NAME here (and not even
315 INTEGER_CST) but there's no point in taking chances. */
316 if (TREE_CODE (varoff) != SSA_NAME)
317 break;
318
319 vr = get_value_range (varoff);
320 if (!vr || vr->undefined_p () || vr->varying_p ())
321 break;
322
323 if (!vr->constant_p ())
324 break;
325
326 if (vr->kind () == VR_RANGE)
327 {
328 offset_int min
329 = wi::to_offset (fold_convert (ptrdiff_type_node, vr->min ()));
330 offset_int max
331 = wi::to_offset (fold_convert (ptrdiff_type_node, vr->max ()));
332 if (min < max)
333 {
334 offrange[0] += min;
335 offrange[1] += max;
336 }
337 else
338 {
339 /* When MIN >= MAX, the offset is effectively in a union
340 of two ranges: [-MAXOBJSIZE -1, MAX] and [MIN, MAXOBJSIZE].
341 Since there is no way to represent such a range across
342 additions, conservatively add [-MAXOBJSIZE -1, MAXOBJSIZE]
343 to OFFRANGE. */
344 offrange[0] += arrbounds[0];
345 offrange[1] += arrbounds[1];
346 }
347 }
348 else
349 {
350 /* For an anti-range, analogously to the above, conservatively
351 add [-MAXOBJSIZE -1, MAXOBJSIZE] to OFFRANGE. */
352 offrange[0] += arrbounds[0];
353 offrange[1] += arrbounds[1];
354 }
355
356 /* Keep track of the minimum and maximum offset. */
357 if (offrange[1] < 0 && offrange[1] < extrema[0])
358 extrema[0] = offrange[1];
359 if (offrange[0] > 0 && offrange[0] > extrema[1])
360 extrema[1] = offrange[0];
361
362 if (offrange[0] < arrbounds[0])
363 offrange[0] = arrbounds[0];
364
365 if (offrange[1] > arrbounds[1])
366 offrange[1] = arrbounds[1];
367 }
368
369 if (TREE_CODE (arg) == ADDR_EXPR)
370 {
371 arg = TREE_OPERAND (arg, 0);
372 if (TREE_CODE (arg) != STRING_CST
373 && TREE_CODE (arg) != PARM_DECL
374 && TREE_CODE (arg) != VAR_DECL)
375 return false;
376 }
377 else
378 return false;
379
380 /* The type of the object being referred to. It can be an array,
381 string literal, or a non-array type when the MEM_REF represents
382 a reference/subscript via a pointer to an object that is not
383 an element of an array. Incomplete types are excluded as well
384 because their size is not known. */
385 tree reftype = TREE_TYPE (arg);
386 if (POINTER_TYPE_P (reftype)
387 || !COMPLETE_TYPE_P (reftype)
388 || TREE_CODE (TYPE_SIZE_UNIT (reftype)) != INTEGER_CST)
389 return false;
390
391 /* Except in declared objects, references to trailing array members
392 of structs and union objects are excluded because MEM_REF doesn't
393 make it possible to identify the member where the reference
394 originated. */
395 if (RECORD_OR_UNION_TYPE_P (reftype)
396 && (!VAR_P (arg)
397 || (DECL_EXTERNAL (arg) && array_at_struct_end_p (ref))))
398 return false;
399
400 arrbounds[0] = 0;
401
402 offset_int eltsize;
403 if (TREE_CODE (reftype) == ARRAY_TYPE)
404 {
405 eltsize = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (reftype)));
406 if (tree dom = TYPE_DOMAIN (reftype))
407 {
408 tree bnds[] = { TYPE_MIN_VALUE (dom), TYPE_MAX_VALUE (dom) };
409 if (TREE_CODE (arg) == COMPONENT_REF)
410 {
411 offset_int size = maxobjsize;
412 if (tree fldsize = component_ref_size (arg))
413 size = wi::to_offset (fldsize);
414 arrbounds[1] = wi::lrshift (size, wi::floor_log2 (eltsize));
415 }
416 else if (array_at_struct_end_p (arg) || !bnds[0] || !bnds[1])
417 arrbounds[1] = wi::lrshift (maxobjsize, wi::floor_log2 (eltsize));
418 else
419 arrbounds[1] = (wi::to_offset (bnds[1]) - wi::to_offset (bnds[0])
420 + 1) * eltsize;
421 }
422 else
423 arrbounds[1] = wi::lrshift (maxobjsize, wi::floor_log2 (eltsize));
424
425 /* Determine a tighter bound of the non-array element type. */
426 tree eltype = TREE_TYPE (reftype);
427 while (TREE_CODE (eltype) == ARRAY_TYPE)
428 eltype = TREE_TYPE (eltype);
429 eltsize = wi::to_offset (TYPE_SIZE_UNIT (eltype));
430 }
431 else
432 {
433 eltsize = 1;
434 tree size = TYPE_SIZE_UNIT (reftype);
435 if (VAR_P (arg))
436 if (tree initsize = DECL_SIZE_UNIT (arg))
437 if (tree_int_cst_lt (size, initsize))
438 size = initsize;
439
440 arrbounds[1] = wi::to_offset (size);
441 }
442
443 offrange[0] += ioff;
444 offrange[1] += ioff;
445
446 /* Compute the more permissive upper bound when IGNORE_OFF_BY_ONE
447 is set (when taking the address of the one-past-last element
448 of an array) but always use the stricter bound in diagnostics. */
449 offset_int ubound = arrbounds[1];
450 if (ignore_off_by_one)
451 ubound += 1;
452
453 if (arrbounds[0] == arrbounds[1]
454 || offrange[0] >= ubound
455 || offrange[1] < arrbounds[0])
456 {
457 /* Treat a reference to a non-array object as one to an array
458 of a single element. */
459 if (TREE_CODE (reftype) != ARRAY_TYPE)
460 reftype = build_array_type_nelts (reftype, 1);
461
462 /* Extract the element type out of MEM_REF and use its size
463 to compute the index to print in the diagnostic; arrays
464 in MEM_REF don't mean anything. A type with no size like
465 void is as good as having a size of 1. */
466 tree type = TREE_TYPE (ref);
467 while (TREE_CODE (type) == ARRAY_TYPE)
468 type = TREE_TYPE (type);
469 if (tree size = TYPE_SIZE_UNIT (type))
470 {
471 offrange[0] = offrange[0] / wi::to_offset (size);
472 offrange[1] = offrange[1] / wi::to_offset (size);
473 }
474
475 bool warned;
476 if (offrange[0] == offrange[1])
477 warned = warning_at (location, OPT_Warray_bounds,
478 "array subscript %wi is outside array bounds "
479 "of %qT",
480 offrange[0].to_shwi (), reftype);
481 else
482 warned = warning_at (location, OPT_Warray_bounds,
483 "array subscript [%wi, %wi] is outside "
484 "array bounds of %qT",
485 offrange[0].to_shwi (),
486 offrange[1].to_shwi (), reftype);
487 if (warned && DECL_P (arg))
488 inform (DECL_SOURCE_LOCATION (arg), "while referencing %qD", arg);
489
490 if (warned)
491 TREE_NO_WARNING (ref) = 1;
492 return warned;
493 }
494
495 if (warn_array_bounds < 2)
496 return false;
497
498 /* At level 2 check also intermediate offsets. */
499 int i = 0;
500 if (extrema[i] < -arrbounds[1] || extrema[i = 1] > ubound)
501 {
502 HOST_WIDE_INT tmpidx = extrema[i].to_shwi () / eltsize.to_shwi ();
503
504 if (warning_at (location, OPT_Warray_bounds,
505 "intermediate array offset %wi is outside array bounds "
506 "of %qT", tmpidx, reftype))
507 {
508 TREE_NO_WARNING (ref) = 1;
509 return true;
510 }
511 }
512
513 return false;
514}
515
516/* Searches if the expr T, located at LOCATION computes
517 address of an ARRAY_REF, and call check_array_ref on it. */
518
519void
520array_bounds_checker::check_addr_expr (location_t location, tree t)
521{
522 /* Check each ARRAY_REF and MEM_REF in the reference chain. */
523 do
524 {
525 bool warned = false;
526 if (TREE_CODE (t) == ARRAY_REF)
527 warned = check_array_ref (location, t, true /*ignore_off_by_one*/);
528 else if (TREE_CODE (t) == MEM_REF)
529 warned = check_mem_ref (location, t, true /*ignore_off_by_one*/);
530
531 if (warned)
532 TREE_NO_WARNING (t) = true;
533
534 t = TREE_OPERAND (t, 0);
535 }
536 while (handled_component_p (t) || TREE_CODE (t) == MEM_REF);
537
538 if (TREE_CODE (t) != MEM_REF
539 || TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR
540 || TREE_NO_WARNING (t))
541 return;
542
543 tree tem = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
544 tree low_bound, up_bound, el_sz;
545 if (TREE_CODE (TREE_TYPE (tem)) != ARRAY_TYPE
546 || TREE_CODE (TREE_TYPE (TREE_TYPE (tem))) == ARRAY_TYPE
547 || !TYPE_DOMAIN (TREE_TYPE (tem)))
548 return;
549
550 low_bound = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (tem)));
551 up_bound = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (tem)));
552 el_sz = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (tem)));
553 if (!low_bound
554 || TREE_CODE (low_bound) != INTEGER_CST
555 || !up_bound
556 || TREE_CODE (up_bound) != INTEGER_CST
557 || !el_sz
558 || TREE_CODE (el_sz) != INTEGER_CST)
559 return;
560
561 offset_int idx;
562 if (!mem_ref_offset (t).is_constant (&idx))
563 return;
564
565 bool warned = false;
566 idx = wi::sdiv_trunc (idx, wi::to_offset (el_sz));
567 if (idx < 0)
568 {
569 if (dump_file && (dump_flags & TDF_DETAILS))
570 {
571 fprintf (dump_file, "Array bound warning for ");
572 dump_generic_expr (MSG_NOTE, TDF_SLIM, t);
573 fprintf (dump_file, "\n");
574 }
575 warned = warning_at (location, OPT_Warray_bounds,
576 "array subscript %wi is below "
577 "array bounds of %qT",
578 idx.to_shwi (), TREE_TYPE (tem));
579 }
580 else if (idx > (wi::to_offset (up_bound)
581 - wi::to_offset (low_bound) + 1))
582 {
583 if (dump_file && (dump_flags & TDF_DETAILS))
584 {
585 fprintf (dump_file, "Array bound warning for ");
586 dump_generic_expr (MSG_NOTE, TDF_SLIM, t);
587 fprintf (dump_file, "\n");
588 }
589 warned = warning_at (location, OPT_Warray_bounds,
590 "array subscript %wu is above "
591 "array bounds of %qT",
592 idx.to_uhwi (), TREE_TYPE (tem));
593 }
594
595 if (warned)
596 {
597 if (DECL_P (t))
598 inform (DECL_SOURCE_LOCATION (t), "while referencing %qD", t);
599
600 TREE_NO_WARNING (t) = 1;
601 }
602}
603
604/* Callback for walk_tree to check a tree for out of bounds array
605 accesses. The array_bounds_checker class is passed in DATA. */
606
607tree
608array_bounds_checker::check_array_bounds (tree *tp, int *walk_subtree,
609 void *data)
610{
611 tree t = *tp;
612 struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
613 location_t location;
614
615 if (EXPR_HAS_LOCATION (t))
616 location = EXPR_LOCATION (t);
617 else
618 location = gimple_location (wi->stmt);
619
620 *walk_subtree = TRUE;
621
622 bool warned = false;
623 array_bounds_checker *checker = (array_bounds_checker *) wi->info;
624 if (TREE_CODE (t) == ARRAY_REF)
625 warned = checker->check_array_ref (location, t,
626 false/*ignore_off_by_one*/);
627 else if (TREE_CODE (t) == MEM_REF)
628 warned = checker->check_mem_ref (location, t,
629 false /*ignore_off_by_one*/);
630 else if (TREE_CODE (t) == ADDR_EXPR)
631 {
632 checker->check_addr_expr (location, t);
633 *walk_subtree = FALSE;
634 }
635 /* Propagate the no-warning bit to the outer expression. */
636 if (warned)
637 TREE_NO_WARNING (t) = true;
638
639 return NULL_TREE;
640}
641
642/* A dom_walker subclass for use by check_all_array_refs, to walk over
643 all statements of all reachable BBs and call check_array_bounds on
644 them. */
645
646class check_array_bounds_dom_walker : public dom_walker
647{
648public:
649 check_array_bounds_dom_walker (array_bounds_checker *checker)
650 : dom_walker (CDI_DOMINATORS,
651 /* Discover non-executable edges, preserving EDGE_EXECUTABLE
652 flags, so that we can merge in information on
653 non-executable edges from vrp_folder . */
654 REACHABLE_BLOCKS_PRESERVING_FLAGS),
655 checker (checker) { }
656 ~check_array_bounds_dom_walker () {}
657
658 edge before_dom_children (basic_block) FINAL OVERRIDE;
659
660private:
661 array_bounds_checker *checker;
662};
663
664/* Implementation of dom_walker::before_dom_children.
665
666 Walk over all statements of BB and call check_array_bounds on them,
667 and determine if there's a unique successor edge. */
668
669edge
670check_array_bounds_dom_walker::before_dom_children (basic_block bb)
671{
672 gimple_stmt_iterator si;
673 for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
674 {
675 gimple *stmt = gsi_stmt (si);
676 struct walk_stmt_info wi;
677 if (!gimple_has_location (stmt)
678 || is_gimple_debug (stmt))
679 continue;
680
681 memset (&wi, 0, sizeof (wi));
682
683 wi.info = checker;
684
685 walk_gimple_op (stmt, array_bounds_checker::check_array_bounds, &wi);
686 }
687
688 /* Determine if there's a unique successor edge, and if so, return
689 that back to dom_walker, ensuring that we don't visit blocks that
690 became unreachable during the VRP propagation
691 (PR tree-optimization/83312). */
692 return find_taken_edge (bb, NULL_TREE);
693}
694
695void
696array_bounds_checker::check ()
697{
698 check_array_bounds_dom_walker w (this);
699 w.walk (ENTRY_BLOCK_PTR_FOR_FN (fun));
700}