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