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