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