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