]>
Commit | Line | Data |
---|---|---|
62efd1c4 | 1 | /* Array bounds checking. |
7adcbafe | 2 | Copyright (C) 2005-2022 Free Software Foundation, Inc. |
62efd1c4 AH |
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" | |
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 | |
42 | array_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 | 49 | const value_range * |
dd44445f | 50 | array_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 | ||
59 | static tree | |
60 | get_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 | ||
98 | static tree | |
99 | get_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 | ||
127 | static bool | |
128 | trailing_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 |
167 | static void |
168 | get_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 |
259 | static bool |
260 | check_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 | ||
335 | bool | |
336 | array_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 | ||
489 | bool | |
490 | array_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 | ||
651 | void | |
dd44445f AH |
652 | array_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 | ||
748 | static bool | |
9a27acc3 | 749 | inbounds_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 | ||
800 | tree | |
801 | array_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 | ||
849 | class check_array_bounds_dom_walker : public dom_walker | |
850 | { | |
851 | public: | |
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 | |
863 | private: | |
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 | ||
872 | edge | |
873 | check_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 | ||
897 | void | |
898 | array_bounds_checker::check () | |
899 | { | |
900 | check_array_bounds_dom_walker w (this); | |
901 | w.walk (ENTRY_BLOCK_PTR_FOR_FN (fun)); | |
902 | } |