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