File: | build/gcc/gimple-ssa-warn-restrict.cc |
Warning: | line 201, column 28 The left operand of '!=' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Pass to detect and issue warnings for violations of the restrict | ||||
2 | qualifier. | ||||
3 | Copyright (C) 2017-2023 Free Software Foundation, Inc. | ||||
4 | Contributed by Martin Sebor <msebor@redhat.com>. | ||||
5 | |||||
6 | This file is part of GCC. | ||||
7 | |||||
8 | GCC is free software; you can redistribute it and/or modify it under | ||||
9 | the terms of the GNU General Public License as published by the Free | ||||
10 | Software Foundation; either version 3, or (at your option) any later | ||||
11 | version. | ||||
12 | |||||
13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | ||||
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||||
16 | for more details. | ||||
17 | |||||
18 | You should have received a copy of the GNU General Public License | ||||
19 | along with GCC; see the file COPYING3. If not see | ||||
20 | <http://www.gnu.org/licenses/>. */ | ||||
21 | |||||
22 | #include "config.h" | ||||
23 | #include "system.h" | ||||
24 | #include "coretypes.h" | ||||
25 | #include "backend.h" | ||||
26 | #include "tree.h" | ||||
27 | #include "gimple.h" | ||||
28 | #include "tree-pass.h" | ||||
29 | #include "pointer-query.h" | ||||
30 | #include "ssa.h" | ||||
31 | #include "gimple-pretty-print.h" | ||||
32 | #include "gimple-ssa-warn-access.h" | ||||
33 | #include "gimple-ssa-warn-restrict.h" | ||||
34 | #include "diagnostic-core.h" | ||||
35 | #include "fold-const.h" | ||||
36 | #include "gimple-iterator.h" | ||||
37 | #include "tree-dfa.h" | ||||
38 | #include "tree-ssa.h" | ||||
39 | #include "tree-cfg.h" | ||||
40 | #include "tree-object-size.h" | ||||
41 | #include "calls.h" | ||||
42 | #include "cfgloop.h" | ||||
43 | #include "intl.h" | ||||
44 | #include "gimple-range.h" | ||||
45 | |||||
46 | namespace { | ||||
47 | |||||
48 | const pass_data pass_data_wrestrict = { | ||||
49 | GIMPLE_PASS, | ||||
50 | "wrestrict", | ||||
51 | OPTGROUP_NONE, | ||||
52 | TV_NONE, | ||||
53 | PROP_cfg(1 << 3), /* Properties_required. */ | ||||
54 | 0, /* properties_provided. */ | ||||
55 | 0, /* properties_destroyed. */ | ||||
56 | 0, /* properties_start */ | ||||
57 | 0, /* properties_finish */ | ||||
58 | }; | ||||
59 | |||||
60 | /* Pass to detect violations of strict aliasing requirements in calls | ||||
61 | to built-in string and raw memory functions. */ | ||||
62 | class pass_wrestrict : public gimple_opt_pass | ||||
63 | { | ||||
64 | public: | ||||
65 | pass_wrestrict (gcc::context *); | ||||
66 | |||||
67 | bool gate (function *) final override; | ||||
68 | unsigned int execute (function *) final override; | ||||
69 | |||||
70 | void check_call (gimple *); | ||||
71 | |||||
72 | void check_block (basic_block); | ||||
73 | |||||
74 | /* A pointer_query object to store information about pointers and | ||||
75 | their targets in. */ | ||||
76 | pointer_query m_ptr_qry; | ||||
77 | }; | ||||
78 | |||||
79 | pass_wrestrict::pass_wrestrict (gcc::context *ctxt) | ||||
80 | : gimple_opt_pass (pass_data_wrestrict, ctxt), | ||||
81 | m_ptr_qry () | ||||
82 | { } | ||||
83 | |||||
84 | bool | ||||
85 | pass_wrestrict::gate (function *fun ATTRIBUTE_UNUSED__attribute__ ((__unused__))) | ||||
86 | { | ||||
87 | return warn_array_boundsglobal_options.x_warn_array_bounds || warn_restrictglobal_options.x_warn_restrict || warn_stringop_overflowglobal_options.x_warn_stringop_overflow; | ||||
88 | } | ||||
89 | |||||
90 | void | ||||
91 | pass_wrestrict::check_block (basic_block bb) | ||||
92 | { | ||||
93 | /* Iterate over statements, looking for function calls. */ | ||||
94 | for (auto si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si)) | ||||
95 | { | ||||
96 | gimple *stmt = gsi_stmt (si); | ||||
97 | if (!is_gimple_call (stmt)) | ||||
98 | continue; | ||||
99 | |||||
100 | check_call (stmt); | ||||
101 | } | ||||
102 | } | ||||
103 | |||||
104 | unsigned | ||||
105 | pass_wrestrict::execute (function *fun) | ||||
106 | { | ||||
107 | /* Create a new ranger instance and associate it with FUN. */ | ||||
108 | m_ptr_qry.rvals = enable_ranger (fun); | ||||
109 | |||||
110 | basic_block bb; | ||||
111 | FOR_EACH_BB_FN (bb, fun)for (bb = (fun)->cfg->x_entry_block_ptr->next_bb; bb != (fun)->cfg->x_exit_block_ptr; bb = bb->next_bb) | ||||
| |||||
112 | check_block (bb); | ||||
113 | |||||
114 | m_ptr_qry.flush_cache (); | ||||
115 | |||||
116 | /* Release the ranger instance and replace it with a global ranger. | ||||
117 | Also reset the pointer since calling disable_ranger() deletes it. */ | ||||
118 | disable_ranger (fun); | ||||
119 | m_ptr_qry.rvals = NULL__null; | ||||
120 | |||||
121 | return 0; | ||||
122 | } | ||||
123 | |||||
124 | /* Description of a memory reference by a built-in function. This | ||||
125 | is similar to ao_ref but made especially suitable for -Wrestrict | ||||
126 | and not for optimization. */ | ||||
127 | class builtin_memref | ||||
128 | { | ||||
129 | public: | ||||
130 | /* The original pointer argument to the built-in function. */ | ||||
131 | tree ptr; | ||||
132 | /* The referenced subobject or NULL if not available, and the base | ||||
133 | object of the memory reference or NULL. */ | ||||
134 | tree ref; | ||||
135 | tree base; | ||||
136 | |||||
137 | /* The size of the BASE object, PTRDIFF_MAX if indeterminate, | ||||
138 | and negative until (possibly lazily) initialized. */ | ||||
139 | offset_int basesize; | ||||
140 | /* Same for the subobject. */ | ||||
141 | offset_int refsize; | ||||
142 | |||||
143 | /* The non-negative offset of the referenced subobject. Used to avoid | ||||
144 | warnings for (apparently) possibly but not definitively overlapping | ||||
145 | accesses to member arrays. Negative when unknown/invalid. */ | ||||
146 | offset_int refoff; | ||||
147 | |||||
148 | /* The offset range relative to the base. */ | ||||
149 | offset_int offrange[2]; | ||||
150 | /* The size range of the access to this reference. */ | ||||
151 | offset_int sizrange[2]; | ||||
152 | |||||
153 | /* Cached result of get_max_objsize(). */ | ||||
154 | const offset_int maxobjsize; | ||||
155 | |||||
156 | /* True for "bounded" string functions like strncat, and strncpy | ||||
157 | and their variants that specify either an exact or upper bound | ||||
158 | on the size of the accesses they perform. For strncat both | ||||
159 | the source and destination references are bounded. For strncpy | ||||
160 | only the destination reference is. */ | ||||
161 | bool strbounded_p; | ||||
162 | |||||
163 | builtin_memref (pointer_query &, gimple *, tree, tree); | ||||
164 | |||||
165 | tree offset_out_of_bounds (int, offset_int[3]) const; | ||||
166 | |||||
167 | private: | ||||
168 | /* Call statement to the built-in. */ | ||||
169 | gimple *stmt; | ||||
170 | |||||
171 | pointer_query &m_ptr_qry; | ||||
172 | |||||
173 | /* Ctor helper to set or extend OFFRANGE based on argument. */ | ||||
174 | void extend_offset_range (tree); | ||||
175 | |||||
176 | /* Ctor helper to determine BASE and OFFRANGE from argument. */ | ||||
177 | void set_base_and_offset (tree); | ||||
178 | }; | ||||
179 | |||||
180 | /* Description of a memory access by a raw memory or string built-in | ||||
181 | function involving a pair of builtin_memref's. */ | ||||
182 | class builtin_access | ||||
183 | { | ||||
184 | public: | ||||
185 | /* Destination and source memory reference. */ | ||||
186 | builtin_memref* const dstref; | ||||
187 | builtin_memref* const srcref; | ||||
188 | /* The size range of the access. It's the greater of the accesses | ||||
189 | to the two references. */ | ||||
190 | HOST_WIDE_INTlong sizrange[2]; | ||||
191 | |||||
192 | /* The minimum and maximum offset of an overlap of the access | ||||
193 | (if it does, in fact, overlap), and the size of the overlap. */ | ||||
194 | HOST_WIDE_INTlong ovloff[2]; | ||||
195 | HOST_WIDE_INTlong ovlsiz[2]; | ||||
196 | |||||
197 | /* True to consider valid only accesses to the smallest subobject | ||||
198 | and false for raw memory functions. */ | ||||
199 | bool strict () const | ||||
200 | { | ||||
201 | return (detect_overlap != &builtin_access::generic_overlap | ||||
| |||||
202 | && detect_overlap != &builtin_access::no_overlap); | ||||
203 | } | ||||
204 | |||||
205 | builtin_access (pointer_query &, gimple *, | ||||
206 | builtin_memref &, builtin_memref &); | ||||
207 | |||||
208 | /* Entry point to determine overlap. */ | ||||
209 | bool overlap (); | ||||
210 | |||||
211 | offset_int write_off (tree) const; | ||||
212 | |||||
213 | void dump (FILE *) const; | ||||
214 | |||||
215 | private: | ||||
216 | /* Implementation functions used to determine overlap. */ | ||||
217 | bool generic_overlap (); | ||||
218 | bool strcat_overlap (); | ||||
219 | bool strcpy_overlap (); | ||||
220 | |||||
221 | bool no_overlap () | ||||
222 | { | ||||
223 | return false; | ||||
224 | } | ||||
225 | |||||
226 | offset_int overlap_size (const offset_int [2], const offset_int[2], | ||||
227 | offset_int [2]); | ||||
228 | |||||
229 | private: | ||||
230 | /* Temporaries used to compute the final result. */ | ||||
231 | offset_int dstoff[2]; | ||||
232 | offset_int srcoff[2]; | ||||
233 | offset_int dstsiz[2]; | ||||
234 | offset_int srcsiz[2]; | ||||
235 | |||||
236 | /* Pointer to a member function to call to determine overlap. */ | ||||
237 | bool (builtin_access::*detect_overlap) (); | ||||
238 | }; | ||||
239 | |||||
240 | /* Initialize a memory reference representation from a pointer EXPR and | ||||
241 | a size SIZE in bytes. If SIZE is NULL_TREE then the size is assumed | ||||
242 | to be unknown. STMT is the statement in which expr appears in. */ | ||||
243 | |||||
244 | builtin_memref::builtin_memref (pointer_query &ptrqry, gimple *stmt, tree expr, | ||||
245 | tree size) | ||||
246 | : ptr (expr), | ||||
247 | ref (), | ||||
248 | base (), | ||||
249 | basesize (-1), | ||||
250 | refsize (-1), | ||||
251 | refoff (HOST_WIDE_INT_MIN(long) (1UL << (64 - 1))), | ||||
252 | offrange (), | ||||
253 | sizrange (), | ||||
254 | maxobjsize (tree_to_shwi (max_object_size ())), | ||||
255 | strbounded_p (), | ||||
256 | stmt (stmt), | ||||
257 | m_ptr_qry (ptrqry) | ||||
258 | { | ||||
259 | /* Unfortunately, wide_int default ctor is a no-op so array members | ||||
260 | of the type must be set individually. */ | ||||
261 | offrange[0] = offrange[1] = 0; | ||||
262 | sizrange[0] = sizrange[1] = 0; | ||||
263 | |||||
264 | if (!expr) | ||||
265 | return; | ||||
266 | |||||
267 | /* Find the BASE object or pointer referenced by EXPR and set | ||||
268 | the offset range OFFRANGE in the process. */ | ||||
269 | set_base_and_offset (expr); | ||||
270 | |||||
271 | if (size) | ||||
272 | { | ||||
273 | tree range[2]; | ||||
274 | /* Determine the size range, allowing for the result to be [0, 0] | ||||
275 | for SIZE in the anti-range ~[0, N] where N >= PTRDIFF_MAX. */ | ||||
276 | get_size_range (m_ptr_qry.rvals, size, stmt, range, SR_ALLOW_ZERO); | ||||
277 | sizrange[0] = wi::to_offset (range[0]); | ||||
278 | sizrange[1] = wi::to_offset (range[1]); | ||||
279 | /* get_size_range returns SIZE_MAX for the maximum size. | ||||
280 | Constrain it to the real maximum of PTRDIFF_MAX. */ | ||||
281 | if (sizrange[0] <= maxobjsize && sizrange[1] > maxobjsize) | ||||
282 | sizrange[1] = maxobjsize; | ||||
283 | } | ||||
284 | else | ||||
285 | sizrange[1] = maxobjsize; | ||||
286 | |||||
287 | if (!DECL_P (base)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (base)->base.code))] == tcc_declaration)) | ||||
288 | return; | ||||
289 | |||||
290 | /* If the offset could be in the range of the referenced object | ||||
291 | constrain its bounds so neither exceeds those of the object. */ | ||||
292 | if (offrange[0] < 0 && offrange[1] > 0) | ||||
293 | offrange[0] = 0; | ||||
294 | |||||
295 | offset_int maxoff = maxobjsize; | ||||
296 | tree basetype = TREE_TYPE (base)((contains_struct_check ((base), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 296, __FUNCTION__))->typed.type); | ||||
297 | if (TREE_CODE (basetype)((enum tree_code) (basetype)->base.code) == ARRAY_TYPE) | ||||
298 | { | ||||
299 | if (ref && array_ref_flexible_size_p (ref)) | ||||
300 | ; /* Use the maximum possible offset for an array that might | ||||
301 | have flexible size. */ | ||||
302 | else if (tree basesize = TYPE_SIZE_UNIT (basetype)((tree_class_check ((basetype), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 302, __FUNCTION__))->type_common.size_unit)) | ||||
303 | if (TREE_CODE (basesize)((enum tree_code) (basesize)->base.code) == INTEGER_CST) | ||||
304 | /* Size could be non-constant for a variable-length type such | ||||
305 | as a struct with a VLA member (a GCC extension). */ | ||||
306 | maxoff = wi::to_offset (basesize); | ||||
307 | } | ||||
308 | |||||
309 | if (offrange[0] >= 0) | ||||
310 | { | ||||
311 | if (offrange[1] < 0) | ||||
312 | offrange[1] = offrange[0] <= maxoff ? maxoff : maxobjsize; | ||||
313 | else if (offrange[0] <= maxoff && offrange[1] > maxoff) | ||||
314 | offrange[1] = maxoff; | ||||
315 | } | ||||
316 | } | ||||
317 | |||||
318 | /* Based on the initial length of the destination STARTLEN, returns | ||||
319 | the offset of the first write access from the beginning of | ||||
320 | the destination. Nonzero only for strcat-type of calls. */ | ||||
321 | |||||
322 | offset_int builtin_access::write_off (tree startlen) const | ||||
323 | { | ||||
324 | if (detect_overlap != &builtin_access::strcat_overlap | ||||
325 | || !startlen || TREE_CODE (startlen)((enum tree_code) (startlen)->base.code) != INTEGER_CST) | ||||
326 | return 0; | ||||
327 | |||||
328 | return wi::to_offset (startlen); | ||||
329 | } | ||||
330 | |||||
331 | /* Ctor helper to set or extend OFFRANGE based on the OFFSET argument. | ||||
332 | Pointer offsets are represented as unsigned sizetype but must be | ||||
333 | treated as signed. */ | ||||
334 | |||||
335 | void | ||||
336 | builtin_memref::extend_offset_range (tree offset) | ||||
337 | { | ||||
338 | if (TREE_CODE (offset)((enum tree_code) (offset)->base.code) == INTEGER_CST) | ||||
339 | { | ||||
340 | offset_int off = int_cst_value (offset); | ||||
341 | if (off != 0) | ||||
342 | { | ||||
343 | offrange[0] += off; | ||||
344 | offrange[1] += off; | ||||
345 | } | ||||
346 | return; | ||||
347 | } | ||||
348 | |||||
349 | if (TREE_CODE (offset)((enum tree_code) (offset)->base.code) == SSA_NAME) | ||||
350 | { | ||||
351 | /* A pointer offset is represented as sizetype but treated | ||||
352 | as signed. */ | ||||
353 | wide_int min, max; | ||||
354 | value_range_kind rng = VR_VARYING; | ||||
355 | value_range vr; | ||||
356 | if (m_ptr_qry.rvals->range_of_expr (vr, offset, stmt)) | ||||
357 | { | ||||
358 | rng = vr.kind (); | ||||
359 | if (!vr.undefined_p ()) | ||||
360 | { | ||||
361 | min = wi::to_wide (vr.min ()); | ||||
362 | max = wi::to_wide (vr.max ()); | ||||
363 | } | ||||
364 | } | ||||
365 | |||||
366 | if (rng == VR_ANTI_RANGE && wi::lts_p (max, min)) | ||||
367 | { | ||||
368 | /* Convert an anti-range whose upper bound is less than | ||||
369 | its lower bound to a signed range. */ | ||||
370 | offrange[0] += offset_int::from (max + 1, SIGNED); | ||||
371 | offrange[1] += offset_int::from (min - 1, SIGNED); | ||||
372 | return; | ||||
373 | } | ||||
374 | |||||
375 | if (rng == VR_RANGE | ||||
376 | && (DECL_P (base)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (base)->base.code))] == tcc_declaration) || wi::lts_p (min, max))) | ||||
377 | { | ||||
378 | /* Preserve the bounds of the range for an offset into | ||||
379 | a known object (it may be adjusted later relative to | ||||
380 | a constant offset from its beginning). Otherwise use | ||||
381 | the bounds only when they are ascending when treated | ||||
382 | as signed. */ | ||||
383 | offrange[0] += offset_int::from (min, SIGNED); | ||||
384 | offrange[1] += offset_int::from (max, SIGNED); | ||||
385 | return; | ||||
386 | } | ||||
387 | |||||
388 | /* Handle an anti-range the same as no range at all. */ | ||||
389 | gimple *stmt = SSA_NAME_DEF_STMT (offset)(tree_check ((offset), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 389, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | ||||
390 | tree type; | ||||
391 | if (is_gimple_assign (stmt) | ||||
392 | && (type = TREE_TYPE (gimple_assign_rhs1 (stmt))((contains_struct_check ((gimple_assign_rhs1 (stmt)), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 392, __FUNCTION__))->typed.type)) | ||||
393 | && INTEGRAL_TYPE_P (type)(((enum tree_code) (type)->base.code) == ENUMERAL_TYPE || ( (enum tree_code) (type)->base.code) == BOOLEAN_TYPE || ((enum tree_code) (type)->base.code) == INTEGER_TYPE)) | ||||
394 | { | ||||
395 | tree_code code = gimple_assign_rhs_code (stmt); | ||||
396 | if (code == NOP_EXPR) | ||||
397 | { | ||||
398 | /* Use the bounds of the type of the NOP_EXPR operand | ||||
399 | even if it's signed. The result doesn't trigger | ||||
400 | warnings but makes their output more readable. */ | ||||
401 | offrange[0] += wi::to_offset (TYPE_MIN_VALUE (type)((tree_check5 ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 401, __FUNCTION__, (INTEGER_TYPE), (ENUMERAL_TYPE), (BOOLEAN_TYPE ), (REAL_TYPE), (FIXED_POINT_TYPE)))->type_non_common.minval )); | ||||
402 | offrange[1] += wi::to_offset (TYPE_MAX_VALUE (type)((tree_check5 ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 402, __FUNCTION__, (INTEGER_TYPE), (ENUMERAL_TYPE), (BOOLEAN_TYPE ), (REAL_TYPE), (FIXED_POINT_TYPE)))->type_non_common.maxval )); | ||||
403 | return; | ||||
404 | } | ||||
405 | } | ||||
406 | } | ||||
407 | |||||
408 | const offset_int maxoff = tree_to_shwi (max_object_size ()) >> 1; | ||||
409 | const offset_int minoff = -maxoff - 1; | ||||
410 | |||||
411 | offrange[0] += minoff; | ||||
412 | offrange[1] += maxoff; | ||||
413 | } | ||||
414 | |||||
415 | /* Determines the base object or pointer of the reference EXPR | ||||
416 | and the offset range from the beginning of the base. */ | ||||
417 | |||||
418 | void | ||||
419 | builtin_memref::set_base_and_offset (tree expr) | ||||
420 | { | ||||
421 | tree offset = NULL_TREE(tree) __null; | ||||
422 | |||||
423 | if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == SSA_NAME) | ||||
424 | { | ||||
425 | /* Try to tease the offset out of the pointer. */ | ||||
426 | gimple *stmt = SSA_NAME_DEF_STMT (expr)(tree_check ((expr), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 426, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | ||||
427 | if (!base | ||||
428 | && gimple_assign_single_p (stmt) | ||||
429 | && gimple_assign_rhs_code (stmt) == ADDR_EXPR) | ||||
430 | expr = gimple_assign_rhs1 (stmt); | ||||
431 | else if (is_gimple_assign (stmt)) | ||||
432 | { | ||||
433 | tree_code code = gimple_assign_rhs_code (stmt); | ||||
434 | if (CONVERT_EXPR_CODE_P (code)((code) == NOP_EXPR || (code) == CONVERT_EXPR)) | ||||
435 | { | ||||
436 | tree rhs = gimple_assign_rhs1 (stmt); | ||||
437 | if (POINTER_TYPE_P (TREE_TYPE (rhs))(((enum tree_code) (((contains_struct_check ((rhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 437, __FUNCTION__))->typed.type))->base.code) == POINTER_TYPE || ((enum tree_code) (((contains_struct_check ((rhs), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 437, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE )) | ||||
438 | expr = gimple_assign_rhs1 (stmt); | ||||
439 | else | ||||
440 | { | ||||
441 | base = expr; | ||||
442 | return; | ||||
443 | } | ||||
444 | } | ||||
445 | else if (code == POINTER_PLUS_EXPR) | ||||
446 | { | ||||
447 | expr = gimple_assign_rhs1 (stmt); | ||||
448 | offset = gimple_assign_rhs2 (stmt); | ||||
449 | } | ||||
450 | else | ||||
451 | { | ||||
452 | base = expr; | ||||
453 | return; | ||||
454 | } | ||||
455 | } | ||||
456 | else | ||||
457 | { | ||||
458 | /* FIXME: Handle PHI nodes in case like: | ||||
459 | _12 = &MEM[(void *)&a + 2B] + _10; | ||||
460 | |||||
461 | <bb> [local count: 1073741824]: | ||||
462 | # prephitmp_13 = PHI <_12, &MEM[(void *)&a + 2B]> | ||||
463 | memcpy (prephitmp_13, p_7(D), 6); */ | ||||
464 | base = expr; | ||||
465 | return; | ||||
466 | } | ||||
467 | } | ||||
468 | |||||
469 | if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == ADDR_EXPR) | ||||
470 | expr = TREE_OPERAND (expr, 0)(*((const_cast<tree*> (tree_operand_check ((expr), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 470, __FUNCTION__))))); | ||||
471 | |||||
472 | /* Stash the reference for offset validation. */ | ||||
473 | ref = expr; | ||||
474 | |||||
475 | poly_int64 bitsize, bitpos; | ||||
476 | tree var_off; | ||||
477 | machine_mode mode; | ||||
478 | int sign, reverse, vol; | ||||
479 | |||||
480 | /* Determine the base object or pointer of the reference and | ||||
481 | the constant bit offset from the beginning of the base. | ||||
482 | If the offset has a non-constant component, it will be in | ||||
483 | VAR_OFF. MODE, SIGN, REVERSE, and VOL are write only and | ||||
484 | unused here. */ | ||||
485 | base = get_inner_reference (expr, &bitsize, &bitpos, &var_off, | ||||
486 | &mode, &sign, &reverse, &vol); | ||||
487 | |||||
488 | /* get_inner_reference is not expected to return null. */ | ||||
489 | gcc_assert (base != NULL)((void)(!(base != __null) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 489, __FUNCTION__), 0 : 0)); | ||||
490 | |||||
491 | if (offset) | ||||
492 | extend_offset_range (offset); | ||||
493 | |||||
494 | poly_int64 bytepos = exact_div (bitpos, BITS_PER_UNIT(8)); | ||||
495 | |||||
496 | /* Convert the poly_int64 offset to offset_int. The offset | ||||
497 | should be constant but be prepared for it not to be just in | ||||
498 | case. */ | ||||
499 | offset_int cstoff; | ||||
500 | if (bytepos.is_constant (&cstoff)) | ||||
501 | { | ||||
502 | offrange[0] += cstoff; | ||||
503 | offrange[1] += cstoff; | ||||
504 | |||||
505 | /* Besides the reference saved above, also stash the offset | ||||
506 | for validation. */ | ||||
507 | if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == COMPONENT_REF) | ||||
508 | refoff = cstoff; | ||||
509 | } | ||||
510 | else | ||||
511 | offrange[1] += maxobjsize; | ||||
512 | |||||
513 | if (var_off) | ||||
514 | { | ||||
515 | if (TREE_CODE (var_off)((enum tree_code) (var_off)->base.code) == INTEGER_CST) | ||||
516 | { | ||||
517 | cstoff = wi::to_offset (var_off); | ||||
518 | offrange[0] += cstoff; | ||||
519 | offrange[1] += cstoff; | ||||
520 | } | ||||
521 | else | ||||
522 | offrange[1] += maxobjsize; | ||||
523 | } | ||||
524 | |||||
525 | if (TREE_CODE (base)((enum tree_code) (base)->base.code) == MEM_REF) | ||||
526 | { | ||||
527 | tree memrefoff = fold_convert (ptrdiff_type_node, TREE_OPERAND (base, 1))fold_convert_loc (((location_t) 0), global_trees[TI_PTRDIFF_TYPE ], (*((const_cast<tree*> (tree_operand_check ((base), ( 1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 527, __FUNCTION__)))))); | ||||
528 | extend_offset_range (memrefoff); | ||||
529 | |||||
530 | if (refoff != HOST_WIDE_INT_MIN(long) (1UL << (64 - 1)) | ||||
531 | && TREE_CODE (expr)((enum tree_code) (expr)->base.code) == COMPONENT_REF) | ||||
532 | { | ||||
533 | /* Bump up the offset of the referenced subobject to reflect | ||||
534 | the offset to the enclosing object. For example, so that | ||||
535 | in | ||||
536 | struct S { char a, b[3]; } s[2]; | ||||
537 | strcpy (s[1].b, "1234"); | ||||
538 | REFOFF is set to s[1].b - (char*)s. */ | ||||
539 | offset_int off = tree_to_shwi (memrefoff); | ||||
540 | refoff += off; | ||||
541 | |||||
542 | if (!integer_zerop (memrefoff) | ||||
543 | && !COMPLETE_TYPE_P (TREE_TYPE (expr))(((tree_class_check ((((contains_struct_check ((expr), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 543, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 543, __FUNCTION__))->type_common.size) != (tree) __null) | ||||
544 | && multiple_of_p (sizetypesizetype_tab[(int) stk_sizetype], memrefoff, | ||||
545 | TYPE_SIZE_UNIT (TREE_TYPE (base))((tree_class_check ((((contains_struct_check ((base), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 545, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 545, __FUNCTION__))->type_common.size_unit), true)) | ||||
546 | /* A non-zero offset into an array of struct with flexible array | ||||
547 | members implies that the array is empty because there is no | ||||
548 | way to initialize such a member when it belongs to an array. | ||||
549 | This must be some sort of a bug. */ | ||||
550 | refsize = 0; | ||||
551 | } | ||||
552 | |||||
553 | base = TREE_OPERAND (base, 0)(*((const_cast<tree*> (tree_operand_check ((base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 553, __FUNCTION__))))); | ||||
554 | } | ||||
555 | |||||
556 | if (TREE_CODE (ref)((enum tree_code) (ref)->base.code) == COMPONENT_REF) | ||||
557 | if (tree size = component_ref_size (ref)) | ||||
558 | if (TREE_CODE (size)((enum tree_code) (size)->base.code) == INTEGER_CST) | ||||
559 | refsize = wi::to_offset (size); | ||||
560 | |||||
561 | if (TREE_CODE (base)((enum tree_code) (base)->base.code) == SSA_NAME) | ||||
562 | set_base_and_offset (base); | ||||
563 | } | ||||
564 | |||||
565 | /* Return error_mark_node if the signed offset exceeds the bounds | ||||
566 | of the address space (PTRDIFF_MAX). Otherwise, return either BASE | ||||
567 | or REF when the offset exceeds the bounds of the BASE or REF object, | ||||
568 | and set OOBOFF to the past-the-end offset formed by the reference, | ||||
569 | including its size. OOBOFF is initially setto the range of offsets, | ||||
570 | and OOBOFF[2] to the offset of the first write access (nonzero for | ||||
571 | the strcat family). When STRICT is nonzero use REF size, when | ||||
572 | available, otherwise use BASE size. When STRICT is greater than 1, | ||||
573 | use the size of the last array member as the bound, otherwise treat | ||||
574 | such a member as a flexible array member. Return NULL when the offset | ||||
575 | is in bounds. */ | ||||
576 | |||||
577 | tree | ||||
578 | builtin_memref::offset_out_of_bounds (int strict, offset_int ooboff[3]) const | ||||
579 | { | ||||
580 | if (!ptr) | ||||
581 | return NULL_TREE(tree) __null; | ||||
582 | |||||
583 | /* The offset of the first write access or zero. */ | ||||
584 | offset_int wroff = ooboff[2]; | ||||
585 | |||||
586 | /* A temporary, possibly adjusted, copy of the offset range. */ | ||||
587 | offset_int offrng[2] = { ooboff[0], ooboff[1] }; | ||||
588 | |||||
589 | if (DECL_P (base)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (base)->base.code))] == tcc_declaration) && TREE_CODE (TREE_TYPE (base))((enum tree_code) (((contains_struct_check ((base), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 589, __FUNCTION__))->typed.type))->base.code) == ARRAY_TYPE) | ||||
590 | { | ||||
591 | /* Check for offset in an anti-range with a negative lower bound. | ||||
592 | For such a range, consider only the non-negative subrange. */ | ||||
593 | if (offrng[1] < offrng[0] && offrng[1] < 0) | ||||
594 | offrng[1] = maxobjsize; | ||||
595 | } | ||||
596 | |||||
597 | /* Conservative offset of the last byte of the referenced object. */ | ||||
598 | offset_int endoff; | ||||
599 | |||||
600 | /* The bounds need not be ordered. Set HIB to use as the index | ||||
601 | of the larger of the bounds and LOB as the opposite. */ | ||||
602 | bool hib = wi::les_p (offrng[0], offrng[1]); | ||||
603 | bool lob = !hib; | ||||
604 | |||||
605 | /* Set to the size remaining in the object after subtracting | ||||
606 | REFOFF. It may become negative as a result of negative indices | ||||
607 | into the enclosing object, such as in: | ||||
608 | extern struct S { char a[4], b[3], c[1]; } *p; | ||||
609 | strcpy (p[-3].b, "123"); */ | ||||
610 | offset_int size = basesize; | ||||
611 | tree obj = base; | ||||
612 | |||||
613 | const bool decl_p = DECL_P (obj)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (obj)->base.code))] == tcc_declaration); | ||||
614 | |||||
615 | if (basesize < 0) | ||||
616 | { | ||||
617 | endoff = offrng[lob] + (sizrange[0] - wroff); | ||||
618 | |||||
619 | /* For a reference through a pointer to an object of unknown size | ||||
620 | all initial offsets are considered valid, positive as well as | ||||
621 | negative, since the pointer itself can point past the beginning | ||||
622 | of the object. However, the sum of the lower bound of the offset | ||||
623 | and that of the size must be less than or equal than PTRDIFF_MAX. */ | ||||
624 | if (endoff > maxobjsize) | ||||
625 | return error_mark_nodeglobal_trees[TI_ERROR_MARK]; | ||||
626 | |||||
627 | /* When the referenced subobject is known, the end offset must be | ||||
628 | within its bounds. Otherwise there is nothing to do. */ | ||||
629 | if (strict | ||||
630 | && !decl_p | ||||
631 | && ref | ||||
632 | && refsize >= 0 | ||||
633 | && TREE_CODE (ref)((enum tree_code) (ref)->base.code) == COMPONENT_REF) | ||||
634 | { | ||||
635 | /* If REFOFF is negative, SIZE will become negative here. */ | ||||
636 | size = refoff + refsize; | ||||
637 | obj = ref; | ||||
638 | } | ||||
639 | else | ||||
640 | return NULL_TREE(tree) __null; | ||||
641 | } | ||||
642 | |||||
643 | /* A reference to an object of known size must be within the bounds | ||||
644 | of either the base object or the subobject (see above for when | ||||
645 | a subobject can be used). */ | ||||
646 | if ((decl_p && offrng[hib] < 0) || offrng[lob] > size) | ||||
647 | return obj; | ||||
648 | |||||
649 | /* The extent of the reference must also be within the bounds of | ||||
650 | the base object (if known) or the subobject or the maximum object | ||||
651 | size otherwise. */ | ||||
652 | endoff = offrng[lob] + sizrange[0]; | ||||
653 | if (endoff > maxobjsize) | ||||
654 | return error_mark_nodeglobal_trees[TI_ERROR_MARK]; | ||||
655 | |||||
656 | if (strict | ||||
657 | && decl_p | ||||
658 | && ref | ||||
659 | && refsize >= 0 | ||||
660 | && TREE_CODE (ref)((enum tree_code) (ref)->base.code) == COMPONENT_REF) | ||||
661 | { | ||||
662 | /* If the reference is to a member subobject of a declared object, | ||||
663 | the offset must be within the bounds of the subobject. */ | ||||
664 | size = refoff + refsize; | ||||
665 | obj = ref; | ||||
666 | } | ||||
667 | |||||
668 | if (endoff <= size) | ||||
669 | return NULL_TREE(tree) __null; | ||||
670 | |||||
671 | /* Set the out-of-bounds offset range to be one greater than | ||||
672 | that delimited by the reference including its size. */ | ||||
673 | ooboff[lob] = size; | ||||
674 | |||||
675 | if (endoff > ooboff[lob]) | ||||
676 | ooboff[hib] = endoff - 1; | ||||
677 | else | ||||
678 | ooboff[hib] = offrng[lob] + sizrange[1]; | ||||
679 | |||||
680 | return obj; | ||||
681 | } | ||||
682 | |||||
683 | /* Create an association between the memory references DST and SRC | ||||
684 | for access by a call EXPR to a memory or string built-in funtion. */ | ||||
685 | |||||
686 | builtin_access::builtin_access (pointer_query &ptrqry, gimple *call, | ||||
687 | builtin_memref &dst, | ||||
688 | builtin_memref &src) | ||||
689 | : dstref (&dst), srcref (&src), sizrange (), ovloff (), ovlsiz (), | ||||
690 | dstoff (), srcoff (), dstsiz (), srcsiz () | ||||
691 | { | ||||
692 | dstoff[0] = dst.offrange[0]; | ||||
693 | dstoff[1] = dst.offrange[1]; | ||||
694 | |||||
695 | /* Zero out since the offset_int ctors invoked above are no-op. */ | ||||
696 | srcoff[0] = srcoff[1] = 0; | ||||
697 | dstsiz[0] = dstsiz[1] = 0; | ||||
698 | srcsiz[0] = srcsiz[1] = 0; | ||||
699 | |||||
700 | /* Object Size Type to use to determine the size of the destination | ||||
701 | and source objects. Overridden below for raw memory functions. */ | ||||
702 | int ostype = 1; | ||||
703 | |||||
704 | /* True when the size of one reference depends on the offset of | ||||
705 | itself or the other. */ | ||||
706 | bool depends_p = true; | ||||
707 | |||||
708 | /* True when the size of the destination reference DSTREF has been | ||||
709 | determined from SRCREF and so needs to be adjusted by the latter's | ||||
710 | offset. Only meaningful for bounded string functions like strncpy. */ | ||||
711 | bool dstadjust_p = false; | ||||
712 | |||||
713 | /* The size argument number (depends on the built-in). */ | ||||
714 | unsigned sizeargno = 2; | ||||
715 | |||||
716 | tree func = gimple_call_fndecl (call); | ||||
717 | switch (DECL_FUNCTION_CODE (func)) | ||||
718 | { | ||||
719 | case BUILT_IN_MEMCPY: | ||||
720 | case BUILT_IN_MEMCPY_CHK: | ||||
721 | case BUILT_IN_MEMPCPY: | ||||
722 | case BUILT_IN_MEMPCPY_CHK: | ||||
723 | ostype = 0; | ||||
724 | depends_p = false; | ||||
725 | detect_overlap = &builtin_access::generic_overlap; | ||||
726 | break; | ||||
727 | |||||
728 | case BUILT_IN_MEMMOVE: | ||||
729 | case BUILT_IN_MEMMOVE_CHK: | ||||
730 | /* For memmove there is never any overlap to check for. */ | ||||
731 | ostype = 0; | ||||
732 | depends_p = false; | ||||
733 | detect_overlap = &builtin_access::no_overlap; | ||||
734 | break; | ||||
735 | |||||
736 | case BUILT_IN_MEMSET: | ||||
737 | case BUILT_IN_MEMSET_CHK: | ||||
738 | /* For memset there is never any overlap to check for. */ | ||||
739 | ostype = 0; | ||||
740 | depends_p = false; | ||||
741 | detect_overlap = &builtin_access::no_overlap; | ||||
742 | break; | ||||
743 | |||||
744 | case BUILT_IN_STPNCPY: | ||||
745 | case BUILT_IN_STPNCPY_CHK: | ||||
746 | case BUILT_IN_STRNCPY: | ||||
747 | case BUILT_IN_STRNCPY_CHK: | ||||
748 | dstref->strbounded_p = true; | ||||
749 | detect_overlap = &builtin_access::strcpy_overlap; | ||||
750 | break; | ||||
751 | |||||
752 | case BUILT_IN_STPCPY: | ||||
753 | case BUILT_IN_STPCPY_CHK: | ||||
754 | case BUILT_IN_STRCPY: | ||||
755 | case BUILT_IN_STRCPY_CHK: | ||||
756 | detect_overlap = &builtin_access::strcpy_overlap; | ||||
757 | break; | ||||
758 | |||||
759 | case BUILT_IN_STRCAT: | ||||
760 | case BUILT_IN_STRCAT_CHK: | ||||
761 | detect_overlap = &builtin_access::strcat_overlap; | ||||
762 | break; | ||||
763 | |||||
764 | case BUILT_IN_STRNCAT: | ||||
765 | case BUILT_IN_STRNCAT_CHK: | ||||
766 | dstref->strbounded_p = true; | ||||
767 | srcref->strbounded_p = true; | ||||
768 | detect_overlap = &builtin_access::strcat_overlap; | ||||
769 | break; | ||||
770 | |||||
771 | default: | ||||
772 | /* Handle other string functions here whose access may need | ||||
773 | to be validated for in-bounds offsets and non-overlapping | ||||
774 | copies. */ | ||||
775 | return; | ||||
776 | } | ||||
777 | |||||
778 | /* Try to determine the size of the base object. compute_objsize | ||||
779 | expects a pointer so create one if BASE is a non-pointer object. */ | ||||
780 | if (dst.basesize < 0) | ||||
781 | { | ||||
782 | access_ref aref; | ||||
783 | if (ptrqry.get_ref (dst.base, call, &aref, ostype) && aref.base0) | ||||
784 | dst.basesize = aref.sizrng[1]; | ||||
785 | else | ||||
786 | dst.basesize = HOST_WIDE_INT_MIN(long) (1UL << (64 - 1)); | ||||
787 | } | ||||
788 | |||||
789 | if (src.base && src.basesize < 0) | ||||
790 | { | ||||
791 | access_ref aref; | ||||
792 | if (ptrqry.get_ref (src.base, call, &aref, ostype) && aref.base0) | ||||
793 | src.basesize = aref.sizrng[1]; | ||||
794 | else | ||||
795 | src.basesize = HOST_WIDE_INT_MIN(long) (1UL << (64 - 1)); | ||||
796 | } | ||||
797 | |||||
798 | const offset_int maxobjsize = dst.maxobjsize; | ||||
799 | |||||
800 | /* Make adjustments for references to the same object by string | ||||
801 | built-in functions to reflect the constraints imposed by | ||||
802 | the function. */ | ||||
803 | |||||
804 | /* For bounded string functions determine the range of the bound | ||||
805 | on the access. For others, the range stays unbounded. */ | ||||
806 | offset_int bounds[2] = { maxobjsize, maxobjsize }; | ||||
807 | if (dstref->strbounded_p) | ||||
808 | { | ||||
809 | unsigned nargs = gimple_call_num_args (call); | ||||
810 | if (nargs <= sizeargno) | ||||
811 | return; | ||||
812 | |||||
813 | tree size = gimple_call_arg (call, sizeargno); | ||||
814 | tree range[2]; | ||||
815 | if (get_size_range (ptrqry.rvals, size, call, range, true)) | ||||
816 | { | ||||
817 | bounds[0] = wi::to_offset (range[0]); | ||||
818 | bounds[1] = wi::to_offset (range[1]); | ||||
819 | } | ||||
820 | |||||
821 | /* If both references' size ranges are indeterminate use the last | ||||
822 | (size) argument from the function call as a substitute. This | ||||
823 | may only be necessary for strncpy (but not for memcpy where | ||||
824 | the size range would have been already determined this way). */ | ||||
825 | if (dstref->sizrange[0] == 0 && dstref->sizrange[1] == maxobjsize | ||||
826 | && srcref->sizrange[0] == 0 && srcref->sizrange[1] == maxobjsize) | ||||
827 | { | ||||
828 | dstref->sizrange[0] = bounds[0]; | ||||
829 | dstref->sizrange[1] = bounds[1]; | ||||
830 | } | ||||
831 | } | ||||
832 | |||||
833 | bool dstsize_set = false; | ||||
834 | /* The size range of one reference involving the same base object | ||||
835 | can be determined from the size range of the other reference. | ||||
836 | This makes it possible to compute accurate offsets for warnings | ||||
837 | involving functions like strcpy where the length of just one of | ||||
838 | the two arguments is known (determined by tree-ssa-strlen). */ | ||||
839 | if (dstref->sizrange[0] == 0 && dstref->sizrange[1] == maxobjsize) | ||||
840 | { | ||||
841 | /* When the destination size is unknown set it to the size of | ||||
842 | the source. */ | ||||
843 | dstref->sizrange[0] = srcref->sizrange[0]; | ||||
844 | dstref->sizrange[1] = srcref->sizrange[1]; | ||||
845 | dstsize_set = true; | ||||
846 | } | ||||
847 | else if (srcref->sizrange[0] == 0 && srcref->sizrange[1] == maxobjsize) | ||||
848 | { | ||||
849 | /* When the size of the source access is unknown set it to the size | ||||
850 | of the destination first and adjust it later if necessary. */ | ||||
851 | srcref->sizrange[0] = dstref->sizrange[0]; | ||||
852 | srcref->sizrange[1] = dstref->sizrange[1]; | ||||
853 | |||||
854 | if (depends_p) | ||||
855 | { | ||||
856 | if (dstref->strbounded_p) | ||||
857 | { | ||||
858 | /* Read access by strncpy is constrained by the third | ||||
859 | argument but except for a zero bound is at least one. */ | ||||
860 | srcref->sizrange[0] = bounds[1] > 0 ? 1 : 0; | ||||
861 | offset_int bound = wi::umin (srcref->basesize, bounds[1]); | ||||
862 | if (bound < srcref->sizrange[1]) | ||||
863 | srcref->sizrange[1] = bound; | ||||
864 | } | ||||
865 | /* For string functions, adjust the size range of the source | ||||
866 | reference by the inverse boundaries of the offset (because | ||||
867 | the higher the offset into the string the shorter its | ||||
868 | length). */ | ||||
869 | if (srcref->offrange[1] >= 0 | ||||
870 | && srcref->offrange[1] < srcref->sizrange[0]) | ||||
871 | srcref->sizrange[0] -= srcref->offrange[1]; | ||||
872 | else | ||||
873 | srcref->sizrange[0] = 1; | ||||
874 | |||||
875 | if (srcref->offrange[0] > 0) | ||||
876 | { | ||||
877 | if (srcref->offrange[0] < srcref->sizrange[1]) | ||||
878 | srcref->sizrange[1] -= srcref->offrange[0]; | ||||
879 | else | ||||
880 | srcref->sizrange[1] = 0; | ||||
881 | } | ||||
882 | |||||
883 | dstadjust_p = true; | ||||
884 | } | ||||
885 | } | ||||
886 | |||||
887 | if (detect_overlap == &builtin_access::generic_overlap) | ||||
888 | { | ||||
889 | if (dstref->strbounded_p) | ||||
890 | { | ||||
891 | dstref->sizrange[0] = bounds[0]; | ||||
892 | dstref->sizrange[1] = bounds[1]; | ||||
893 | |||||
894 | if (dstref->sizrange[0] < srcref->sizrange[0]) | ||||
895 | srcref->sizrange[0] = dstref->sizrange[0]; | ||||
896 | |||||
897 | if (dstref->sizrange[1] < srcref->sizrange[1]) | ||||
898 | srcref->sizrange[1] = dstref->sizrange[1]; | ||||
899 | } | ||||
900 | } | ||||
901 | else if (detect_overlap == &builtin_access::strcpy_overlap) | ||||
902 | { | ||||
903 | if (!dstref->strbounded_p) | ||||
904 | { | ||||
905 | /* For strcpy, adjust the destination size range to match that | ||||
906 | of the source computed above. */ | ||||
907 | if (depends_p && dstadjust_p) | ||||
908 | { | ||||
909 | dstref->sizrange[0] = srcref->sizrange[0]; | ||||
910 | dstref->sizrange[1] = srcref->sizrange[1]; | ||||
911 | } | ||||
912 | } | ||||
913 | } | ||||
914 | else if (!dstsize_set && detect_overlap == &builtin_access::strcat_overlap) | ||||
915 | { | ||||
916 | dstref->sizrange[0] += srcref->sizrange[0] - 1; | ||||
917 | dstref->sizrange[1] += srcref->sizrange[1] - 1; | ||||
918 | } | ||||
919 | |||||
920 | if (dstref->strbounded_p) | ||||
921 | { | ||||
922 | /* For strncpy, adjust the destination size range to match that | ||||
923 | of the source computed above. */ | ||||
924 | dstref->sizrange[0] = bounds[0]; | ||||
925 | dstref->sizrange[1] = bounds[1]; | ||||
926 | |||||
927 | if (bounds[0] < srcref->sizrange[0]) | ||||
928 | srcref->sizrange[0] = bounds[0]; | ||||
929 | |||||
930 | if (bounds[1] < srcref->sizrange[1]) | ||||
931 | srcref->sizrange[1] = bounds[1]; | ||||
932 | } | ||||
933 | } | ||||
934 | |||||
935 | offset_int | ||||
936 | builtin_access::overlap_size (const offset_int a[2], const offset_int b[2], | ||||
937 | offset_int *off) | ||||
938 | { | ||||
939 | const offset_int *p = a; | ||||
940 | const offset_int *q = b; | ||||
941 | |||||
942 | /* Point P at the bigger of the two ranges and Q at the smaller. */ | ||||
943 | if (wi::lts_p (a[1] - a[0], b[1] - b[0])) | ||||
944 | { | ||||
945 | p = b; | ||||
946 | q = a; | ||||
947 | } | ||||
948 | |||||
949 | if (p[0] < q[0]) | ||||
950 | { | ||||
951 | if (p[1] < q[0]) | ||||
952 | return 0; | ||||
953 | |||||
954 | *off = q[0]; | ||||
955 | return wi::smin (p[1], q[1]) - q[0]; | ||||
956 | } | ||||
957 | |||||
958 | if (q[1] < p[0]) | ||||
959 | return 0; | ||||
960 | |||||
961 | off[0] = p[0]; | ||||
962 | return q[1] - p[0]; | ||||
963 | } | ||||
964 | |||||
965 | /* Return true if the bounded mempry (memcpy amd similar) or string function | ||||
966 | access (strncpy and similar) ACS overlaps. */ | ||||
967 | |||||
968 | bool | ||||
969 | builtin_access::generic_overlap () | ||||
970 | { | ||||
971 | builtin_access &acs = *this; | ||||
972 | const builtin_memref *dstref = acs.dstref; | ||||
973 | const builtin_memref *srcref = acs.srcref; | ||||
974 | |||||
975 | gcc_assert (dstref->base == srcref->base)((void)(!(dstref->base == srcref->base) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 975, __FUNCTION__), 0 : 0)); | ||||
976 | |||||
977 | const offset_int maxobjsize = acs.dstref->maxobjsize; | ||||
978 | |||||
979 | offset_int maxsize = dstref->basesize < 0 ? maxobjsize : dstref->basesize; | ||||
980 | |||||
981 | /* Adjust the larger bounds of the offsets (which may be the first | ||||
982 | element if the lower bound is larger than the upper bound) to | ||||
983 | make them valid for the smallest access (if possible) but no smaller | ||||
984 | than the smaller bounds. */ | ||||
985 | gcc_assert (wi::les_p (acs.dstoff[0], acs.dstoff[1]))((void)(!(wi::les_p (acs.dstoff[0], acs.dstoff[1])) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 985, __FUNCTION__), 0 : 0)); | ||||
986 | |||||
987 | if (maxsize < acs.dstoff[1] + acs.dstsiz[0]) | ||||
988 | acs.dstoff[1] = maxsize - acs.dstsiz[0]; | ||||
989 | if (acs.dstoff[1] < acs.dstoff[0]) | ||||
990 | acs.dstoff[1] = acs.dstoff[0]; | ||||
991 | |||||
992 | gcc_assert (wi::les_p (acs.srcoff[0], acs.srcoff[1]))((void)(!(wi::les_p (acs.srcoff[0], acs.srcoff[1])) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 992, __FUNCTION__), 0 : 0)); | ||||
993 | |||||
994 | if (maxsize < acs.srcoff[1] + acs.srcsiz[0]) | ||||
995 | acs.srcoff[1] = maxsize - acs.srcsiz[0]; | ||||
996 | if (acs.srcoff[1] < acs.srcoff[0]) | ||||
997 | acs.srcoff[1] = acs.srcoff[0]; | ||||
998 | |||||
999 | /* Determine the minimum and maximum space for the access given | ||||
1000 | the offsets. */ | ||||
1001 | offset_int space[2]; | ||||
1002 | space[0] = wi::abs (acs.dstoff[0] - acs.srcoff[0]); | ||||
1003 | space[1] = space[0]; | ||||
1004 | |||||
1005 | offset_int d = wi::abs (acs.dstoff[0] - acs.srcoff[1]); | ||||
1006 | if (acs.srcsiz[0] > 0) | ||||
1007 | { | ||||
1008 | if (d < space[0]) | ||||
1009 | space[0] = d; | ||||
1010 | |||||
1011 | if (space[1] < d) | ||||
1012 | space[1] = d; | ||||
1013 | } | ||||
1014 | else | ||||
1015 | space[1] = acs.dstsiz[1]; | ||||
1016 | |||||
1017 | d = wi::abs (acs.dstoff[1] - acs.srcoff[0]); | ||||
1018 | if (d < space[0]) | ||||
1019 | space[0] = d; | ||||
1020 | |||||
1021 | if (space[1] < d) | ||||
1022 | space[1] = d; | ||||
1023 | |||||
1024 | /* Treat raw memory functions both of whose references are bounded | ||||
1025 | as special and permit uncertain overlaps to go undetected. For | ||||
1026 | all kinds of constant offset and constant size accesses, if | ||||
1027 | overlap isn't certain it is not possible. */ | ||||
1028 | bool overlap_possible = space[0] < acs.dstsiz[1]; | ||||
1029 | if (!overlap_possible) | ||||
1030 | return false; | ||||
1031 | |||||
1032 | bool overlap_certain = space[1] < acs.dstsiz[0]; | ||||
1033 | |||||
1034 | /* True when the size of one reference depends on the offset of | ||||
1035 | the other. */ | ||||
1036 | bool depends_p = detect_overlap != &builtin_access::generic_overlap; | ||||
1037 | |||||
1038 | if (!overlap_certain) | ||||
1039 | { | ||||
1040 | if (!dstref->strbounded_p && !depends_p) | ||||
1041 | /* Memcpy only considers certain overlap. */ | ||||
1042 | return false; | ||||
1043 | |||||
1044 | /* There's no way to distinguish an access to the same member | ||||
1045 | of a structure from one to two distinct members of the same | ||||
1046 | structure. Give up to avoid excessive false positives. */ | ||||
1047 | tree basetype = TREE_TYPE (dstref->base)((contains_struct_check ((dstref->base), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1047, __FUNCTION__))->typed.type); | ||||
1048 | |||||
1049 | if (POINTER_TYPE_P (basetype)(((enum tree_code) (basetype)->base.code) == POINTER_TYPE || ((enum tree_code) (basetype)->base.code) == REFERENCE_TYPE )) | ||||
1050 | basetype = TREE_TYPE (basetype)((contains_struct_check ((basetype), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1050, __FUNCTION__))->typed.type); | ||||
1051 | else | ||||
1052 | while (TREE_CODE (basetype)((enum tree_code) (basetype)->base.code) == ARRAY_TYPE) | ||||
1053 | basetype = TREE_TYPE (basetype)((contains_struct_check ((basetype), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1053, __FUNCTION__))->typed.type); | ||||
1054 | |||||
1055 | if (RECORD_OR_UNION_TYPE_P (basetype)(((enum tree_code) (basetype)->base.code) == RECORD_TYPE || ((enum tree_code) (basetype)->base.code) == UNION_TYPE || ((enum tree_code) (basetype)->base.code) == QUAL_UNION_TYPE )) | ||||
1056 | return false; | ||||
1057 | } | ||||
1058 | |||||
1059 | /* True for stpcpy and strcpy. */ | ||||
1060 | bool stxcpy_p = (!dstref->strbounded_p | ||||
1061 | && detect_overlap == &builtin_access::strcpy_overlap); | ||||
1062 | |||||
1063 | if (dstref->refoff >= 0 | ||||
1064 | && srcref->refoff >= 0 | ||||
1065 | && dstref->refoff != srcref->refoff | ||||
1066 | && (stxcpy_p || dstref->strbounded_p || srcref->strbounded_p)) | ||||
1067 | return false; | ||||
1068 | |||||
1069 | offset_int siz[2] = { maxobjsize + 1, 0 }; | ||||
1070 | |||||
1071 | ovloff[0] = HOST_WIDE_INT_MAX(~((long) (1UL << (64 - 1)))); | ||||
1072 | ovloff[1] = HOST_WIDE_INT_MIN(long) (1UL << (64 - 1)); | ||||
1073 | |||||
1074 | if (stxcpy_p) | ||||
1075 | { | ||||
1076 | /* Iterate over the extreme locations (on the horizontal axis formed | ||||
1077 | by their offsets) and sizes of two regions and find their smallest | ||||
1078 | and largest overlap and the corresponding offsets. */ | ||||
1079 | for (unsigned i = 0; i != 2; ++i) | ||||
1080 | { | ||||
1081 | const offset_int a[2] = { | ||||
1082 | acs.dstoff[i], acs.dstoff[i] + acs.dstsiz[!i] | ||||
1083 | }; | ||||
1084 | |||||
1085 | const offset_int b[2] = { | ||||
1086 | acs.srcoff[i], acs.srcoff[i] + acs.srcsiz[!i] | ||||
1087 | }; | ||||
1088 | |||||
1089 | offset_int off; | ||||
1090 | offset_int sz = overlap_size (a, b, &off); | ||||
1091 | if (sz < siz[0]) | ||||
1092 | siz[0] = sz; | ||||
1093 | |||||
1094 | if (siz[1] <= sz) | ||||
1095 | siz[1] = sz; | ||||
1096 | |||||
1097 | if (sz != 0) | ||||
1098 | { | ||||
1099 | if (wi::lts_p (off, ovloff[0])) | ||||
1100 | ovloff[0] = off.to_shwi (); | ||||
1101 | if (wi::lts_p (ovloff[1], off)) | ||||
1102 | ovloff[1] = off.to_shwi (); | ||||
1103 | } | ||||
1104 | } | ||||
1105 | } | ||||
1106 | else | ||||
1107 | { | ||||
1108 | /* Iterate over the extreme locations (on the horizontal axis | ||||
1109 | formed by their offsets) and sizes of the two regions and | ||||
1110 | find their smallest and largest overlap and the corresponding | ||||
1111 | offsets. */ | ||||
1112 | |||||
1113 | for (unsigned io = 0; io != 2; ++io) | ||||
1114 | for (unsigned is = 0; is != 2; ++is) | ||||
1115 | { | ||||
1116 | const offset_int a[2] = { | ||||
1117 | acs.dstoff[io], acs.dstoff[io] + acs.dstsiz[is] | ||||
1118 | }; | ||||
1119 | |||||
1120 | for (unsigned jo = 0; jo != 2; ++jo) | ||||
1121 | for (unsigned js = 0; js != 2; ++js) | ||||
1122 | { | ||||
1123 | const offset_int b[2] = { | ||||
1124 | acs.srcoff[jo], acs.srcoff[jo] + acs.srcsiz[js] | ||||
1125 | }; | ||||
1126 | |||||
1127 | offset_int off; | ||||
1128 | offset_int sz = overlap_size (a, b, &off); | ||||
1129 | if (sz < siz[0]) | ||||
1130 | siz[0] = sz; | ||||
1131 | |||||
1132 | if (siz[1] <= sz) | ||||
1133 | siz[1] = sz; | ||||
1134 | |||||
1135 | if (sz != 0) | ||||
1136 | { | ||||
1137 | if (wi::lts_p (off, ovloff[0])) | ||||
1138 | ovloff[0] = off.to_shwi (); | ||||
1139 | if (wi::lts_p (ovloff[1], off)) | ||||
1140 | ovloff[1] = off.to_shwi (); | ||||
1141 | } | ||||
1142 | } | ||||
1143 | } | ||||
1144 | } | ||||
1145 | |||||
1146 | ovlsiz[0] = siz[0].to_shwi (); | ||||
1147 | ovlsiz[1] = siz[1].to_shwi (); | ||||
1148 | |||||
1149 | /* Adjust the overlap offset range to reflect the overlap size range. */ | ||||
1150 | if (ovlsiz[0] == 0 && ovlsiz[1] > 1) | ||||
1151 | ovloff[1] = ovloff[0] + ovlsiz[1] - 1; | ||||
1152 | |||||
1153 | return true; | ||||
1154 | } | ||||
1155 | |||||
1156 | /* Return true if the strcat-like access overlaps. */ | ||||
1157 | |||||
1158 | bool | ||||
1159 | builtin_access::strcat_overlap () | ||||
1160 | { | ||||
1161 | builtin_access &acs = *this; | ||||
1162 | const builtin_memref *dstref = acs.dstref; | ||||
1163 | const builtin_memref *srcref = acs.srcref; | ||||
1164 | |||||
1165 | gcc_assert (dstref->base == srcref->base)((void)(!(dstref->base == srcref->base) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1165, __FUNCTION__), 0 : 0)); | ||||
1166 | |||||
1167 | const offset_int maxobjsize = acs.dstref->maxobjsize; | ||||
1168 | |||||
1169 | gcc_assert (dstref->base && dstref->base == srcref->base)((void)(!(dstref->base && dstref->base == srcref ->base) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1169, __FUNCTION__), 0 : 0)); | ||||
1170 | |||||
1171 | /* Adjust for strcat-like accesses. */ | ||||
1172 | |||||
1173 | /* As a special case for strcat, set the DSTREF offsets to the length | ||||
1174 | of the destination string since the function starts writing over | ||||
1175 | its terminating nul, and set the destination size to 1 for the length | ||||
1176 | of the nul. */ | ||||
1177 | acs.dstoff[0] += dstsiz[0] - srcref->sizrange[0]; | ||||
1178 | acs.dstoff[1] += dstsiz[1] - srcref->sizrange[1]; | ||||
1179 | |||||
1180 | bool strfunc_unknown_args = acs.dstsiz[0] == 0 && acs.dstsiz[1] != 0; | ||||
1181 | |||||
1182 | /* The lower bound is zero when the size is unknown because then | ||||
1183 | overlap is not certain. */ | ||||
1184 | acs.dstsiz[0] = strfunc_unknown_args ? 0 : 1; | ||||
1185 | acs.dstsiz[1] = 1; | ||||
1186 | |||||
1187 | offset_int maxsize = dstref->basesize < 0 ? maxobjsize : dstref->basesize; | ||||
1188 | |||||
1189 | /* For references to the same base object, determine if there's a pair | ||||
1190 | of valid offsets into the two references such that access between | ||||
1191 | them doesn't overlap. Adjust both upper bounds to be valid for | ||||
1192 | the smaller size (i.e., at most MAXSIZE - SIZE). */ | ||||
1193 | |||||
1194 | if (maxsize < acs.dstoff[1] + acs.dstsiz[0]) | ||||
1195 | acs.dstoff[1] = maxsize - acs.dstsiz[0]; | ||||
1196 | |||||
1197 | if (maxsize < acs.srcoff[1] + acs.srcsiz[0]) | ||||
1198 | acs.srcoff[1] = maxsize - acs.srcsiz[0]; | ||||
1199 | |||||
1200 | /* Check to see if there's enough space for both accesses without | ||||
1201 | overlap. Determine the optimistic (maximum) amount of available | ||||
1202 | space. */ | ||||
1203 | offset_int space; | ||||
1204 | if (acs.dstoff[0] <= acs.srcoff[0]) | ||||
1205 | { | ||||
1206 | if (acs.dstoff[1] < acs.srcoff[1]) | ||||
1207 | space = acs.srcoff[1] + acs.srcsiz[0] - acs.dstoff[0]; | ||||
1208 | else | ||||
1209 | space = acs.dstoff[1] + acs.dstsiz[0] - acs.srcoff[0]; | ||||
1210 | } | ||||
1211 | else | ||||
1212 | space = acs.dstoff[1] + acs.dstsiz[0] - acs.srcoff[0]; | ||||
1213 | |||||
1214 | /* Overlap is certain if the distance between the farthest offsets | ||||
1215 | of the opposite accesses is less than the sum of the lower bounds | ||||
1216 | of the sizes of the two accesses. */ | ||||
1217 | bool overlap_certain = space < acs.dstsiz[0] + acs.srcsiz[0]; | ||||
1218 | |||||
1219 | /* For a constant-offset, constant size access, consider the largest | ||||
1220 | distance between the offset bounds and the lower bound of the access | ||||
1221 | size. If the overlap isn't certain return success. */ | ||||
1222 | if (!overlap_certain | ||||
1223 | && acs.dstoff[0] == acs.dstoff[1] | ||||
1224 | && acs.srcoff[0] == acs.srcoff[1] | ||||
1225 | && acs.dstsiz[0] == acs.dstsiz[1] | ||||
1226 | && acs.srcsiz[0] == acs.srcsiz[1]) | ||||
1227 | return false; | ||||
1228 | |||||
1229 | /* Overlap is not certain but may be possible. */ | ||||
1230 | |||||
1231 | offset_int access_min = acs.dstsiz[0] + acs.srcsiz[0]; | ||||
1232 | |||||
1233 | /* Determine the conservative (minimum) amount of space. */ | ||||
1234 | space = wi::abs (acs.dstoff[0] - acs.srcoff[0]); | ||||
1235 | offset_int d = wi::abs (acs.dstoff[0] - acs.srcoff[1]); | ||||
1236 | if (d < space) | ||||
1237 | space = d; | ||||
1238 | d = wi::abs (acs.dstoff[1] - acs.srcoff[0]); | ||||
1239 | if (d < space) | ||||
1240 | space = d; | ||||
1241 | |||||
1242 | /* For a strict test (used for strcpy and similar with unknown or | ||||
1243 | variable bounds or sizes), consider the smallest distance between | ||||
1244 | the offset bounds and either the upper bound of the access size | ||||
1245 | if known, or the lower bound otherwise. */ | ||||
1246 | if (access_min <= space && (access_min != 0 || !strfunc_unknown_args)) | ||||
1247 | return false; | ||||
1248 | |||||
1249 | /* When strcat overlap is certain it is always a single byte: | ||||
1250 | the terminating NUL, regardless of offsets and sizes. When | ||||
1251 | overlap is only possible its range is [0, 1]. */ | ||||
1252 | acs.ovlsiz[0] = dstref->sizrange[0] == dstref->sizrange[1] ? 1 : 0; | ||||
1253 | acs.ovlsiz[1] = 1; | ||||
1254 | |||||
1255 | offset_int endoff | ||||
1256 | = dstref->offrange[0] + (dstref->sizrange[0] - srcref->sizrange[0]); | ||||
1257 | if (endoff <= srcref->offrange[0]) | ||||
1258 | acs.ovloff[0] = wi::smin (maxobjsize, srcref->offrange[0]).to_shwi (); | ||||
1259 | else | ||||
1260 | acs.ovloff[0] = wi::smin (maxobjsize, endoff).to_shwi (); | ||||
1261 | |||||
1262 | acs.sizrange[0] = wi::smax (wi::abs (endoff - srcref->offrange[0]) + 1, | ||||
1263 | srcref->sizrange[0]).to_shwi (); | ||||
1264 | if (dstref->offrange[0] == dstref->offrange[1]) | ||||
1265 | { | ||||
1266 | if (srcref->offrange[0] == srcref->offrange[1]) | ||||
1267 | acs.ovloff[1] = acs.ovloff[0]; | ||||
1268 | else | ||||
1269 | acs.ovloff[1] | ||||
1270 | = wi::smin (maxobjsize, | ||||
1271 | srcref->offrange[1] + srcref->sizrange[1]).to_shwi (); | ||||
1272 | } | ||||
1273 | else | ||||
1274 | acs.ovloff[1] | ||||
1275 | = wi::smin (maxobjsize, | ||||
1276 | dstref->offrange[1] + dstref->sizrange[1]).to_shwi (); | ||||
1277 | |||||
1278 | if (acs.sizrange[0] == 0) | ||||
1279 | acs.sizrange[0] = 1; | ||||
1280 | acs.sizrange[1] = wi::smax (acs.dstsiz[1], srcref->sizrange[1]).to_shwi (); | ||||
1281 | return true; | ||||
1282 | } | ||||
1283 | |||||
1284 | /* Return true if the strcpy-like access overlaps. */ | ||||
1285 | |||||
1286 | bool | ||||
1287 | builtin_access::strcpy_overlap () | ||||
1288 | { | ||||
1289 | return generic_overlap (); | ||||
1290 | } | ||||
1291 | |||||
1292 | /* For a BASE of array type, clamp REFOFF to at most [0, BASE_SIZE] | ||||
1293 | if known, or [0, MAXOBJSIZE] otherwise. */ | ||||
1294 | |||||
1295 | static void | ||||
1296 | clamp_offset (tree base, offset_int refoff[2], offset_int maxobjsize) | ||||
1297 | { | ||||
1298 | if (!base || TREE_CODE (TREE_TYPE (base))((enum tree_code) (((contains_struct_check ((base), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1298, __FUNCTION__))->typed.type))->base.code) != ARRAY_TYPE) | ||||
1299 | return; | ||||
1300 | |||||
1301 | if (refoff[0] < 0 && refoff[1] >= 0) | ||||
1302 | refoff[0] = 0; | ||||
1303 | |||||
1304 | if (refoff[1] < refoff[0]) | ||||
1305 | { | ||||
1306 | offset_int maxsize = maxobjsize; | ||||
1307 | if (tree size = TYPE_SIZE_UNIT (TREE_TYPE (base))((tree_class_check ((((contains_struct_check ((base), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1307, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1307, __FUNCTION__))->type_common.size_unit)) | ||||
1308 | maxsize = wi::to_offset (size); | ||||
1309 | |||||
1310 | refoff[1] = wi::umin (refoff[1], maxsize); | ||||
1311 | } | ||||
1312 | } | ||||
1313 | |||||
1314 | /* Return true if DSTREF and SRCREF describe accesses that either overlap | ||||
1315 | one another or that, in order not to overlap, would imply that the size | ||||
1316 | of the referenced object(s) exceeds the maximum size of an object. Set | ||||
1317 | Otherwise, if DSTREF and SRCREF do not definitely overlap (even though | ||||
1318 | they may overlap in a way that's not apparent from the available data), | ||||
1319 | return false. */ | ||||
1320 | |||||
1321 | bool | ||||
1322 | builtin_access::overlap () | ||||
1323 | { | ||||
1324 | builtin_access &acs = *this; | ||||
1325 | |||||
1326 | const offset_int maxobjsize = dstref->maxobjsize; | ||||
1327 | |||||
1328 | acs.sizrange[0] = wi::smax (dstref->sizrange[0], | ||||
1329 | srcref->sizrange[0]).to_shwi (); | ||||
1330 | acs.sizrange[1] = wi::smax (dstref->sizrange[1], | ||||
1331 | srcref->sizrange[1]).to_shwi (); | ||||
1332 | |||||
1333 | /* Check to see if the two references refer to regions that are | ||||
1334 | too large not to overlap in the address space (whose maximum | ||||
1335 | size is PTRDIFF_MAX). */ | ||||
1336 | offset_int size = dstref->sizrange[0] + srcref->sizrange[0]; | ||||
1337 | if (maxobjsize < size) | ||||
1338 | { | ||||
1339 | acs.ovloff[0] = (maxobjsize - dstref->sizrange[0]).to_shwi (); | ||||
1340 | acs.ovlsiz[0] = (size - maxobjsize).to_shwi (); | ||||
1341 | return true; | ||||
1342 | } | ||||
1343 | |||||
1344 | /* If both base objects aren't known return the maximum possible | ||||
1345 | offset that would make them not overlap. */ | ||||
1346 | if (!dstref->base || !srcref->base) | ||||
1347 | return false; | ||||
1348 | |||||
1349 | /* If the base object is an array adjust the bounds of the offset | ||||
1350 | to be non-negative and within the bounds of the array if possible. */ | ||||
1351 | clamp_offset (dstref->base, acs.dstoff, maxobjsize); | ||||
1352 | |||||
1353 | acs.srcoff[0] = srcref->offrange[0]; | ||||
1354 | acs.srcoff[1] = srcref->offrange[1]; | ||||
1355 | |||||
1356 | clamp_offset (srcref->base, acs.srcoff, maxobjsize); | ||||
1357 | |||||
1358 | /* When the upper bound of the offset is less than the lower bound | ||||
1359 | the former is the result of a negative offset being represented | ||||
1360 | as a large positive value or vice versa. The resulting range is | ||||
1361 | a union of two subranges: [MIN, UB] and [LB, MAX]. Since such | ||||
1362 | a union is not representable using the current data structure | ||||
1363 | replace it with the full range of offsets. */ | ||||
1364 | if (acs.dstoff[1] < acs.dstoff[0]) | ||||
1365 | { | ||||
1366 | acs.dstoff[0] = -maxobjsize - 1; | ||||
1367 | acs.dstoff[1] = maxobjsize; | ||||
1368 | } | ||||
1369 | |||||
1370 | /* Validate the offset and size of each reference on its own first. | ||||
1371 | This is independent of whether or not the base objects are the | ||||
1372 | same. Normally, this would have already been detected and | ||||
1373 | diagnosed by -Warray-bounds, unless it has been disabled. */ | ||||
1374 | offset_int maxoff = acs.dstoff[0] + dstref->sizrange[0]; | ||||
1375 | if (maxobjsize < maxoff) | ||||
1376 | { | ||||
1377 | acs.ovlsiz[0] = (maxoff - maxobjsize).to_shwi (); | ||||
1378 | acs.ovloff[0] = acs.dstoff[0].to_shwi () - acs.ovlsiz[0]; | ||||
1379 | return true; | ||||
1380 | } | ||||
1381 | |||||
1382 | /* Repeat the same as above but for the source offsets. */ | ||||
1383 | if (acs.srcoff[1] < acs.srcoff[0]) | ||||
1384 | { | ||||
1385 | acs.srcoff[0] = -maxobjsize - 1; | ||||
1386 | acs.srcoff[1] = maxobjsize; | ||||
1387 | } | ||||
1388 | |||||
1389 | maxoff = acs.srcoff[0] + srcref->sizrange[0]; | ||||
1390 | if (maxobjsize < maxoff) | ||||
1391 | { | ||||
1392 | acs.ovlsiz[0] = (maxoff - maxobjsize).to_shwi (); | ||||
1393 | acs.ovlsiz[1] = (acs.srcoff[0] + srcref->sizrange[1] | ||||
1394 | - maxobjsize).to_shwi (); | ||||
1395 | acs.ovloff[0] = acs.srcoff[0].to_shwi () - acs.ovlsiz[0]; | ||||
1396 | return true; | ||||
1397 | } | ||||
1398 | |||||
1399 | if (dstref->base != srcref->base) | ||||
1400 | return false; | ||||
1401 | |||||
1402 | acs.dstsiz[0] = dstref->sizrange[0]; | ||||
1403 | acs.dstsiz[1] = dstref->sizrange[1]; | ||||
1404 | |||||
1405 | acs.srcsiz[0] = srcref->sizrange[0]; | ||||
1406 | acs.srcsiz[1] = srcref->sizrange[1]; | ||||
1407 | |||||
1408 | /* Call the appropriate function to determine the overlap. */ | ||||
1409 | if ((this->*detect_overlap) ()) | ||||
1410 | { | ||||
1411 | if (!sizrange[1]) | ||||
1412 | { | ||||
1413 | /* Unless the access size range has already been set, do so here. */ | ||||
1414 | sizrange[0] = wi::smax (acs.dstsiz[0], srcref->sizrange[0]).to_shwi (); | ||||
1415 | sizrange[1] = wi::smax (acs.dstsiz[1], srcref->sizrange[1]).to_shwi (); | ||||
1416 | } | ||||
1417 | return true; | ||||
1418 | } | ||||
1419 | |||||
1420 | return false; | ||||
1421 | } | ||||
1422 | |||||
1423 | /* Attempt to detect and diagnose an overlapping copy in a call expression | ||||
1424 | EXPR involving an access ACS to a built-in memory or string function. | ||||
1425 | Return true when one has been detected, false otherwise. */ | ||||
1426 | |||||
1427 | static bool | ||||
1428 | maybe_diag_overlap (location_t loc, gimple *call, builtin_access &acs) | ||||
1429 | { | ||||
1430 | if (!acs.overlap ()) | ||||
1431 | return false; | ||||
1432 | |||||
1433 | if (warning_suppressed_p (call, OPT_Wrestrict)) | ||||
1434 | return true; | ||||
1435 | |||||
1436 | /* For convenience. */ | ||||
1437 | const builtin_memref &dstref = *acs.dstref; | ||||
1438 | const builtin_memref &srcref = *acs.srcref; | ||||
1439 | |||||
1440 | /* Determine the range of offsets and sizes of the overlap if it | ||||
1441 | exists and issue diagnostics. */ | ||||
1442 | HOST_WIDE_INTlong *ovloff = acs.ovloff; | ||||
1443 | HOST_WIDE_INTlong *ovlsiz = acs.ovlsiz; | ||||
1444 | HOST_WIDE_INTlong *sizrange = acs.sizrange; | ||||
1445 | |||||
1446 | tree func = gimple_call_fndecl (call); | ||||
1447 | |||||
1448 | /* To avoid a combinatorial explosion of diagnostics format the offsets | ||||
1449 | or their ranges as strings and use them in the warning calls below. */ | ||||
1450 | char offstr[3][64]; | ||||
1451 | |||||
1452 | if (dstref.offrange[0] == dstref.offrange[1] | ||||
1453 | || dstref.offrange[1] > HOST_WIDE_INT_MAX(~((long) (1UL << (64 - 1))))) | ||||
1454 | sprintf (offstr[0], HOST_WIDE_INT_PRINT_DEC"%" "l" "d", | ||||
1455 | dstref.offrange[0].to_shwi ()); | ||||
1456 | else | ||||
1457 | sprintf (offstr[0], | ||||
1458 | "[" HOST_WIDE_INT_PRINT_DEC"%" "l" "d" ", " HOST_WIDE_INT_PRINT_DEC"%" "l" "d" "]", | ||||
1459 | dstref.offrange[0].to_shwi (), | ||||
1460 | dstref.offrange[1].to_shwi ()); | ||||
1461 | |||||
1462 | if (srcref.offrange[0] == srcref.offrange[1] | ||||
1463 | || srcref.offrange[1] > HOST_WIDE_INT_MAX(~((long) (1UL << (64 - 1))))) | ||||
1464 | sprintf (offstr[1], | ||||
1465 | HOST_WIDE_INT_PRINT_DEC"%" "l" "d", | ||||
1466 | srcref.offrange[0].to_shwi ()); | ||||
1467 | else | ||||
1468 | sprintf (offstr[1], | ||||
1469 | "[" HOST_WIDE_INT_PRINT_DEC"%" "l" "d" ", " HOST_WIDE_INT_PRINT_DEC"%" "l" "d" "]", | ||||
1470 | srcref.offrange[0].to_shwi (), | ||||
1471 | srcref.offrange[1].to_shwi ()); | ||||
1472 | |||||
1473 | if (ovloff[0] == ovloff[1] || !ovloff[1]) | ||||
1474 | sprintf (offstr[2], HOST_WIDE_INT_PRINT_DEC"%" "l" "d", ovloff[0]); | ||||
1475 | else | ||||
1476 | sprintf (offstr[2], | ||||
1477 | "[" HOST_WIDE_INT_PRINT_DEC"%" "l" "d" ", " HOST_WIDE_INT_PRINT_DEC"%" "l" "d" "]", | ||||
1478 | ovloff[0], ovloff[1]); | ||||
1479 | |||||
1480 | const offset_int maxobjsize = dstref.maxobjsize; | ||||
1481 | bool must_overlap = ovlsiz[0] > 0; | ||||
1482 | |||||
1483 | if (ovlsiz[1] == 0) | ||||
1484 | ovlsiz[1] = ovlsiz[0]; | ||||
1485 | |||||
1486 | if (must_overlap) | ||||
1487 | { | ||||
1488 | /* Issue definitive "overlaps" diagnostic in this block. */ | ||||
1489 | |||||
1490 | if (sizrange[0] == sizrange[1]) | ||||
1491 | { | ||||
1492 | if (ovlsiz[0] == ovlsiz[1]) | ||||
1493 | warning_at (loc, OPT_Wrestrict, | ||||
1494 | sizrange[0] == 1 | ||||
1495 | ? (ovlsiz[0] == 1 | ||||
1496 | ? G_("%qD accessing %wu byte at offsets %s ""%qD accessing %wu byte at offsets %s " "and %s overlaps %wu byte at offset %s" | ||||
1497 | "and %s overlaps %wu byte at offset %s")"%qD accessing %wu byte at offsets %s " "and %s overlaps %wu byte at offset %s" | ||||
1498 | : G_("%qD accessing %wu byte at offsets %s ""%qD accessing %wu byte at offsets %s " "and %s overlaps %wu bytes at offset " "%s" | ||||
1499 | "and %s overlaps %wu bytes at offset ""%qD accessing %wu byte at offsets %s " "and %s overlaps %wu bytes at offset " "%s" | ||||
1500 | "%s")"%qD accessing %wu byte at offsets %s " "and %s overlaps %wu bytes at offset " "%s") | ||||
1501 | : (ovlsiz[0] == 1 | ||||
1502 | ? G_("%qD accessing %wu bytes at offsets %s ""%qD accessing %wu bytes at offsets %s " "and %s overlaps %wu byte at offset %s" | ||||
1503 | "and %s overlaps %wu byte at offset %s")"%qD accessing %wu bytes at offsets %s " "and %s overlaps %wu byte at offset %s" | ||||
1504 | : G_("%qD accessing %wu bytes at offsets %s ""%qD accessing %wu bytes at offsets %s " "and %s overlaps %wu bytes at offset " "%s" | ||||
1505 | "and %s overlaps %wu bytes at offset ""%qD accessing %wu bytes at offsets %s " "and %s overlaps %wu bytes at offset " "%s" | ||||
1506 | "%s")"%qD accessing %wu bytes at offsets %s " "and %s overlaps %wu bytes at offset " "%s"), | ||||
1507 | func, sizrange[0], | ||||
1508 | offstr[0], offstr[1], ovlsiz[0], offstr[2]); | ||||
1509 | else if (ovlsiz[1] >= 0 && ovlsiz[1] < maxobjsize.to_shwi ()) | ||||
1510 | warning_n (loc, OPT_Wrestrict, sizrange[0], | ||||
1511 | "%qD accessing %wu byte at offsets %s " | ||||
1512 | "and %s overlaps between %wu and %wu bytes " | ||||
1513 | "at offset %s", | ||||
1514 | "%qD accessing %wu bytes at offsets %s " | ||||
1515 | "and %s overlaps between %wu and %wu bytes " | ||||
1516 | "at offset %s", | ||||
1517 | func, sizrange[0], offstr[0], offstr[1], | ||||
1518 | ovlsiz[0], ovlsiz[1], offstr[2]); | ||||
1519 | else | ||||
1520 | warning_n (loc, OPT_Wrestrict, sizrange[0], | ||||
1521 | "%qD accessing %wu byte at offsets %s and " | ||||
1522 | "%s overlaps %wu or more bytes at offset %s", | ||||
1523 | "%qD accessing %wu bytes at offsets %s and " | ||||
1524 | "%s overlaps %wu or more bytes at offset %s", | ||||
1525 | func, sizrange[0], | ||||
1526 | offstr[0], offstr[1], ovlsiz[0], offstr[2]); | ||||
1527 | return true; | ||||
1528 | } | ||||
1529 | |||||
1530 | if (sizrange[1] >= 0 && sizrange[1] < maxobjsize.to_shwi ()) | ||||
1531 | { | ||||
1532 | if (ovlsiz[0] == ovlsiz[1]) | ||||
1533 | warning_n (loc, OPT_Wrestrict, ovlsiz[0], | ||||
1534 | "%qD accessing between %wu and %wu bytes " | ||||
1535 | "at offsets %s and %s overlaps %wu byte at " | ||||
1536 | "offset %s", | ||||
1537 | "%qD accessing between %wu and %wu bytes " | ||||
1538 | "at offsets %s and %s overlaps %wu bytes " | ||||
1539 | "at offset %s", | ||||
1540 | func, sizrange[0], sizrange[1], | ||||
1541 | offstr[0], offstr[1], ovlsiz[0], offstr[2]); | ||||
1542 | else if (ovlsiz[1] >= 0 && ovlsiz[1] < maxobjsize.to_shwi ()) | ||||
1543 | warning_at (loc, OPT_Wrestrict, | ||||
1544 | "%qD accessing between %wu and %wu bytes at " | ||||
1545 | "offsets %s and %s overlaps between %wu and %wu " | ||||
1546 | "bytes at offset %s", | ||||
1547 | func, sizrange[0], sizrange[1], | ||||
1548 | offstr[0], offstr[1], ovlsiz[0], ovlsiz[1], | ||||
1549 | offstr[2]); | ||||
1550 | else | ||||
1551 | warning_at (loc, OPT_Wrestrict, | ||||
1552 | "%qD accessing between %wu and %wu bytes at " | ||||
1553 | "offsets %s and %s overlaps %wu or more bytes " | ||||
1554 | "at offset %s", | ||||
1555 | func, sizrange[0], sizrange[1], | ||||
1556 | offstr[0], offstr[1], ovlsiz[0], offstr[2]); | ||||
1557 | return true; | ||||
1558 | } | ||||
1559 | |||||
1560 | if (ovlsiz[0] != ovlsiz[1]) | ||||
1561 | ovlsiz[1] = maxobjsize.to_shwi (); | ||||
1562 | |||||
1563 | if (ovlsiz[0] == ovlsiz[1]) | ||||
1564 | warning_n (loc, OPT_Wrestrict, ovlsiz[0], | ||||
1565 | "%qD accessing %wu or more bytes at offsets " | ||||
1566 | "%s and %s overlaps %wu byte at offset %s", | ||||
1567 | "%qD accessing %wu or more bytes at offsets " | ||||
1568 | "%s and %s overlaps %wu bytes at offset %s", | ||||
1569 | func, sizrange[0], offstr[0], offstr[1], | ||||
1570 | ovlsiz[0], offstr[2]); | ||||
1571 | else if (ovlsiz[1] >= 0 && ovlsiz[1] < maxobjsize.to_shwi ()) | ||||
1572 | warning_at (loc, OPT_Wrestrict, | ||||
1573 | "%qD accessing %wu or more bytes at offsets %s " | ||||
1574 | "and %s overlaps between %wu and %wu bytes " | ||||
1575 | "at offset %s", | ||||
1576 | func, sizrange[0], offstr[0], offstr[1], | ||||
1577 | ovlsiz[0], ovlsiz[1], offstr[2]); | ||||
1578 | else | ||||
1579 | warning_at (loc, OPT_Wrestrict, | ||||
1580 | "%qD accessing %wu or more bytes at offsets %s " | ||||
1581 | "and %s overlaps %wu or more bytes at offset %s", | ||||
1582 | func, sizrange[0], offstr[0], offstr[1], | ||||
1583 | ovlsiz[0], offstr[2]); | ||||
1584 | return true; | ||||
1585 | } | ||||
1586 | |||||
1587 | /* Use more concise wording when one of the offsets is unbounded | ||||
1588 | to avoid confusing the user with large and mostly meaningless | ||||
1589 | numbers. */ | ||||
1590 | bool open_range; | ||||
1591 | if (DECL_P (dstref.base)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (dstref.base)->base.code))] == tcc_declaration) && TREE_CODE (TREE_TYPE (dstref.base))((enum tree_code) (((contains_struct_check ((dstref.base), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1591, __FUNCTION__))->typed.type))->base.code) == ARRAY_TYPE) | ||||
1592 | open_range = ((dstref.offrange[0] == 0 | ||||
1593 | && dstref.offrange[1] == maxobjsize) | ||||
1594 | || (srcref.offrange[0] == 0 | ||||
1595 | && srcref.offrange[1] == maxobjsize)); | ||||
1596 | else | ||||
1597 | open_range = ((dstref.offrange[0] == -maxobjsize - 1 | ||||
1598 | && dstref.offrange[1] == maxobjsize) | ||||
1599 | || (srcref.offrange[0] == -maxobjsize - 1 | ||||
1600 | && srcref.offrange[1] == maxobjsize)); | ||||
1601 | |||||
1602 | if (sizrange[0] == sizrange[1] || sizrange[1] == 1) | ||||
1603 | { | ||||
1604 | if (ovlsiz[1] == 1) | ||||
1605 | { | ||||
1606 | if (open_range) | ||||
1607 | warning_n (loc, OPT_Wrestrict, sizrange[1], | ||||
1608 | "%qD accessing %wu byte may overlap " | ||||
1609 | "%wu byte", | ||||
1610 | "%qD accessing %wu bytes may overlap " | ||||
1611 | "%wu byte", | ||||
1612 | func, sizrange[1], ovlsiz[1]); | ||||
1613 | else | ||||
1614 | warning_n (loc, OPT_Wrestrict, sizrange[1], | ||||
1615 | "%qD accessing %wu byte at offsets %s " | ||||
1616 | "and %s may overlap %wu byte at offset %s", | ||||
1617 | "%qD accessing %wu bytes at offsets %s " | ||||
1618 | "and %s may overlap %wu byte at offset %s", | ||||
1619 | func, sizrange[1], offstr[0], offstr[1], | ||||
1620 | ovlsiz[1], offstr[2]); | ||||
1621 | return true; | ||||
1622 | } | ||||
1623 | |||||
1624 | if (open_range) | ||||
1625 | warning_n (loc, OPT_Wrestrict, sizrange[1], | ||||
1626 | "%qD accessing %wu byte may overlap " | ||||
1627 | "up to %wu bytes", | ||||
1628 | "%qD accessing %wu bytes may overlap " | ||||
1629 | "up to %wu bytes", | ||||
1630 | func, sizrange[1], ovlsiz[1]); | ||||
1631 | else | ||||
1632 | warning_n (loc, OPT_Wrestrict, sizrange[1], | ||||
1633 | "%qD accessing %wu byte at offsets %s and " | ||||
1634 | "%s may overlap up to %wu bytes at offset %s", | ||||
1635 | "%qD accessing %wu bytes at offsets %s and " | ||||
1636 | "%s may overlap up to %wu bytes at offset %s", | ||||
1637 | func, sizrange[1], offstr[0], offstr[1], | ||||
1638 | ovlsiz[1], offstr[2]); | ||||
1639 | return true; | ||||
1640 | } | ||||
1641 | |||||
1642 | if (sizrange[1] >= 0 && sizrange[1] < maxobjsize.to_shwi ()) | ||||
1643 | { | ||||
1644 | if (open_range) | ||||
1645 | warning_n (loc, OPT_Wrestrict, ovlsiz[1], | ||||
1646 | "%qD accessing between %wu and %wu bytes " | ||||
1647 | "may overlap %wu byte", | ||||
1648 | "%qD accessing between %wu and %wu bytes " | ||||
1649 | "may overlap up to %wu bytes", | ||||
1650 | func, sizrange[0], sizrange[1], ovlsiz[1]); | ||||
1651 | else | ||||
1652 | warning_n (loc, OPT_Wrestrict, ovlsiz[1], | ||||
1653 | "%qD accessing between %wu and %wu bytes " | ||||
1654 | "at offsets %s and %s may overlap %wu byte " | ||||
1655 | "at offset %s", | ||||
1656 | "%qD accessing between %wu and %wu bytes " | ||||
1657 | "at offsets %s and %s may overlap up to %wu " | ||||
1658 | "bytes at offset %s", | ||||
1659 | func, sizrange[0], sizrange[1], | ||||
1660 | offstr[0], offstr[1], ovlsiz[1], offstr[2]); | ||||
1661 | return true; | ||||
1662 | } | ||||
1663 | |||||
1664 | warning_n (loc, OPT_Wrestrict, ovlsiz[1], | ||||
1665 | "%qD accessing %wu or more bytes at offsets %s " | ||||
1666 | "and %s may overlap %wu byte at offset %s", | ||||
1667 | "%qD accessing %wu or more bytes at offsets %s " | ||||
1668 | "and %s may overlap up to %wu bytes at offset %s", | ||||
1669 | func, sizrange[0], offstr[0], offstr[1], | ||||
1670 | ovlsiz[1], offstr[2]); | ||||
1671 | |||||
1672 | return true; | ||||
1673 | } | ||||
1674 | |||||
1675 | /* Validate REF size and offsets in an expression passed as an argument | ||||
1676 | to a CALL to a built-in function FUNC to make sure they are within | ||||
1677 | the bounds of the referenced object if its size is known, or | ||||
1678 | PTRDIFF_MAX otherwise. DO_WARN is true when a diagnostic should | ||||
1679 | be issued, false otherwise. | ||||
1680 | Both initial values of the offsets and their final value computed | ||||
1681 | by the function by incrementing the initial value by the size are | ||||
1682 | validated. Return the warning number if the offsets are not valid | ||||
1683 | and a diagnostic has been issued, or would have been issued if | ||||
1684 | DO_WARN had been true, otherwise an invalid warning number. */ | ||||
1685 | |||||
1686 | static opt_code | ||||
1687 | maybe_diag_access_bounds (gimple *call, tree func, int strict, | ||||
1688 | const builtin_memref &ref, offset_int wroff, | ||||
1689 | bool do_warn) | ||||
1690 | { | ||||
1691 | location_t loc = gimple_location (call); | ||||
1692 | const offset_int maxobjsize = ref.maxobjsize; | ||||
1693 | |||||
1694 | /* Check for excessive size first and regardless of warning options | ||||
1695 | since the result is used to make codegen decisions. */ | ||||
1696 | if (ref.sizrange[0] > maxobjsize) | ||||
1697 | { | ||||
1698 | const opt_code opt = OPT_Wstringop_overflow_; | ||||
1699 | /* Return true without issuing a warning. */ | ||||
1700 | if (!do_warn) | ||||
1701 | return opt; | ||||
1702 | |||||
1703 | if (ref.ref && warning_suppressed_p (ref.ref, OPT_Wstringop_overflow_)) | ||||
1704 | return no_warning; | ||||
1705 | |||||
1706 | bool warned = false; | ||||
1707 | if (warn_stringop_overflowglobal_options.x_warn_stringop_overflow) | ||||
1708 | { | ||||
1709 | if (ref.sizrange[0] == ref.sizrange[1]) | ||||
1710 | warned = warning_at (loc, opt, | ||||
1711 | "%qD specified bound %wu " | ||||
1712 | "exceeds maximum object size %wu", | ||||
1713 | func, ref.sizrange[0].to_uhwi (), | ||||
1714 | maxobjsize.to_uhwi ()); | ||||
1715 | else | ||||
1716 | warned = warning_at (loc, opt, | ||||
1717 | "%qD specified bound between %wu and %wu " | ||||
1718 | "exceeds maximum object size %wu", | ||||
1719 | func, ref.sizrange[0].to_uhwi (), | ||||
1720 | ref.sizrange[1].to_uhwi (), | ||||
1721 | maxobjsize.to_uhwi ()); | ||||
1722 | return warned ? opt : no_warning; | ||||
1723 | } | ||||
1724 | } | ||||
1725 | |||||
1726 | /* Check for out-bounds pointers regardless of warning options since | ||||
1727 | the result is used to make codegen decisions. An excessive WROFF | ||||
1728 | can only come up as a result of an invalid strncat bound and is | ||||
1729 | diagnosed separately using a more meaningful warning. */ | ||||
1730 | if (maxobjsize < wroff) | ||||
1731 | wroff = 0; | ||||
1732 | offset_int ooboff[] = { ref.offrange[0], ref.offrange[1], wroff }; | ||||
1733 | tree oobref = ref.offset_out_of_bounds (strict, ooboff); | ||||
1734 | if (!oobref) | ||||
1735 | return no_warning; | ||||
1736 | |||||
1737 | const opt_code opt = OPT_Warray_bounds_; | ||||
1738 | /* Return true without issuing a warning. */ | ||||
1739 | if (!do_warn) | ||||
1740 | return opt; | ||||
1741 | |||||
1742 | if (!warn_array_boundsglobal_options.x_warn_array_bounds) | ||||
1743 | return no_warning; | ||||
1744 | |||||
1745 | if (warning_suppressed_p (ref.ptr, opt) | ||||
1746 | || (ref.ref && warning_suppressed_p (ref.ref, opt))) | ||||
1747 | return no_warning; | ||||
1748 | |||||
1749 | char rangestr[2][64]; | ||||
1750 | if (ooboff[0] == ooboff[1] | ||||
1751 | || (ooboff[0] != ref.offrange[0] | ||||
1752 | && ooboff[0].to_shwi () >= ooboff[1].to_shwi ())) | ||||
1753 | sprintf (rangestr[0], "%lli", (long long) ooboff[0].to_shwi ()); | ||||
1754 | else | ||||
1755 | sprintf (rangestr[0], "[%lli, %lli]", | ||||
1756 | (long long) ooboff[0].to_shwi (), | ||||
1757 | (long long) ooboff[1].to_shwi ()); | ||||
1758 | |||||
1759 | bool warned = false; | ||||
1760 | |||||
1761 | if (oobref == error_mark_nodeglobal_trees[TI_ERROR_MARK]) | ||||
1762 | { | ||||
1763 | if (ref.sizrange[0] == ref.sizrange[1]) | ||||
1764 | sprintf (rangestr[1], "%llu", | ||||
1765 | (unsigned long long) ref.sizrange[0].to_shwi ()); | ||||
1766 | else | ||||
1767 | sprintf (rangestr[1], "[%lli, %lli]", | ||||
1768 | (unsigned long long) ref.sizrange[0].to_uhwi (), | ||||
1769 | (unsigned long long) ref.sizrange[1].to_uhwi ()); | ||||
1770 | |||||
1771 | tree type; | ||||
1772 | |||||
1773 | if (DECL_P (ref.base)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (ref.base)->base.code))] == tcc_declaration) | ||||
1774 | && TREE_CODE (type = TREE_TYPE (ref.base))((enum tree_code) (type = ((contains_struct_check ((ref.base) , (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1774, __FUNCTION__))->typed.type))->base.code) == ARRAY_TYPE) | ||||
1775 | { | ||||
1776 | auto_diagnostic_group d; | ||||
1777 | if (warning_at (loc, opt, | ||||
1778 | "%qD pointer overflow between offset %s " | ||||
1779 | "and size %s accessing array %qD with type %qT", | ||||
1780 | func, rangestr[0], rangestr[1], ref.base, type)) | ||||
1781 | { | ||||
1782 | inform (DECL_SOURCE_LOCATION (ref.base)((contains_struct_check ((ref.base), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1782, __FUNCTION__))->decl_minimal.locus), | ||||
1783 | "array %qD declared here", ref.base); | ||||
1784 | warned = true; | ||||
1785 | } | ||||
1786 | else | ||||
1787 | warned = warning_at (loc, opt, | ||||
1788 | "%qD pointer overflow between offset %s " | ||||
1789 | "and size %s", | ||||
1790 | func, rangestr[0], rangestr[1]); | ||||
1791 | } | ||||
1792 | else | ||||
1793 | warned = warning_at (loc, opt, | ||||
1794 | "%qD pointer overflow between offset %s " | ||||
1795 | "and size %s", | ||||
1796 | func, rangestr[0], rangestr[1]); | ||||
1797 | } | ||||
1798 | else if (oobref == ref.base) | ||||
1799 | { | ||||
1800 | /* True when the offset formed by an access to the reference | ||||
1801 | is out of bounds, rather than the initial offset wich is | ||||
1802 | in bounds. This implies access past the end. */ | ||||
1803 | bool form = ooboff[0] != ref.offrange[0]; | ||||
1804 | |||||
1805 | if (DECL_P (ref.base)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (ref.base)->base.code))] == tcc_declaration)) | ||||
1806 | { | ||||
1807 | auto_diagnostic_group d; | ||||
1808 | if ((ref.basesize < maxobjsize | ||||
1809 | && warning_at (loc, opt, | ||||
1810 | form | ||||
1811 | ? G_("%qD forming offset %s is out of ""%qD forming offset %s is out of " "the bounds [0, %wu] of object %qD with " "type %qT" | ||||
1812 | "the bounds [0, %wu] of object %qD with ""%qD forming offset %s is out of " "the bounds [0, %wu] of object %qD with " "type %qT" | ||||
1813 | "type %qT")"%qD forming offset %s is out of " "the bounds [0, %wu] of object %qD with " "type %qT" | ||||
1814 | : G_("%qD offset %s is out of the bounds ""%qD offset %s is out of the bounds " "[0, %wu] of object %qD with type %qT" | ||||
1815 | "[0, %wu] of object %qD with type %qT")"%qD offset %s is out of the bounds " "[0, %wu] of object %qD with type %qT", | ||||
1816 | func, rangestr[0], ref.basesize.to_uhwi (), | ||||
1817 | ref.base, TREE_TYPE (ref.base)((contains_struct_check ((ref.base), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1817, __FUNCTION__))->typed.type))) | ||||
1818 | || warning_at (loc, opt, | ||||
1819 | form | ||||
1820 | ? G_("%qD forming offset %s is out of ""%qD forming offset %s is out of " "the bounds of object %qD with type %qT" | ||||
1821 | "the bounds of object %qD with type %qT")"%qD forming offset %s is out of " "the bounds of object %qD with type %qT" | ||||
1822 | : G_("%qD offset %s is out of the bounds ""%qD offset %s is out of the bounds " "of object %qD with type %qT" | ||||
1823 | "of object %qD with type %qT")"%qD offset %s is out of the bounds " "of object %qD with type %qT", | ||||
1824 | func, rangestr[0], | ||||
1825 | ref.base, TREE_TYPE (ref.base)((contains_struct_check ((ref.base), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1825, __FUNCTION__))->typed.type))) | ||||
1826 | { | ||||
1827 | inform (DECL_SOURCE_LOCATION (ref.base)((contains_struct_check ((ref.base), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1827, __FUNCTION__))->decl_minimal.locus), | ||||
1828 | "%qD declared here", ref.base); | ||||
1829 | warned = true; | ||||
1830 | } | ||||
1831 | } | ||||
1832 | else if (ref.basesize < maxobjsize) | ||||
1833 | warned = warning_at (loc, opt, | ||||
1834 | form | ||||
1835 | ? G_("%qD forming offset %s is out ""%qD forming offset %s is out " "of the bounds [0, %wu]" | ||||
1836 | "of the bounds [0, %wu]")"%qD forming offset %s is out " "of the bounds [0, %wu]" | ||||
1837 | : G_("%qD offset %s is out ""%qD offset %s is out " "of the bounds [0, %wu]" | ||||
1838 | "of the bounds [0, %wu]")"%qD offset %s is out " "of the bounds [0, %wu]", | ||||
1839 | func, rangestr[0], ref.basesize.to_uhwi ()); | ||||
1840 | else | ||||
1841 | warned = warning_at (loc, opt, | ||||
1842 | form | ||||
1843 | ? G_("%qD forming offset %s is out of bounds")"%qD forming offset %s is out of bounds" | ||||
1844 | : G_("%qD offset %s is out of bounds")"%qD offset %s is out of bounds", | ||||
1845 | func, rangestr[0]); | ||||
1846 | } | ||||
1847 | else if (TREE_CODE (ref.ref)((enum tree_code) (ref.ref)->base.code) == MEM_REF) | ||||
1848 | { | ||||
1849 | tree refop = TREE_OPERAND (ref.ref, 0)(*((const_cast<tree*> (tree_operand_check ((ref.ref), ( 0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1849, __FUNCTION__))))); | ||||
1850 | tree type = TREE_TYPE (refop)((contains_struct_check ((refop), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1850, __FUNCTION__))->typed.type); | ||||
1851 | if (POINTER_TYPE_P (type)(((enum tree_code) (type)->base.code) == POINTER_TYPE || ( (enum tree_code) (type)->base.code) == REFERENCE_TYPE)) | ||||
1852 | type = TREE_TYPE (type)((contains_struct_check ((type), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1852, __FUNCTION__))->typed.type); | ||||
1853 | type = TYPE_MAIN_VARIANT (type)((tree_class_check ((type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1853, __FUNCTION__))->type_common.main_variant); | ||||
1854 | |||||
1855 | if (warning_at (loc, opt, | ||||
1856 | "%qD offset %s from the object at %qE is out " | ||||
1857 | "of the bounds of %qT", | ||||
1858 | func, rangestr[0], ref.base, type)) | ||||
1859 | { | ||||
1860 | if (TREE_CODE (ref.ref)((enum tree_code) (ref.ref)->base.code) == COMPONENT_REF) | ||||
1861 | refop = TREE_OPERAND (ref.ref, 1)(*((const_cast<tree*> (tree_operand_check ((ref.ref), ( 1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1861, __FUNCTION__))))); | ||||
1862 | if (DECL_P (refop)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (refop)->base.code))] == tcc_declaration)) | ||||
1863 | inform (DECL_SOURCE_LOCATION (refop)((contains_struct_check ((refop), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1863, __FUNCTION__))->decl_minimal.locus), | ||||
1864 | "subobject %qD declared here", refop); | ||||
1865 | warned = true; | ||||
1866 | } | ||||
1867 | } | ||||
1868 | else | ||||
1869 | { | ||||
1870 | tree refop = TREE_OPERAND (ref.ref, 0)(*((const_cast<tree*> (tree_operand_check ((ref.ref), ( 0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1870, __FUNCTION__))))); | ||||
1871 | tree type = TYPE_MAIN_VARIANT (TREE_TYPE (ref.ref))((tree_class_check ((((contains_struct_check ((ref.ref), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1871, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1871, __FUNCTION__))->type_common.main_variant); | ||||
1872 | |||||
1873 | if (warning_at (loc, opt, | ||||
1874 | "%qD offset %s from the object at %qE is out " | ||||
1875 | "of the bounds of referenced subobject %qD with " | ||||
1876 | "type %qT at offset %wi", | ||||
1877 | func, rangestr[0], ref.base, | ||||
1878 | TREE_OPERAND (ref.ref, 1)(*((const_cast<tree*> (tree_operand_check ((ref.ref), ( 1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1878, __FUNCTION__))))), type, | ||||
1879 | ref.refoff.to_shwi ())) | ||||
1880 | { | ||||
1881 | if (TREE_CODE (ref.ref)((enum tree_code) (ref.ref)->base.code) == COMPONENT_REF) | ||||
1882 | refop = TREE_OPERAND (ref.ref, 1)(*((const_cast<tree*> (tree_operand_check ((ref.ref), ( 1), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1882, __FUNCTION__))))); | ||||
1883 | if (DECL_P (refop)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (refop)->base.code))] == tcc_declaration)) | ||||
1884 | inform (DECL_SOURCE_LOCATION (refop)((contains_struct_check ((refop), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1884, __FUNCTION__))->decl_minimal.locus), | ||||
1885 | "subobject %qD declared here", refop); | ||||
1886 | warned = true; | ||||
1887 | } | ||||
1888 | } | ||||
1889 | |||||
1890 | return warned ? opt : no_warning; | ||||
1891 | } | ||||
1892 | |||||
1893 | /* Check a CALL statement for restrict-violations and issue warnings | ||||
1894 | if/when appropriate. */ | ||||
1895 | |||||
1896 | void | ||||
1897 | pass_wrestrict::check_call (gimple *call) | ||||
1898 | { | ||||
1899 | /* Avoid checking the call if it has already been diagnosed for | ||||
1900 | some reason. */ | ||||
1901 | if (warning_suppressed_p (call, OPT_Wrestrict)) | ||||
1902 | return; | ||||
1903 | |||||
1904 | tree func = gimple_call_fndecl (call); | ||||
1905 | if (!func
| ||||
1906 | return; | ||||
1907 | |||||
1908 | /* Argument number to extract from the call (depends on the built-in | ||||
1909 | and its kind). */ | ||||
1910 | unsigned dst_idx = -1; | ||||
1911 | unsigned src_idx = -1; | ||||
1912 | unsigned bnd_idx = -1; | ||||
1913 | |||||
1914 | /* Is this CALL to a string function (as opposed to one to a raw | ||||
1915 | memory function). */ | ||||
1916 | bool strfun = true; | ||||
1917 | |||||
1918 | switch (DECL_FUNCTION_CODE (func)) | ||||
1919 | { | ||||
1920 | case BUILT_IN_MEMCPY: | ||||
1921 | case BUILT_IN_MEMCPY_CHK: | ||||
1922 | case BUILT_IN_MEMPCPY: | ||||
1923 | case BUILT_IN_MEMPCPY_CHK: | ||||
1924 | case BUILT_IN_MEMMOVE: | ||||
1925 | case BUILT_IN_MEMMOVE_CHK: | ||||
1926 | strfun = false; | ||||
1927 | /* Fall through. */ | ||||
1928 | |||||
1929 | case BUILT_IN_STPNCPY: | ||||
1930 | case BUILT_IN_STPNCPY_CHK: | ||||
1931 | case BUILT_IN_STRNCAT: | ||||
1932 | case BUILT_IN_STRNCAT_CHK: | ||||
1933 | case BUILT_IN_STRNCPY: | ||||
1934 | case BUILT_IN_STRNCPY_CHK: | ||||
1935 | dst_idx = 0; | ||||
1936 | src_idx = 1; | ||||
1937 | bnd_idx = 2; | ||||
1938 | break; | ||||
1939 | |||||
1940 | case BUILT_IN_MEMSET: | ||||
1941 | case BUILT_IN_MEMSET_CHK: | ||||
1942 | dst_idx = 0; | ||||
1943 | bnd_idx = 2; | ||||
1944 | break; | ||||
1945 | |||||
1946 | case BUILT_IN_STPCPY: | ||||
1947 | case BUILT_IN_STPCPY_CHK: | ||||
1948 | case BUILT_IN_STRCPY: | ||||
1949 | case BUILT_IN_STRCPY_CHK: | ||||
1950 | case BUILT_IN_STRCAT: | ||||
1951 | case BUILT_IN_STRCAT_CHK: | ||||
1952 | dst_idx = 0; | ||||
1953 | src_idx = 1; | ||||
1954 | break; | ||||
1955 | |||||
1956 | default: | ||||
1957 | /* Handle other string functions here whose access may need | ||||
1958 | to be validated for in-bounds offsets and non-overlapping | ||||
1959 | copies. */ | ||||
1960 | return; | ||||
1961 | } | ||||
1962 | |||||
1963 | unsigned nargs = gimple_call_num_args (call); | ||||
1964 | |||||
1965 | tree dst = dst_idx < nargs ? gimple_call_arg (call, dst_idx) : NULL_TREE(tree) __null; | ||||
1966 | tree src = src_idx < nargs ? gimple_call_arg (call, src_idx) : NULL_TREE(tree) __null; | ||||
1967 | tree dstwr = bnd_idx
| ||||
1968 | |||||
1969 | /* For string functions with an unspecified or unknown bound, | ||||
1970 | assume the size of the access is one. */ | ||||
1971 | if (!dstwr
| ||||
1972 | dstwr = size_one_nodeglobal_trees[TI_SIZE_ONE]; | ||||
1973 | |||||
1974 | /* DST and SRC can be null for a call with an insufficient number | ||||
1975 | of arguments to a built-in function declared without a protype. */ | ||||
1976 | if (!dst || (src_idx
| ||||
1977 | return; | ||||
1978 | |||||
1979 | /* DST, SRC, or DSTWR can also have the wrong type in a call to | ||||
1980 | a function declared without a prototype. Avoid checking such | ||||
1981 | invalid calls. */ | ||||
1982 | if (TREE_CODE (TREE_TYPE (dst))((enum tree_code) (((contains_struct_check ((dst), (TS_TYPED) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1982, __FUNCTION__))->typed.type))->base.code) != POINTER_TYPE | ||||
1983 | || (src
, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1983, __FUNCTION__))->typed.type))->base.code) != POINTER_TYPE) | ||||
1984 | || (dstwr && !INTEGRAL_TYPE_P (TREE_TYPE (dstwr))(((enum tree_code) (((contains_struct_check ((dstwr), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1984, __FUNCTION__))->typed.type))->base.code) == ENUMERAL_TYPE || ((enum tree_code) (((contains_struct_check ((dstwr), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1984, __FUNCTION__))->typed.type))->base.code) == BOOLEAN_TYPE || ((enum tree_code) (((contains_struct_check ((dstwr), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/gimple-ssa-warn-restrict.cc" , 1984, __FUNCTION__))->typed.type))->base.code) == INTEGER_TYPE ))) | ||||
1985 | return; | ||||
1986 | |||||
1987 | opt_code opt = check_bounds_or_overlap (m_ptr_qry, call, dst, src, dstwr, | ||||
1988 | NULL_TREE(tree) __null); | ||||
1989 | /* Avoid diagnosing the call again. */ | ||||
1990 | suppress_warning (call, opt); | ||||
1991 | } | ||||
1992 | |||||
1993 | } /* anonymous namespace */ | ||||
1994 | |||||
1995 | /* Attempt to detect and diagnose invalid offset bounds and (except for | ||||
1996 | memmove) overlapping copy in a call expression EXPR from SRC to DST | ||||
1997 | and DSTSIZE and SRCSIZE bytes, respectively. Both DSTSIZE and | ||||
1998 | SRCSIZE may be NULL. DO_WARN is false to detect either problem | ||||
1999 | without issue a warning. Return the OPT_Wxxx constant corresponding | ||||
2000 | to the warning if one has been detected and zero otherwise. */ | ||||
2001 | |||||
2002 | opt_code | ||||
2003 | check_bounds_or_overlap (gimple *call, tree dst, tree src, tree dstsize, | ||||
2004 | tree srcsize, bool bounds_only /* = false */, | ||||
2005 | bool do_warn /* = true */) | ||||
2006 | { | ||||
2007 | pointer_query ptrqry (get_range_query (cfun(cfun + 0))); | ||||
2008 | return check_bounds_or_overlap (ptrqry, | ||||
2009 | call, dst, src, dstsize, srcsize, | ||||
2010 | bounds_only, do_warn); | ||||
2011 | } | ||||
2012 | |||||
2013 | opt_code | ||||
2014 | check_bounds_or_overlap (pointer_query &ptrqry, | ||||
2015 | gimple *call, tree dst, tree src, tree dstsize, | ||||
2016 | tree srcsize, bool bounds_only /* = false */, | ||||
2017 | bool do_warn /* = true */) | ||||
2018 | { | ||||
2019 | tree func = gimple_call_fndecl (call); | ||||
2020 | |||||
2021 | builtin_memref dstref (ptrqry, call, dst, dstsize); | ||||
2022 | builtin_memref srcref (ptrqry, call, src, srcsize); | ||||
2023 | |||||
2024 | /* Create a descriptor of the access. This may adjust both DSTREF | ||||
2025 | and SRCREF based on one another and the kind of the access. */ | ||||
2026 | builtin_access acs (ptrqry, call, dstref, srcref); | ||||
2027 | |||||
2028 | /* Set STRICT to the value of the -Warray-bounds=N argument for | ||||
2029 | string functions or when N > 1. */ | ||||
2030 | int strict = (acs.strict () || warn_array_boundsglobal_options.x_warn_array_bounds > 1 ? warn_array_boundsglobal_options.x_warn_array_bounds : 0); | ||||
2031 | |||||
2032 | /* The starting offset of the destination write access. Nonzero only | ||||
2033 | for the strcat family of functions. */ | ||||
2034 | offset_int wroff = acs.write_off (dstsize); | ||||
2035 | |||||
2036 | /* Validate offsets to each reference before the access first to make | ||||
2037 | sure they are within the bounds of the destination object if its | ||||
2038 | size is known, or PTRDIFF_MAX otherwise. */ | ||||
2039 | opt_code opt | ||||
2040 | = maybe_diag_access_bounds (call, func, strict, dstref, wroff, do_warn); | ||||
2041 | if (opt == no_warning) | ||||
2042 | opt = maybe_diag_access_bounds (call, func, strict, srcref, 0, do_warn); | ||||
2043 | |||||
2044 | if (opt != no_warning) | ||||
2045 | { | ||||
2046 | if (do_warn) | ||||
2047 | suppress_warning (call, opt); | ||||
2048 | return opt; | ||||
2049 | } | ||||
2050 | |||||
2051 | if (!warn_restrictglobal_options.x_warn_restrict || bounds_only || !src) | ||||
2052 | return no_warning; | ||||
2053 | |||||
2054 | if (!bounds_only) | ||||
2055 | { | ||||
2056 | switch (DECL_FUNCTION_CODE (func)) | ||||
2057 | { | ||||
2058 | case BUILT_IN_MEMMOVE: | ||||
2059 | case BUILT_IN_MEMMOVE_CHK: | ||||
2060 | case BUILT_IN_MEMSET: | ||||
2061 | case BUILT_IN_MEMSET_CHK: | ||||
2062 | return no_warning; | ||||
2063 | default: | ||||
2064 | break; | ||||
2065 | } | ||||
2066 | } | ||||
2067 | |||||
2068 | location_t loc = gimple_location (call); | ||||
2069 | if (operand_equal_p (dst, src, 0)) | ||||
2070 | { | ||||
2071 | /* Issue -Wrestrict unless the pointers are null (those do | ||||
2072 | not point to objects and so do not indicate an overlap; | ||||
2073 | such calls could be the result of sanitization and jump | ||||
2074 | threading). */ | ||||
2075 | if (!integer_zerop (dst) && !warning_suppressed_p (call, OPT_Wrestrict)) | ||||
2076 | { | ||||
2077 | warning_at (loc, OPT_Wrestrict, | ||||
2078 | "%qD source argument is the same as destination", | ||||
2079 | func); | ||||
2080 | suppress_warning (call, OPT_Wrestrict); | ||||
2081 | return OPT_Wrestrict; | ||||
2082 | } | ||||
2083 | |||||
2084 | return no_warning; | ||||
2085 | } | ||||
2086 | |||||
2087 | /* Return false when overlap has been detected. */ | ||||
2088 | if (maybe_diag_overlap (loc, call, acs)) | ||||
2089 | { | ||||
2090 | suppress_warning (call, OPT_Wrestrict); | ||||
2091 | return OPT_Wrestrict; | ||||
2092 | } | ||||
2093 | |||||
2094 | return no_warning; | ||||
2095 | } | ||||
2096 | |||||
2097 | gimple_opt_pass * | ||||
2098 | make_pass_warn_restrict (gcc::context *ctxt) | ||||
2099 | { | ||||
2100 | return new pass_wrestrict (ctxt); | ||||
2101 | } | ||||
2102 | |||||
2103 | DEBUG_FUNCTION__attribute__ ((__used__)) void | ||||
2104 | dump_builtin_memref (FILE *fp, const builtin_memref &ref) | ||||
2105 | { | ||||
2106 | fprintf (fp, "\n ptr = "); | ||||
2107 | print_generic_expr (fp, ref.ptr, TDF_LINENO); | ||||
2108 | fprintf (fp, "\n ref = "); | ||||
2109 | if (ref.ref) | ||||
2110 | print_generic_expr (fp, ref.ref, TDF_LINENO); | ||||
2111 | else | ||||
2112 | fputs ("null", fp); | ||||
2113 | fprintf (fp, "\n base = "); | ||||
2114 | print_generic_expr (fp, ref.base, TDF_LINENO); | ||||
2115 | fprintf (fp, | ||||
2116 | "\n basesize = %lli" | ||||
2117 | "\n refsize = %lli" | ||||
2118 | "\n refoff = %lli" | ||||
2119 | "\n offrange = [%lli, %lli]" | ||||
2120 | "\n sizrange = [%lli, %lli]" | ||||
2121 | "\n strbounded_p = %s\n", | ||||
2122 | (long long)ref.basesize.to_shwi (), | ||||
2123 | (long long)ref.refsize.to_shwi (), | ||||
2124 | (long long)ref.refoff.to_shwi (), | ||||
2125 | (long long)ref.offrange[0].to_shwi (), | ||||
2126 | (long long)ref.offrange[1].to_shwi (), | ||||
2127 | (long long)ref.sizrange[0].to_shwi (), | ||||
2128 | (long long)ref.sizrange[1].to_shwi (), | ||||
2129 | ref.strbounded_p ? "true" : "false"); | ||||
2130 | } | ||||
2131 | |||||
2132 | void | ||||
2133 | builtin_access::dump (FILE *fp) const | ||||
2134 | { | ||||
2135 | fprintf (fp, " dstref:"); | ||||
2136 | dump_builtin_memref (fp, *dstref); | ||||
2137 | fprintf (fp, "\n srcref:"); | ||||
2138 | dump_builtin_memref (fp, *srcref); | ||||
2139 | |||||
2140 | fprintf (fp, | ||||
2141 | " sizrange = [%lli, %lli]\n" | ||||
2142 | " ovloff = [%lli, %lli]\n" | ||||
2143 | " ovlsiz = [%lli, %lli]\n" | ||||
2144 | " dstoff = [%lli, %lli]\n" | ||||
2145 | " dstsiz = [%lli, %lli]\n" | ||||
2146 | " srcoff = [%lli, %lli]\n" | ||||
2147 | " srcsiz = [%lli, %lli]\n", | ||||
2148 | (long long)sizrange[0], (long long)sizrange[1], | ||||
2149 | (long long)ovloff[0], (long long)ovloff[1], | ||||
2150 | (long long)ovlsiz[0], (long long)ovlsiz[1], | ||||
2151 | (long long)dstoff[0].to_shwi (), (long long)dstoff[1].to_shwi (), | ||||
2152 | (long long)dstsiz[0].to_shwi (), (long long)dstsiz[1].to_shwi (), | ||||
2153 | (long long)srcoff[0].to_shwi (), (long long)srcoff[1].to_shwi (), | ||||
2154 | (long long)srcsiz[0].to_shwi (), (long long)srcsiz[1].to_shwi ()); | ||||
2155 | } | ||||
2156 | |||||
2157 | DEBUG_FUNCTION__attribute__ ((__used__)) void | ||||
2158 | dump_builtin_access (FILE *fp, gimple *stmt, const builtin_access &acs) | ||||
2159 | { | ||||
2160 | if (stmt) | ||||
2161 | { | ||||
2162 | fprintf (fp, "\nDumping builtin_access for "); | ||||
2163 | print_gimple_expr (fp, stmt, TDF_LINENO); | ||||
2164 | fputs (":\n", fp); | ||||
2165 | } | ||||
2166 | |||||
2167 | acs.dump (fp); | ||||
2168 | } | ||||
2169 | |||||
2170 | DEBUG_FUNCTION__attribute__ ((__used__)) void | ||||
2171 | debug (gimple *stmt, const builtin_access &acs) | ||||
2172 | { | ||||
2173 | dump_builtin_access (stdoutstdout, stmt, acs); | ||||
2174 | } |