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

source code of gcc/gimple-ssa-warn-restrict.cc