Branch data Line data Source code
1 : : /* Array bounds checking.
2 : : Copyright (C) 2005-2025 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 : 108572 : array_bounds_checker::array_bounds_checker (struct function *func)
47 : 217144 : : fun (func), m_ptr_qry (get_range_query (func))
48 : : {
49 : : /* No-op. */
50 : 108572 : }
51 : :
52 : : void
53 : 133832 : array_bounds_checker::get_value_range (irange &r, const_tree op, gimple *stmt)
54 : : {
55 : 133832 : 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 : 163901 : get_base_decl (tree ref)
66 : : {
67 : 163901 : tree base = get_base_address (ref);
68 : 163901 : if (DECL_P (base))
69 : : return base;
70 : :
71 : 14323 : if (TREE_CODE (base) == MEM_REF)
72 : 13865 : base = TREE_OPERAND (base, 0);
73 : :
74 : 14323 : if (TREE_CODE (base) != SSA_NAME)
75 : : return base;
76 : :
77 : 13904 : do
78 : : {
79 : 13904 : gimple *def = SSA_NAME_DEF_STMT (base);
80 : 13904 : if (gimple_assign_single_p (def))
81 : : {
82 : 1984 : base = gimple_assign_rhs1 (def);
83 : 1984 : return base;
84 : : }
85 : :
86 : 11920 : if (!gimple_nop_p (def))
87 : : return base;
88 : :
89 : 8174 : break;
90 : : } while (true);
91 : :
92 : 8174 : tree var = SSA_NAME_VAR (base);
93 : 8174 : 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 : 65590 : get_ref_size (tree arg, tree *pref)
105 : : {
106 : 65590 : if (TREE_CODE (arg) != MEM_REF)
107 : : return NULL_TREE;
108 : :
109 : 65590 : arg = TREE_OPERAND (arg, 0);
110 : 65590 : tree type = TREE_TYPE (arg);
111 : 65590 : if (!POINTER_TYPE_P (type))
112 : : return NULL_TREE;
113 : :
114 : 65590 : type = TREE_TYPE (type);
115 : 65590 : 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 : 163862 : trailing_array (tree arg, tree *pref)
134 : : {
135 : 163862 : tree ref = arg;
136 : 163862 : tree base = get_base_decl (arg);
137 : 498435 : while (TREE_CODE (ref) == ARRAY_REF || TREE_CODE (ref) == MEM_REF)
138 : 170711 : ref = TREE_OPERAND (ref, 0);
139 : :
140 : 163862 : if (TREE_CODE (ref) == COMPONENT_REF)
141 : : {
142 : 36281 : *pref = TREE_OPERAND (ref, 1);
143 : 36281 : tree type = TREE_TYPE (*pref);
144 : 36281 : 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 : 36281 : type = TREE_TYPE (type);
149 : 36281 : if (TREE_CODE (type) == ARRAY_TYPE)
150 : : return false;
151 : : }
152 : : }
153 : : else
154 : 127581 : *pref = base;
155 : :
156 : 159878 : tree basetype = TREE_TYPE (base);
157 : 159878 : if (TREE_CODE (base) == PARM_DECL
158 : 11260 : && POINTER_TYPE_P (basetype))
159 : : {
160 : 7646 : tree ptype = TREE_TYPE (basetype);
161 : 7646 : if (TREE_CODE (ptype) == ARRAY_TYPE)
162 : : return false;
163 : : }
164 : :
165 : 159653 : 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 : 237746 : get_up_bounds_for_array_ref (tree ref, tree *decl,
174 : : tree *up_bound, tree *up_bound_p1)
175 : : {
176 : 237746 : if (!(*up_bound)
177 : 165329 : || TREE_CODE (*up_bound) != INTEGER_CST
178 : 401608 : || 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 : 80321 : tree eltsize = array_ref_element_size (ref);
186 : :
187 : 80321 : if (TREE_CODE (eltsize) != INTEGER_CST
188 : 80321 : || integer_zerop (eltsize))
189 : : {
190 : 577 : *up_bound = NULL_TREE;
191 : 577 : *up_bound_p1 = NULL_TREE;
192 : : }
193 : : else
194 : : {
195 : 79744 : tree ptrdiff_max = TYPE_MAX_VALUE (ptrdiff_type_node);
196 : 79744 : tree maxbound = ptrdiff_max;
197 : 79744 : tree arg = TREE_OPERAND (ref, 0);
198 : :
199 : 79744 : const bool compref = TREE_CODE (arg) == COMPONENT_REF;
200 : 79744 : if (compref)
201 : : {
202 : : /* Try to determine the size of the trailing array from
203 : : its initializer (if it has one). */
204 : 70978 : if (tree refsize = component_ref_size (arg))
205 : 5922 : if (TREE_CODE (refsize) == INTEGER_CST)
206 : 79744 : maxbound = refsize;
207 : : }
208 : :
209 : 79744 : 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 : 73825 : poly_int64 off;
217 : 73825 : if (tree base = get_addr_base_and_unit_offset (arg, &off))
218 : : {
219 : 73517 : 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 : 65590 : if (tree size = get_ref_size (base, decl))
224 : 73517 : maxbound = size;
225 : : }
226 : 7927 : 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 : 73517 : if (known_gt (off, 0))
235 : 64863 : maxbound = wide_int_to_tree (sizetype,
236 : 129726 : wi::sub (wi::to_wide (maxbound),
237 : : off));
238 : : }
239 : : }
240 : : else
241 : 5919 : maxbound = fold_convert (sizetype, maxbound);
242 : :
243 : 79744 : *up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
244 : :
245 : 79744 : if (*up_bound_p1 != NULL_TREE)
246 : 79744 : *up_bound = int_const_binop (MINUS_EXPR, *up_bound_p1,
247 : 159488 : build_int_cst (ptrdiff_type_node, 1));
248 : : else
249 : 0 : *up_bound = NULL_TREE;
250 : : }
251 : : }
252 : : else
253 : 157425 : *up_bound_p1 = int_const_binop (PLUS_EXPR, *up_bound,
254 : 314850 : build_int_cst (TREE_TYPE (*up_bound), 1));
255 : 237746 : 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 : 237746 : 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 : 237746 : tree min, max;
274 : 237746 : tree low_bound = array_ref_low_bound (ref);
275 : 237746 : tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
276 : :
277 : 237746 : bool warned = false;
278 : 237746 : *out_of_bound = false;
279 : :
280 : 237746 : rich_location_with_details richloc (location, stmt);
281 : : /* Empty array. */
282 : 237746 : 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 : 237522 : 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 : 236298 : else if (up_bound
312 : 235721 : && TREE_CODE (up_sub) == INTEGER_CST
313 : 477583 : && (ignore_off_by_one
314 : 232900 : ? !tree_int_cst_le (up_sub, up_bound_p1)
315 : 224515 : : !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 : 235648 : else if (TREE_CODE (low_sub) == INTEGER_CST
324 : 235648 : && 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 : 475492 : return warned;
333 : 237746 : }
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 : 237833 : array_bounds_checker::check_array_ref (location_t location, tree ref,
345 : : gimple *stmt, bool ignore_off_by_one)
346 : : {
347 : 237833 : 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 : 237746 : tree up_bound = array_ref_up_bound (ref);
354 : 237746 : tree up_bound_p1 = NULL_TREE;
355 : :
356 : : /* Referenced decl if one can be determined. */
357 : 237746 : tree decl = NULL_TREE;
358 : :
359 : : /* Set to the type of the special array member for a COMPONENT_REF. */
360 : 237746 : special_array_member sam{ };
361 : 237746 : tree afield_decl = NULL_TREE;
362 : 237746 : tree arg = TREE_OPERAND (ref, 0);
363 : :
364 : 237746 : if (TREE_CODE (arg) == COMPONENT_REF)
365 : : {
366 : : /* Try to determine special array member type for this COMPONENT_REF. */
367 : 98955 : sam = component_ref_sam_type (arg);
368 : 98955 : afield_decl = TREE_OPERAND (arg, 1);
369 : : }
370 : :
371 : 237746 : get_up_bounds_for_array_ref (ref, &decl, &up_bound, &up_bound_p1);
372 : :
373 : 237746 : bool warned = false;
374 : 237746 : bool out_of_bound = false;
375 : :
376 : 237746 : tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
377 : 237746 : tree low_sub_org = TREE_OPERAND (ref, 1);
378 : 237746 : tree up_sub = low_sub_org;
379 : 237746 : tree low_sub = low_sub_org;
380 : :
381 : 237746 : int_range_max vr;
382 : 237746 : if (TREE_CODE (low_sub_org) == SSA_NAME)
383 : : {
384 : 133832 : get_value_range (vr, low_sub_org, stmt);
385 : 133832 : if (!vr.undefined_p () && !vr.varying_p ())
386 : : {
387 : 130958 : tree min, max;
388 : 130958 : value_range_kind kind = get_legacy_range (vr, min, max);
389 : 130958 : low_sub = kind == VR_RANGE ? max : min;
390 : 130958 : up_sub = kind == VR_RANGE ? min : max;
391 : : }
392 : : }
393 : :
394 : 475492 : 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 : 237746 : ignore_off_by_one, warn_array_bounds,
398 : : &out_of_bound);
399 : :
400 : 237746 : rich_location_with_details richloc (location, stmt);
401 : :
402 : 237746 : 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 : 237746 : 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 : 237764 : && 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 : 237746 : 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 : 237746 : return warned;
471 : 237746 : }
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 : 630643 : array_bounds_checker::check_mem_ref (location_t location, tree ref,
485 : : gimple *stmt,
486 : : bool ignore_off_by_one)
487 : : {
488 : 630643 : if (warning_suppressed_p (ref, OPT_Warray_bounds_))
489 : : return false;
490 : :
491 : : /* The statement used to allocate the array or null. */
492 : 630570 : gimple *alloc_stmt = NULL;
493 : : /* For an allocation statement, the low bound of the size range. */
494 : 630570 : offset_int minbound = 0;
495 : : /* The type and size of the access. */
496 : 630570 : tree axstype = TREE_TYPE (ref);
497 : 630570 : offset_int axssize = 0;
498 : 630570 : if (tree access_size = TYPE_SIZE_UNIT (axstype))
499 : 629777 : if (TREE_CODE (access_size) == INTEGER_CST)
500 : 628889 : axssize = wi::to_offset (access_size);
501 : :
502 : 630570 : access_ref aref;
503 : 630570 : if (!m_ptr_qry.get_ref (ref, m_stmt, &aref, 0))
504 : : return false;
505 : :
506 : 630566 : if (aref.offset_in_range (axssize))
507 : : return false;
508 : :
509 : 10726 : if (TREE_CODE (aref.ref) == SSA_NAME)
510 : : {
511 : 525 : gimple *def = SSA_NAME_DEF_STMT (aref.ref);
512 : 525 : if (is_gimple_call (def))
513 : : {
514 : : /* Save the allocation call and the low bound on the size. */
515 : 10726 : alloc_stmt = def;
516 : : minbound = aref.sizrng[0];
517 : : }
518 : : }
519 : :
520 : : /* The range of the byte offset into the reference. Adjusted below. */
521 : 10726 : offset_int offrange[2] = { aref.offrng[0], aref.offrng[1] };
522 : :
523 : : /* The type of the referenced object. */
524 : 10726 : tree reftype = TREE_TYPE (aref.ref);
525 : : /* The size of the referenced array element. */
526 : 10726 : offset_int eltsize = 1;
527 : 10726 : if (POINTER_TYPE_P (reftype))
528 : 546 : reftype = TREE_TYPE (reftype);
529 : :
530 : 10726 : 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 : 10717 : if (TREE_CODE (reftype) == ARRAY_TYPE)
541 : 9901 : reftype = TREE_TYPE (reftype);
542 : 10717 : if (tree refsize = TYPE_SIZE_UNIT (reftype))
543 : 10717 : if (TREE_CODE (refsize) == INTEGER_CST)
544 : 10701 : eltsize = wi::to_offset (refsize);
545 : :
546 : 10717 : const offset_int nelts = aref.sizrng[1] / eltsize;
547 : 10717 : 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 : 10726 : offset_int ubound = aref.sizrng[1];
554 : 10726 : if (ignore_off_by_one)
555 : 9585 : ubound += eltsize;
556 : :
557 : : /* Set if the lower bound of the subscript is out of bounds. */
558 : 10726 : const bool lboob = (aref.sizrng[1] == 0
559 : 10501 : || offrange[0] >= ubound
560 : 20878 : || 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 : 10726 : const bool uboob = !lboob && offrange[0] + axssize > ubound;
565 : 10726 : if (lboob || uboob)
566 : : {
567 : : /* Treat a reference to a non-array object as one to an array
568 : : of a single element. */
569 : 10013 : 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 : 10013 : tree type = strip_array_types (TREE_TYPE (ref));
577 : 10013 : if (tree size = TYPE_SIZE_UNIT (type))
578 : : {
579 : 10012 : offrange[0] = offrange[0] / wi::to_offset (size);
580 : 10012 : offrange[1] = offrange[1] / wi::to_offset (size);
581 : : }
582 : : }
583 : :
584 : 10726 : rich_location_with_details richloc (location, stmt);
585 : 10726 : bool warned = false;
586 : 10726 : 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 : 9958 : else if (uboob && !ignore_off_by_one)
601 : : {
602 : 446 : tree backtype = reftype;
603 : 446 : if (alloc_stmt)
604 : : /* If the memory was dynamically allocated refer to it as if
605 : : it were an untyped array of bytes. */
606 : 284 : backtype = build_array_type_nelts (unsigned_char_type_node,
607 : 284 : aref.sizrng[1].to_uhwi ());
608 : 446 : 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 : 1214 : if (warned)
615 : : {
616 : : /* TODO: Determine the access from the statement and use it. */
617 : 1209 : aref.inform_access (access_none);
618 : 1209 : suppress_warning (ref, OPT_Warray_bounds_);
619 : 1209 : return true;
620 : : }
621 : :
622 : 9517 : 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 : 10726 : }
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 : 893761 : 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 : 893761 : bool ignore_off_by_one = true;
653 : :
654 : : /* Check each ARRAY_REF and MEM_REF in the reference chain. */
655 : 1042868 : do
656 : : {
657 : 1042868 : bool warned = false;
658 : 1042868 : if (TREE_CODE (t) == ARRAY_REF)
659 : : {
660 : 14441 : warned = check_array_ref (location, t, stmt, ignore_off_by_one);
661 : 14441 : ignore_off_by_one = false;
662 : : }
663 : 1028427 : else if (TREE_CODE (t) == MEM_REF)
664 : 58188 : warned = check_mem_ref (location, t, stmt, ignore_off_by_one);
665 : :
666 : 72629 : if (warned)
667 : 181 : suppress_warning (t, OPT_Warray_bounds_);
668 : :
669 : 1042868 : t = TREE_OPERAND (t, 0);
670 : : }
671 : 1191975 : while (handled_component_p (t) || TREE_CODE (t) == MEM_REF);
672 : :
673 : 893761 : if (TREE_CODE (t) != MEM_REF
674 : 0 : || TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR
675 : 893761 : || warning_suppressed_p (t, OPT_Warray_bounds_))
676 : 893761 : 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 : 10050420 : inbounds_memaccess_p (tree t, gimple *stmt)
746 : : {
747 : 10050420 : if (TREE_CODE (t) != COMPONENT_REF)
748 : : return false;
749 : :
750 : 675529 : tree mref = TREE_OPERAND (t, 0);
751 : 675529 : if (TREE_CODE (mref) != MEM_REF)
752 : : return false;
753 : :
754 : : /* Consider the access if its type is a derived class. */
755 : 392007 : tree mreftype = TREE_TYPE (mref);
756 : 392007 : if (!RECORD_OR_UNION_TYPE_P (mreftype)
757 : 392007 : || !TYPE_BINFO (mreftype))
758 : : return false;
759 : :
760 : : /* Compute the size of the referenced object (it could be dynamically
761 : : allocated). */
762 : 194041 : access_ref aref; // unused
763 : 194041 : tree refop = TREE_OPERAND (mref, 0);
764 : 194041 : tree refsize = compute_objsize (refop, stmt, 1, &aref);
765 : 194041 : if (!refsize || TREE_CODE (refsize) != INTEGER_CST)
766 : : return false;
767 : :
768 : : /* Compute the byte offset of the member within its enclosing class. */
769 : 194041 : tree fld = TREE_OPERAND (t, 1);
770 : 194041 : tree fldpos = byte_position (fld);
771 : 194041 : 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 : 194041 : tree refoff = TREE_OPERAND (mref, 1);
777 : 194041 : 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 : 194041 : if (!tree_int_cst_lt (fldoff, refsize))
781 : : return false;
782 : :
783 : 190941 : tree fldsiz = DECL_SIZE_UNIT (fld);
784 : 190941 : 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 : 190785 : tree fldend = int_const_binop (PLUS_EXPR, fldoff, fldsiz);
790 : 190785 : 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 : 11740028 : array_bounds_checker::check_array_bounds (tree *tp, int *walk_subtree,
798 : : void *data)
799 : : {
800 : 11740028 : tree t = *tp;
801 : 11740028 : struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
802 : :
803 : 11740028 : location_t location;
804 : :
805 : 11740028 : if (EXPR_HAS_LOCATION (t))
806 : 1662443 : location = EXPR_LOCATION (t);
807 : : else
808 : 10077585 : location = gimple_location (wi->stmt);
809 : :
810 : 11740028 : *walk_subtree = true;
811 : :
812 : 11740028 : bool warned = false;
813 : 11740028 : array_bounds_checker *checker = (array_bounds_checker *) wi->info;
814 : 11740028 : gcc_assert (checker->m_stmt == wi->stmt);
815 : :
816 : 11740028 : if (TREE_CODE (t) == ARRAY_REF)
817 : 223392 : warned = checker->check_array_ref (location, t, wi->stmt,
818 : : false/*ignore_off_by_one*/);
819 : 11516636 : else if (TREE_CODE (t) == MEM_REF)
820 : 572455 : warned = checker->check_mem_ref (location, t, wi->stmt,
821 : : false /*ignore_off_by_one*/);
822 : 10944181 : else if (TREE_CODE (t) == ADDR_EXPR)
823 : : {
824 : 893761 : checker->check_addr_expr (location, t, wi->stmt);
825 : 893761 : *walk_subtree = false;
826 : : }
827 : 10050420 : 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 : 190704 : *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 : 1880312 : if (warned)
836 : 2300 : suppress_warning (wi->stmt, OPT_Warray_bounds_);
837 : :
838 : 11740028 : 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 : 108572 : check_array_bounds_dom_walker (array_bounds_checker *checker)
849 : 108572 : : dom_walker (CDI_DOMINATORS, REACHABLE_BLOCKS),
850 : 217144 : checker (checker) { }
851 : 217144 : ~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 : 1059253 : check_array_bounds_dom_walker::before_dom_children (basic_block bb)
866 : : {
867 : 1059253 : gimple_stmt_iterator si;
868 : 10746337 : for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
869 : : {
870 : 8627831 : gimple *stmt = gsi_stmt (si);
871 : 8627831 : if (!gimple_has_location (stmt)
872 : 8627831 : || is_gimple_debug (stmt))
873 : 4970544 : continue;
874 : :
875 : 3657287 : struct walk_stmt_info wi{ };
876 : 3657287 : wi.info = checker;
877 : 3657287 : checker->m_stmt = stmt;
878 : :
879 : 3657287 : 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 : 1059253 : return find_taken_edge (bb, NULL_TREE);
887 : : }
888 : :
889 : : void
890 : 108572 : array_bounds_checker::check ()
891 : : {
892 : 108572 : check_array_bounds_dom_walker w (this);
893 : 108572 : w.walk (ENTRY_BLOCK_PTR_FOR_FN (fun));
894 : 108572 : }
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 : 287349 : pass_array_bounds (gcc::context *ctxt, const pass_data &data_)
913 : 574698 : : 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 : 1027737 : bool gate (function *) final override
920 : : {
921 : : // Gate on the VRP pass to preserve previous behavior.
922 : 1027737 : return flag_tree_vrp && (warn_array_bounds || warn_strict_flex_arrays);
923 : : }
924 : 108572 : unsigned int execute (function *fun) final override
925 : : {
926 : 108572 : calculate_dominance_info (CDI_DOMINATORS);
927 : : // Enable ranger as the current range query.
928 : 108572 : enable_ranger (fun, false);
929 : 108572 : array_bounds_checker array_checker (fun);
930 : 108572 : array_checker.check ();
931 : 108572 : disable_ranger (fun);
932 : 108572 : return 0;
933 : 108572 : }
934 : :
935 : : private:
936 : : const pass_data &data;
937 : : }; // class pass_array_bounds
938 : :
939 : : gimple_opt_pass *
940 : 287349 : make_pass_array_bounds (gcc::context *ctxt)
941 : : {
942 : 287349 : return new pass_array_bounds (ctxt, pass_data_array_bounds);
943 : : }
|