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