138fd1498Szrj /* Pass to detect and issue warnings for violations of the restrict
238fd1498Szrj    qualifier.
338fd1498Szrj    Copyright (C) 2017-2018 Free Software Foundation, Inc.
438fd1498Szrj    Contributed by Martin Sebor <msebor@redhat.com>.
538fd1498Szrj 
638fd1498Szrj    This file is part of GCC.
738fd1498Szrj 
838fd1498Szrj    GCC is free software; you can redistribute it and/or modify it under
938fd1498Szrj    the terms of the GNU General Public License as published by the Free
1038fd1498Szrj    Software Foundation; either version 3, or (at your option) any later
1138fd1498Szrj    version.
1238fd1498Szrj 
1338fd1498Szrj    GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1438fd1498Szrj    WARRANTY; without even the implied warranty of MERCHANTABILITY or
1538fd1498Szrj    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1638fd1498Szrj    for more details.
1738fd1498Szrj 
1838fd1498Szrj    You should have received a copy of the GNU General Public License
1938fd1498Szrj    along with GCC; see the file COPYING3.  If not see
2038fd1498Szrj    <http://www.gnu.org/licenses/>.  */
2138fd1498Szrj 
2238fd1498Szrj #include "config.h"
2338fd1498Szrj #include "system.h"
2438fd1498Szrj #include "coretypes.h"
2538fd1498Szrj #include "backend.h"
2638fd1498Szrj #include "tree.h"
2738fd1498Szrj #include "gimple.h"
2838fd1498Szrj #include "domwalk.h"
2938fd1498Szrj #include "tree-pass.h"
3038fd1498Szrj #include "builtins.h"
3138fd1498Szrj #include "ssa.h"
3238fd1498Szrj #include "gimple-pretty-print.h"
3338fd1498Szrj #include "gimple-ssa-warn-restrict.h"
3438fd1498Szrj #include "diagnostic-core.h"
3538fd1498Szrj #include "fold-const.h"
3638fd1498Szrj #include "gimple-iterator.h"
3738fd1498Szrj #include "tree-dfa.h"
3838fd1498Szrj #include "tree-ssa.h"
3938fd1498Szrj #include "params.h"
4038fd1498Szrj #include "tree-cfg.h"
4138fd1498Szrj #include "tree-object-size.h"
4238fd1498Szrj #include "calls.h"
4338fd1498Szrj #include "cfgloop.h"
4438fd1498Szrj #include "intl.h"
4538fd1498Szrj 
4638fd1498Szrj namespace {
4738fd1498Szrj 
4838fd1498Szrj const pass_data pass_data_wrestrict = {
4938fd1498Szrj   GIMPLE_PASS,
5038fd1498Szrj   "wrestrict",
5138fd1498Szrj   OPTGROUP_NONE,
5238fd1498Szrj   TV_NONE,
5338fd1498Szrj   PROP_cfg, /* Properties_required.  */
5438fd1498Szrj   0,	    /* properties_provided.  */
5538fd1498Szrj   0,	    /* properties_destroyed.  */
5638fd1498Szrj   0,	    /* properties_start */
5738fd1498Szrj   0,	    /* properties_finish */
5838fd1498Szrj };
5938fd1498Szrj 
6038fd1498Szrj /* Pass to detect violations of strict aliasing requirements in calls
6138fd1498Szrj    to built-in string and raw memory functions.  */
6238fd1498Szrj class pass_wrestrict : public gimple_opt_pass
6338fd1498Szrj {
6438fd1498Szrj  public:
pass_wrestrict(gcc::context * ctxt)6538fd1498Szrj   pass_wrestrict (gcc::context *ctxt)
6638fd1498Szrj     : gimple_opt_pass (pass_data_wrestrict, ctxt)
6738fd1498Szrj     { }
6838fd1498Szrj 
clone()6938fd1498Szrj   opt_pass *clone () { return new pass_wrestrict (m_ctxt); }
7038fd1498Szrj 
7138fd1498Szrj   virtual bool gate (function *);
7238fd1498Szrj   virtual unsigned int execute (function *);
7338fd1498Szrj };
7438fd1498Szrj 
7538fd1498Szrj bool
gate(function * fun ATTRIBUTE_UNUSED)7638fd1498Szrj pass_wrestrict::gate (function *fun ATTRIBUTE_UNUSED)
7738fd1498Szrj {
7838fd1498Szrj   return warn_array_bounds != 0 || warn_restrict != 0;
7938fd1498Szrj }
8038fd1498Szrj 
8138fd1498Szrj /* Class to walk the basic blocks of a function in dominator order.  */
8238fd1498Szrj class wrestrict_dom_walker : public dom_walker
8338fd1498Szrj {
8438fd1498Szrj  public:
wrestrict_dom_walker()8538fd1498Szrj   wrestrict_dom_walker () : dom_walker (CDI_DOMINATORS) {}
8638fd1498Szrj 
8738fd1498Szrj   edge before_dom_children (basic_block) FINAL OVERRIDE;
8838fd1498Szrj   bool handle_gimple_call (gimple_stmt_iterator *);
8938fd1498Szrj 
9038fd1498Szrj  private:
9138fd1498Szrj   void check_call (gcall *);
9238fd1498Szrj };
9338fd1498Szrj 
9438fd1498Szrj edge
before_dom_children(basic_block bb)9538fd1498Szrj wrestrict_dom_walker::before_dom_children (basic_block bb)
9638fd1498Szrj {
9738fd1498Szrj   /* Iterate over statements, looking for function calls.  */
9838fd1498Szrj   for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
9938fd1498Szrj        gsi_next (&si))
10038fd1498Szrj     {
10138fd1498Szrj       gimple *stmt = gsi_stmt (si);
10238fd1498Szrj       if (!is_gimple_call (stmt))
10338fd1498Szrj 	continue;
10438fd1498Szrj 
10538fd1498Szrj       if (gcall *call = as_a <gcall *> (stmt))
10638fd1498Szrj 	check_call (call);
10738fd1498Szrj     }
10838fd1498Szrj 
10938fd1498Szrj   return NULL;
11038fd1498Szrj }
11138fd1498Szrj 
11238fd1498Szrj /* Execute the pass for function FUN, walking in dominator order.  */
11338fd1498Szrj 
11438fd1498Szrj unsigned
execute(function * fun)11538fd1498Szrj pass_wrestrict::execute (function *fun)
11638fd1498Szrj {
11738fd1498Szrj   calculate_dominance_info (CDI_DOMINATORS);
11838fd1498Szrj 
11938fd1498Szrj   wrestrict_dom_walker walker;
12038fd1498Szrj   walker.walk (ENTRY_BLOCK_PTR_FOR_FN (fun));
12138fd1498Szrj 
12238fd1498Szrj   return 0;
12338fd1498Szrj }
12438fd1498Szrj 
12538fd1498Szrj /* Description of a memory reference by a built-in function.  This
12638fd1498Szrj    is similar to ao_ref but made especially suitable for -Wrestrict
12738fd1498Szrj    and not for optimization.  */
12838fd1498Szrj struct builtin_memref
12938fd1498Szrj {
13038fd1498Szrj   /* The original pointer argument to the built-in function.  */
13138fd1498Szrj   tree ptr;
13238fd1498Szrj   /* The referenced subobject or NULL if not available, and the base
13338fd1498Szrj      object of the memory reference or NULL.  */
13438fd1498Szrj   tree ref;
13538fd1498Szrj   tree base;
13638fd1498Szrj 
13738fd1498Szrj   /* The size of the BASE object, PTRDIFF_MAX if indeterminate,
13838fd1498Szrj      and negative until (possibly lazily) initialized.  */
13938fd1498Szrj   offset_int basesize;
14038fd1498Szrj 
14138fd1498Szrj   /* The non-negative offset of the referenced subobject.  Used to avoid
14238fd1498Szrj      warnings for (apparently) possibly but not definitively overlapping
14338fd1498Szrj      accesses to member arrays.  Negative when unknown/invalid.  */
14438fd1498Szrj   offset_int refoff;
14538fd1498Szrj 
14638fd1498Szrj   /* The offset range relative to the base.  */
14738fd1498Szrj   offset_int offrange[2];
14838fd1498Szrj   /* The size range of the access to this reference.  */
14938fd1498Szrj   offset_int sizrange[2];
15038fd1498Szrj 
15138fd1498Szrj   /* True for "bounded" string functions like strncat, and strncpy
15238fd1498Szrj      and their variants that specify either an exact or upper bound
15338fd1498Szrj      on the size of the accesses they perform.  For strncat both
15438fd1498Szrj      the source and destination references are bounded.  For strncpy
15538fd1498Szrj      only the destination reference is.  */
15638fd1498Szrj   bool strbounded_p;
15738fd1498Szrj 
15838fd1498Szrj   builtin_memref (tree, tree);
15938fd1498Szrj 
16038fd1498Szrj   tree offset_out_of_bounds (int, offset_int[2]) const;
16138fd1498Szrj 
16238fd1498Szrj private:
16338fd1498Szrj 
16438fd1498Szrj   /* Ctor helper to set or extend OFFRANGE based on argument.  */
16538fd1498Szrj   void extend_offset_range (tree);
16638fd1498Szrj 
16738fd1498Szrj   /*  Ctor helper to determine BASE and OFFRANGE from argument.  */
16838fd1498Szrj   void set_base_and_offset (tree);
16938fd1498Szrj };
17038fd1498Szrj 
17138fd1498Szrj /* Description of a memory access by a raw memory or string built-in
17238fd1498Szrj    function involving a pair of builtin_memref's.  */
17338fd1498Szrj class builtin_access
17438fd1498Szrj {
17538fd1498Szrj  public:
17638fd1498Szrj   /* Destination and source memory reference.  */
17738fd1498Szrj   builtin_memref* const dstref;
17838fd1498Szrj   builtin_memref* const srcref;
17938fd1498Szrj   /* The size range of the access.  It's the greater of the accesses
18038fd1498Szrj      to the two references.  */
18138fd1498Szrj   HOST_WIDE_INT sizrange[2];
18238fd1498Szrj 
18338fd1498Szrj   /* The minimum and maximum offset of an overlap of the access
18438fd1498Szrj      (if it does, in fact, overlap), and the size of the overlap.  */
18538fd1498Szrj   HOST_WIDE_INT ovloff[2];
18638fd1498Szrj   HOST_WIDE_INT ovlsiz[2];
18738fd1498Szrj 
18838fd1498Szrj   /* True to consider valid only accesses to the smallest subobject
18938fd1498Szrj      and false for raw memory functions.  */
strict()19038fd1498Szrj   bool strict () const
19138fd1498Szrj   {
19238fd1498Szrj     return detect_overlap != &builtin_access::generic_overlap;
19338fd1498Szrj   }
19438fd1498Szrj 
19538fd1498Szrj   builtin_access (gcall *, builtin_memref &, builtin_memref &);
19638fd1498Szrj 
19738fd1498Szrj   /* Entry point to determine overlap.  */
19838fd1498Szrj   bool overlap ();
19938fd1498Szrj 
20038fd1498Szrj  private:
20138fd1498Szrj   /* Implementation functions used to determine overlap.  */
20238fd1498Szrj   bool generic_overlap ();
20338fd1498Szrj   bool strcat_overlap ();
20438fd1498Szrj   bool strcpy_overlap ();
20538fd1498Szrj 
no_overlap()20638fd1498Szrj   bool no_overlap ()
20738fd1498Szrj   {
20838fd1498Szrj     return false;
20938fd1498Szrj   }
21038fd1498Szrj 
21138fd1498Szrj   offset_int overlap_size (const offset_int [2], const offset_int[2],
21238fd1498Szrj 			   offset_int [2]);
21338fd1498Szrj 
21438fd1498Szrj  private:
21538fd1498Szrj   /* Temporaries used to compute the final result.  */
21638fd1498Szrj   offset_int dstoff[2];
21738fd1498Szrj   offset_int srcoff[2];
21838fd1498Szrj   offset_int dstsiz[2];
21938fd1498Szrj   offset_int srcsiz[2];
22038fd1498Szrj 
22138fd1498Szrj   /* Pointer to a member function to call to determine overlap.  */
22238fd1498Szrj   bool (builtin_access::*detect_overlap) ();
22338fd1498Szrj };
22438fd1498Szrj 
22538fd1498Szrj /* Initialize a memory reference representation from a pointer EXPR and
22638fd1498Szrj    a size SIZE in bytes.  If SIZE is NULL_TREE then the size is assumed
22738fd1498Szrj    to be unknown.  */
22838fd1498Szrj 
builtin_memref(tree expr,tree size)22938fd1498Szrj builtin_memref::builtin_memref (tree expr, tree size)
23038fd1498Szrj : ptr (expr),
23138fd1498Szrj   ref (),
23238fd1498Szrj   base (),
23338fd1498Szrj   basesize (-1),
23438fd1498Szrj   refoff (HOST_WIDE_INT_MIN),
23538fd1498Szrj   offrange (),
23638fd1498Szrj   sizrange (),
23738fd1498Szrj   strbounded_p ()
23838fd1498Szrj {
23938fd1498Szrj   /* Unfortunately, wide_int default ctor is a no-op so array members
24038fd1498Szrj      of the type must be set individually.  */
24138fd1498Szrj   offrange[0] = offrange[1] = 0;
24238fd1498Szrj   sizrange[0] = sizrange[1] = 0;
24338fd1498Szrj 
24438fd1498Szrj   const offset_int maxobjsize = tree_to_shwi (max_object_size ());
24538fd1498Szrj 
24638fd1498Szrj   /* Find the BASE object or pointer referenced by EXPR and set
24738fd1498Szrj      the offset range OFFRANGE in the process.  */
24838fd1498Szrj   set_base_and_offset (expr);
24938fd1498Szrj 
25038fd1498Szrj   if (size)
25138fd1498Szrj     {
25238fd1498Szrj       tree range[2];
25338fd1498Szrj       /* Determine the size range, allowing for the result to be [0, 0]
25438fd1498Szrj 	 for SIZE in the anti-range ~[0, N] where N >= PTRDIFF_MAX.  */
25538fd1498Szrj       get_size_range (size, range, true);
25638fd1498Szrj       sizrange[0] = wi::to_offset (range[0]);
25738fd1498Szrj       sizrange[1] = wi::to_offset (range[1]);
25838fd1498Szrj       /* get_size_range returns SIZE_MAX for the maximum size.
25938fd1498Szrj 	 Constrain it to the real maximum of PTRDIFF_MAX.  */
26038fd1498Szrj       if (sizrange[1] > maxobjsize)
26138fd1498Szrj 	sizrange[1] = maxobjsize;
26238fd1498Szrj     }
26338fd1498Szrj   else
26438fd1498Szrj     sizrange[1] = maxobjsize;
26538fd1498Szrj 
26638fd1498Szrj   tree basetype = TREE_TYPE (base);
26738fd1498Szrj   if (DECL_P (base) && TREE_CODE (basetype) == ARRAY_TYPE)
26838fd1498Szrj     {
26938fd1498Szrj       /* If the offset could be in range of the referenced object
27038fd1498Szrj 	 constrain its bounds so neither exceeds those of the object.  */
27138fd1498Szrj       if (offrange[0] < 0 && offrange[1] > 0)
27238fd1498Szrj 	offrange[0] = 0;
27338fd1498Szrj 
27438fd1498Szrj       offset_int maxoff = maxobjsize;
27538fd1498Szrj       if (ref && array_at_struct_end_p (ref))
27638fd1498Szrj 	;   /* Use the maximum possible offset for last member arrays.  */
27738fd1498Szrj       else if (tree basesize = TYPE_SIZE_UNIT (basetype))
27838fd1498Szrj 	maxoff = wi::to_offset (basesize);
27938fd1498Szrj 
28038fd1498Szrj       if (offrange[0] >= 0)
28138fd1498Szrj 	{
28238fd1498Szrj 	  if (offrange[1] < 0)
28338fd1498Szrj 	    offrange[1] = offrange[0] <= maxoff ? maxoff : maxobjsize;
28438fd1498Szrj 	  else if (offrange[0] <= maxoff && offrange[1] > maxoff)
28538fd1498Szrj 	    offrange[1] = maxoff;
28638fd1498Szrj 	}
28738fd1498Szrj     }
28838fd1498Szrj }
28938fd1498Szrj 
29038fd1498Szrj /* Ctor helper to set or extend OFFRANGE based on the OFFSET argument.  */
29138fd1498Szrj 
29238fd1498Szrj void
extend_offset_range(tree offset)29338fd1498Szrj builtin_memref::extend_offset_range (tree offset)
29438fd1498Szrj {
29538fd1498Szrj   const offset_int maxobjsize = tree_to_shwi (max_object_size ());
29638fd1498Szrj 
29738fd1498Szrj   if (TREE_CODE (offset) == INTEGER_CST)
29838fd1498Szrj     {
29938fd1498Szrj       offset_int off = int_cst_value (offset);
30038fd1498Szrj       if (off != 0)
30138fd1498Szrj 	{
30238fd1498Szrj 	  offrange[0] += off;
30338fd1498Szrj 	  offrange[1] += off;
30438fd1498Szrj 	}
30538fd1498Szrj       return;
30638fd1498Szrj     }
30738fd1498Szrj 
30838fd1498Szrj   if (TREE_CODE (offset) == SSA_NAME)
30938fd1498Szrj     {
31038fd1498Szrj       wide_int min, max;
31138fd1498Szrj       value_range_type rng = get_range_info (offset, &min, &max);
31238fd1498Szrj       if (rng == VR_RANGE)
31338fd1498Szrj 	{
31438fd1498Szrj 	  offrange[0] += offset_int::from (min, SIGNED);
31538fd1498Szrj 	  offrange[1] += offset_int::from (max, SIGNED);
31638fd1498Szrj 	}
31738fd1498Szrj       else
31838fd1498Szrj 	{
319*e215fc28Szrj 	  /* Handle an anti-range the same as no range at all.  */
32038fd1498Szrj 	  gimple *stmt = SSA_NAME_DEF_STMT (offset);
32138fd1498Szrj 	  tree type;
32238fd1498Szrj 	  if (is_gimple_assign (stmt)
32338fd1498Szrj 	      && gimple_assign_rhs_code (stmt) == NOP_EXPR
32438fd1498Szrj 	      && (type = TREE_TYPE (gimple_assign_rhs1 (stmt)))
32538fd1498Szrj 	      && INTEGRAL_TYPE_P (type))
32638fd1498Szrj 	    {
32738fd1498Szrj 	      /* Use the bounds of the type of the NOP_EXPR operand
32838fd1498Szrj 		 even if it's signed.  The result doesn't trigger
32938fd1498Szrj 		 warnings but makes their output more readable.  */
33038fd1498Szrj 	      offrange[0] += wi::to_offset (TYPE_MIN_VALUE (type));
33138fd1498Szrj 	      offrange[1] += wi::to_offset (TYPE_MAX_VALUE (type));
33238fd1498Szrj 	    }
33338fd1498Szrj 	  else
33438fd1498Szrj 	    offrange[1] += maxobjsize;
33538fd1498Szrj 	}
33638fd1498Szrj       return;
33738fd1498Szrj     }
33838fd1498Szrj 
33938fd1498Szrj   offrange[1] += maxobjsize;
34038fd1498Szrj }
34138fd1498Szrj 
34238fd1498Szrj /* Determines the base object or pointer of the reference EXPR
34338fd1498Szrj    and the offset range from the beginning of the base.  */
34438fd1498Szrj 
34538fd1498Szrj void
set_base_and_offset(tree expr)34638fd1498Szrj builtin_memref::set_base_and_offset (tree expr)
34738fd1498Szrj {
34838fd1498Szrj   const offset_int maxobjsize = tree_to_shwi (max_object_size ());
34938fd1498Szrj 
35038fd1498Szrj   if (TREE_CODE (expr) == SSA_NAME)
35138fd1498Szrj     {
35238fd1498Szrj       /* Try to tease the offset out of the pointer.  */
35338fd1498Szrj       gimple *stmt = SSA_NAME_DEF_STMT (expr);
35438fd1498Szrj       if (!base
35538fd1498Szrj 	  && gimple_assign_single_p (stmt)
35638fd1498Szrj 	  && gimple_assign_rhs_code (stmt) == ADDR_EXPR)
35738fd1498Szrj 	expr = gimple_assign_rhs1 (stmt);
35838fd1498Szrj       else if (is_gimple_assign (stmt))
35938fd1498Szrj 	{
36038fd1498Szrj 	  tree_code code = gimple_assign_rhs_code (stmt);
36138fd1498Szrj 	  if (code == NOP_EXPR)
36238fd1498Szrj 	    {
36338fd1498Szrj 	      tree rhs = gimple_assign_rhs1 (stmt);
36438fd1498Szrj 	      if (POINTER_TYPE_P (TREE_TYPE (rhs)))
36538fd1498Szrj 		expr = gimple_assign_rhs1 (stmt);
36638fd1498Szrj 	      else
36738fd1498Szrj 		{
36838fd1498Szrj 		  base = expr;
36938fd1498Szrj 		  return;
37038fd1498Szrj 		}
37138fd1498Szrj 	    }
37238fd1498Szrj 	  else if (code == POINTER_PLUS_EXPR)
37338fd1498Szrj 	    {
37438fd1498Szrj 	      expr = gimple_assign_rhs1 (stmt);
37538fd1498Szrj 
37638fd1498Szrj 	      tree offset = gimple_assign_rhs2 (stmt);
37738fd1498Szrj 	      extend_offset_range (offset);
37838fd1498Szrj 	    }
37938fd1498Szrj 	  else
38038fd1498Szrj 	    {
38138fd1498Szrj 	      base = expr;
38238fd1498Szrj 	      return;
38338fd1498Szrj 	    }
38438fd1498Szrj 	}
38538fd1498Szrj       else
38638fd1498Szrj 	{
38738fd1498Szrj 	  base = expr;
38838fd1498Szrj 	  return;
38938fd1498Szrj 	}
39038fd1498Szrj     }
39138fd1498Szrj 
39238fd1498Szrj   if (TREE_CODE (expr) == ADDR_EXPR)
39338fd1498Szrj     expr = TREE_OPERAND (expr, 0);
39438fd1498Szrj 
39538fd1498Szrj   /* Stash the reference for offset validation.  */
39638fd1498Szrj   ref = expr;
39738fd1498Szrj 
39838fd1498Szrj   poly_int64 bitsize, bitpos;
39938fd1498Szrj   tree var_off;
40038fd1498Szrj   machine_mode mode;
40138fd1498Szrj   int sign, reverse, vol;
40238fd1498Szrj 
40338fd1498Szrj   /* Determine the base object or pointer of the reference and
40438fd1498Szrj      the constant bit offset from the beginning of the base.
40538fd1498Szrj      If the offset has a non-constant component, it will be in
40638fd1498Szrj      VAR_OFF.  MODE, SIGN, REVERSE, and VOL are write only and
40738fd1498Szrj      unused here.  */
40838fd1498Szrj   base = get_inner_reference (expr, &bitsize, &bitpos, &var_off,
40938fd1498Szrj 			      &mode, &sign, &reverse, &vol);
41038fd1498Szrj 
41138fd1498Szrj   /* get_inner_reference is not expected to return null.  */
41238fd1498Szrj   gcc_assert (base != NULL);
41338fd1498Szrj 
41438fd1498Szrj   poly_int64 bytepos = exact_div (bitpos, BITS_PER_UNIT);
41538fd1498Szrj 
41638fd1498Szrj   /* Convert the poly_int64 offset to offset_int.  The offset
41738fd1498Szrj      should be constant but be prepared for it not to be just in
41838fd1498Szrj      case.  */
41938fd1498Szrj   offset_int cstoff;
42038fd1498Szrj   if (bytepos.is_constant (&cstoff))
42138fd1498Szrj     {
42238fd1498Szrj       offrange[0] += cstoff;
42338fd1498Szrj       offrange[1] += cstoff;
42438fd1498Szrj 
42538fd1498Szrj       /* Besides the reference saved above, also stash the offset
42638fd1498Szrj 	 for validation.  */
42738fd1498Szrj       if (TREE_CODE (expr) == COMPONENT_REF)
42838fd1498Szrj 	refoff = cstoff;
42938fd1498Szrj     }
43038fd1498Szrj   else
43138fd1498Szrj     offrange[1] += maxobjsize;
43238fd1498Szrj 
43338fd1498Szrj   if (var_off)
43438fd1498Szrj     {
43538fd1498Szrj       if (TREE_CODE (var_off) == INTEGER_CST)
43638fd1498Szrj 	{
43738fd1498Szrj 	  cstoff = wi::to_offset (var_off);
43838fd1498Szrj 	  offrange[0] += cstoff;
43938fd1498Szrj 	  offrange[1] += cstoff;
44038fd1498Szrj 	}
44138fd1498Szrj       else
44238fd1498Szrj 	offrange[1] += maxobjsize;
44338fd1498Szrj     }
44438fd1498Szrj 
44538fd1498Szrj   if (TREE_CODE (base) == MEM_REF)
44638fd1498Szrj     {
44738fd1498Szrj       tree memrefoff = TREE_OPERAND (base, 1);
44838fd1498Szrj       extend_offset_range (memrefoff);
44938fd1498Szrj       base = TREE_OPERAND (base, 0);
45038fd1498Szrj     }
45138fd1498Szrj 
45238fd1498Szrj   if (TREE_CODE (base) == SSA_NAME)
45338fd1498Szrj     set_base_and_offset (base);
45438fd1498Szrj }
45538fd1498Szrj 
45638fd1498Szrj /* Return error_mark_node if the signed offset exceeds the bounds
45738fd1498Szrj    of the address space (PTRDIFF_MAX).  Otherwise, return either
45838fd1498Szrj    BASE or REF when the offset exceeds the bounds of the BASE or
45938fd1498Szrj    REF object, and set OOBOFF to the past-the-end offset formed
46038fd1498Szrj    by the reference, including its size.  When STRICT is non-zero
46138fd1498Szrj    use REF size, when available, otherwise use BASE size.  When
46238fd1498Szrj    STRICT is greater than 1, use the size of the last array member
46338fd1498Szrj    as the bound, otherwise treat such a member as a flexible array
46438fd1498Szrj    member.  Return NULL when the offset is in bounds.  */
46538fd1498Szrj 
46638fd1498Szrj tree
offset_out_of_bounds(int strict,offset_int ooboff[2])46738fd1498Szrj builtin_memref::offset_out_of_bounds (int strict, offset_int ooboff[2]) const
46838fd1498Szrj {
46938fd1498Szrj   const offset_int maxobjsize = tree_to_shwi (max_object_size ());
47038fd1498Szrj 
47138fd1498Szrj   /* A temporary, possibly adjusted, copy of the offset range.  */
47238fd1498Szrj   offset_int offrng[2] = { offrange[0], offrange[1] };
47338fd1498Szrj 
47438fd1498Szrj   if (DECL_P (base) && TREE_CODE (TREE_TYPE (base)) == ARRAY_TYPE)
47538fd1498Szrj     {
47638fd1498Szrj       /* Check for offset in an anti-range with a negative lower bound.
47738fd1498Szrj 	 For such a range, consider only the non-negative subrange.  */
47838fd1498Szrj       if (offrng[1] < offrng[0] && offrng[1] < 0)
47938fd1498Szrj   	offrng[1] = maxobjsize;
48038fd1498Szrj     }
48138fd1498Szrj 
48238fd1498Szrj   /* Conservative offset of the last byte of the referenced object.  */
48338fd1498Szrj   offset_int endoff;
48438fd1498Szrj 
48538fd1498Szrj   /* The bounds need not be ordered.  Set HIB to use as the index
48638fd1498Szrj      of the larger of the bounds and LOB as the opposite.  */
48738fd1498Szrj   bool hib = wi::les_p (offrng[0], offrng[1]);
48838fd1498Szrj   bool lob = !hib;
48938fd1498Szrj 
49038fd1498Szrj   if (basesize < 0)
49138fd1498Szrj     {
49238fd1498Szrj       endoff = offrng[lob] + sizrange[0];
49338fd1498Szrj 
49438fd1498Szrj       /* For a reference through a pointer to an object of unknown size
49538fd1498Szrj 	 all initial offsets are considered valid, positive as well as
49638fd1498Szrj 	 negative, since the pointer itself can point past the beginning
49738fd1498Szrj 	 of the object.  However, the sum of the lower bound of the offset
49838fd1498Szrj 	 and that of the size must be less than or equal than PTRDIFF_MAX.  */
49938fd1498Szrj       if (endoff > maxobjsize)
50038fd1498Szrj 	return error_mark_node;
50138fd1498Szrj 
50238fd1498Szrj       return NULL_TREE;
50338fd1498Szrj     }
50438fd1498Szrj 
50538fd1498Szrj   /* A reference to an object of known size must be within the bounds
50638fd1498Szrj      of the base object.  */
50738fd1498Szrj   if (offrng[hib] < 0 || offrng[lob] > basesize)
50838fd1498Szrj     return base;
50938fd1498Szrj 
51038fd1498Szrj   /* The extent of the reference must also be within the bounds of
51138fd1498Szrj      the base object (if known) or the maximum object size otherwise.  */
51238fd1498Szrj   endoff = wi::smax (offrng[lob], 0) + sizrange[0];
51338fd1498Szrj   if (endoff > maxobjsize)
51438fd1498Szrj     return error_mark_node;
51538fd1498Szrj 
51638fd1498Szrj   offset_int size = basesize;
51738fd1498Szrj   tree obj = base;
51838fd1498Szrj 
51938fd1498Szrj   if (strict
52038fd1498Szrj       && DECL_P (obj)
52138fd1498Szrj       && ref
52238fd1498Szrj       && refoff >= 0
52338fd1498Szrj       && TREE_CODE (ref) == COMPONENT_REF
52438fd1498Szrj       && (strict > 1
52538fd1498Szrj 	  || !array_at_struct_end_p (ref)))
52638fd1498Szrj     {
52738fd1498Szrj       /* If the reference is to a member subobject, the offset must
52838fd1498Szrj 	 be within the bounds of the subobject.  */
52938fd1498Szrj       tree field = TREE_OPERAND (ref, 1);
53038fd1498Szrj       tree type = TREE_TYPE (field);
53138fd1498Szrj       if (tree sz = TYPE_SIZE_UNIT (type))
53238fd1498Szrj 	if (TREE_CODE (sz) == INTEGER_CST)
53338fd1498Szrj 	  {
53438fd1498Szrj 	    size = refoff + wi::to_offset (sz);
53538fd1498Szrj 	    obj = ref;
53638fd1498Szrj 	  }
53738fd1498Szrj     }
53838fd1498Szrj 
53938fd1498Szrj   if (endoff <= size)
54038fd1498Szrj     return NULL_TREE;
54138fd1498Szrj 
54238fd1498Szrj   /* Set the out-of-bounds offset range to be one greater than
54338fd1498Szrj      that delimited by the reference including its size.  */
54438fd1498Szrj   ooboff[lob] = size + 1;
54538fd1498Szrj 
54638fd1498Szrj   if (endoff > ooboff[lob])
54738fd1498Szrj     ooboff[hib] = endoff;
54838fd1498Szrj   else
54938fd1498Szrj     ooboff[hib] = wi::smax (offrng[lob], 0) + sizrange[1];
55038fd1498Szrj 
55138fd1498Szrj   return obj;
55238fd1498Szrj }
55338fd1498Szrj 
55438fd1498Szrj /* Create an association between the memory references DST and SRC
55538fd1498Szrj    for access by a call EXPR to a memory or string built-in funtion.  */
55638fd1498Szrj 
builtin_access(gcall * call,builtin_memref & dst,builtin_memref & src)55738fd1498Szrj builtin_access::builtin_access (gcall *call, builtin_memref &dst,
55838fd1498Szrj 				builtin_memref &src)
55938fd1498Szrj : dstref (&dst), srcref (&src), sizrange (), ovloff (), ovlsiz (),
56038fd1498Szrj   dstoff (), srcoff (), dstsiz (), srcsiz ()
56138fd1498Szrj {
56238fd1498Szrj   /* Zero out since the offset_int ctors invoked above are no-op.  */
56338fd1498Szrj   dstoff[0] = dstoff[1] = 0;
56438fd1498Szrj   srcoff[0] = srcoff[1] = 0;
56538fd1498Szrj   dstsiz[0] = dstsiz[1] = 0;
56638fd1498Szrj   srcsiz[0] = srcsiz[1] = 0;
56738fd1498Szrj 
56838fd1498Szrj   /* Object Size Type to use to determine the size of the destination
56938fd1498Szrj      and source objects.  Overridden below for raw memory functions.  */
57038fd1498Szrj   int ostype = 1;
57138fd1498Szrj 
57238fd1498Szrj   /* True when the size of one reference depends on the offset of
57338fd1498Szrj      itself or the other.  */
57438fd1498Szrj   bool depends_p = true;
57538fd1498Szrj 
57638fd1498Szrj   /* True when the size of the destination reference DSTREF has been
57738fd1498Szrj      determined from SRCREF and so needs to be adjusted by the latter's
57838fd1498Szrj      offset.  Only meaningful for bounded string functions like strncpy.  */
57938fd1498Szrj   bool dstadjust_p = false;
58038fd1498Szrj 
58138fd1498Szrj   /* The size argument number (depends on the built-in).  */
58238fd1498Szrj   unsigned sizeargno = 2;
58338fd1498Szrj   if (gimple_call_with_bounds_p (call))
58438fd1498Szrj     sizeargno += 2;
58538fd1498Szrj 
58638fd1498Szrj   tree func = gimple_call_fndecl (call);
58738fd1498Szrj   switch (DECL_FUNCTION_CODE (func))
58838fd1498Szrj     {
58938fd1498Szrj     case BUILT_IN_MEMCPY:
59038fd1498Szrj     case BUILT_IN_MEMCPY_CHK:
59138fd1498Szrj     case BUILT_IN_MEMCPY_CHKP:
59238fd1498Szrj     case BUILT_IN_MEMCPY_CHK_CHKP:
59338fd1498Szrj     case BUILT_IN_MEMPCPY:
59438fd1498Szrj     case BUILT_IN_MEMPCPY_CHK:
59538fd1498Szrj     case BUILT_IN_MEMPCPY_CHKP:
59638fd1498Szrj     case BUILT_IN_MEMPCPY_CHK_CHKP:
59738fd1498Szrj       ostype = 0;
59838fd1498Szrj       depends_p = false;
59938fd1498Szrj       detect_overlap = &builtin_access::generic_overlap;
60038fd1498Szrj       break;
60138fd1498Szrj 
60238fd1498Szrj     case BUILT_IN_MEMMOVE:
60338fd1498Szrj     case BUILT_IN_MEMMOVE_CHK:
60438fd1498Szrj     case BUILT_IN_MEMMOVE_CHKP:
60538fd1498Szrj     case BUILT_IN_MEMMOVE_CHK_CHKP:
60638fd1498Szrj       /* For memmove there is never any overlap to check for.  */
60738fd1498Szrj       ostype = 0;
60838fd1498Szrj       depends_p = false;
60938fd1498Szrj       detect_overlap = &builtin_access::no_overlap;
61038fd1498Szrj       break;
61138fd1498Szrj 
61238fd1498Szrj     case BUILT_IN_STPNCPY:
61338fd1498Szrj     case BUILT_IN_STPNCPY_CHK:
61438fd1498Szrj     case BUILT_IN_STRNCPY:
61538fd1498Szrj     case BUILT_IN_STRNCPY_CHK:
61638fd1498Szrj       dstref->strbounded_p = true;
61738fd1498Szrj       detect_overlap = &builtin_access::strcpy_overlap;
61838fd1498Szrj       break;
61938fd1498Szrj 
62038fd1498Szrj     case BUILT_IN_STPCPY:
62138fd1498Szrj     case BUILT_IN_STPCPY_CHK:
62238fd1498Szrj     case BUILT_IN_STPCPY_CHKP:
62338fd1498Szrj     case BUILT_IN_STPCPY_CHK_CHKP:
62438fd1498Szrj     case BUILT_IN_STRCPY:
62538fd1498Szrj     case BUILT_IN_STRCPY_CHK:
62638fd1498Szrj     case BUILT_IN_STRCPY_CHKP:
62738fd1498Szrj     case BUILT_IN_STRCPY_CHK_CHKP:
62838fd1498Szrj       detect_overlap = &builtin_access::strcpy_overlap;
62938fd1498Szrj       break;
63038fd1498Szrj 
63138fd1498Szrj     case BUILT_IN_STRCAT:
63238fd1498Szrj     case BUILT_IN_STRCAT_CHK:
63338fd1498Szrj     case BUILT_IN_STRCAT_CHKP:
63438fd1498Szrj     case BUILT_IN_STRCAT_CHK_CHKP:
63538fd1498Szrj       detect_overlap = &builtin_access::strcat_overlap;
63638fd1498Szrj       break;
63738fd1498Szrj 
63838fd1498Szrj     case BUILT_IN_STRNCAT:
63938fd1498Szrj     case BUILT_IN_STRNCAT_CHK:
64038fd1498Szrj       dstref->strbounded_p = true;
64138fd1498Szrj       srcref->strbounded_p = true;
64238fd1498Szrj       detect_overlap = &builtin_access::strcat_overlap;
64338fd1498Szrj       break;
64438fd1498Szrj 
64538fd1498Szrj     default:
64638fd1498Szrj       /* Handle other string functions here whose access may need
64738fd1498Szrj 	 to be validated for in-bounds offsets and non-overlapping
64838fd1498Szrj 	 copies.  (Not all _chkp functions have BUILT_IN_XXX_CHKP
64938fd1498Szrj 	 macros so they need to be handled here.)  */
65038fd1498Szrj       return;
65138fd1498Szrj     }
65238fd1498Szrj 
65338fd1498Szrj   const offset_int maxobjsize = tree_to_shwi (max_object_size ());
65438fd1498Szrj 
65538fd1498Szrj   /* Try to determine the size of the base object.  compute_objsize
65638fd1498Szrj      expects a pointer so create one if BASE is a non-pointer object.  */
65738fd1498Szrj   tree addr;
65838fd1498Szrj   if (dst.basesize < 0)
65938fd1498Szrj     {
66038fd1498Szrj       addr = dst.base;
66138fd1498Szrj       if (!POINTER_TYPE_P (TREE_TYPE (addr)))
66238fd1498Szrj 	addr = build1 (ADDR_EXPR, (TREE_TYPE (addr)), addr);
66338fd1498Szrj 
66438fd1498Szrj       if (tree dstsize = compute_objsize (addr, ostype))
66538fd1498Szrj 	dst.basesize = wi::to_offset (dstsize);
66638fd1498Szrj       else if (POINTER_TYPE_P (TREE_TYPE (addr)))
66738fd1498Szrj 	dst.basesize = HOST_WIDE_INT_MIN;
66838fd1498Szrj       else
66938fd1498Szrj 	dst.basesize = maxobjsize;
67038fd1498Szrj     }
67138fd1498Szrj 
67238fd1498Szrj   if (src.basesize < 0)
67338fd1498Szrj     {
67438fd1498Szrj       addr = src.base;
67538fd1498Szrj       if (!POINTER_TYPE_P (TREE_TYPE (addr)))
67638fd1498Szrj 	addr = build1 (ADDR_EXPR, (TREE_TYPE (addr)), addr);
67738fd1498Szrj 
67838fd1498Szrj       if (tree srcsize = compute_objsize (addr, ostype))
67938fd1498Szrj 	src.basesize = wi::to_offset (srcsize);
68038fd1498Szrj       else if (POINTER_TYPE_P (TREE_TYPE (addr)))
68138fd1498Szrj 	src.basesize = HOST_WIDE_INT_MIN;
68238fd1498Szrj       else
68338fd1498Szrj 	src.basesize = maxobjsize;
68438fd1498Szrj     }
68538fd1498Szrj 
68638fd1498Szrj   /* If there is no dependency between the references or the base
68738fd1498Szrj      objects of the two references aren't the same there's nothing
68838fd1498Szrj      else to do.  */
68938fd1498Szrj   if (depends_p && dstref->base != srcref->base)
69038fd1498Szrj     return;
69138fd1498Szrj 
69238fd1498Szrj   /* ...otherwise, make adjustments for references to the same object
69338fd1498Szrj      by string built-in functions to reflect the constraints imposed
69438fd1498Szrj      by the function.  */
69538fd1498Szrj 
69638fd1498Szrj   /* For bounded string functions determine the range of the bound
69738fd1498Szrj      on the access.  For others, the range stays unbounded.  */
69838fd1498Szrj   offset_int bounds[2] = { maxobjsize, maxobjsize };
69938fd1498Szrj   if (dstref->strbounded_p)
70038fd1498Szrj     {
701*e215fc28Szrj       unsigned nargs = gimple_call_num_args (call);
702*e215fc28Szrj       if (nargs <= sizeargno)
703*e215fc28Szrj 	return;
704*e215fc28Szrj 
70538fd1498Szrj       tree size = gimple_call_arg (call, sizeargno);
70638fd1498Szrj       tree range[2];
70738fd1498Szrj       if (get_size_range (size, range, true))
70838fd1498Szrj 	{
70938fd1498Szrj 	  bounds[0] = wi::to_offset (range[0]);
71038fd1498Szrj 	  bounds[1] = wi::to_offset (range[1]);
71138fd1498Szrj 	}
71238fd1498Szrj 
71338fd1498Szrj       /* If both references' size ranges are indeterminate use the last
71438fd1498Szrj 	 (size) argument from the function call as a substitute.  This
71538fd1498Szrj 	 may only be necessary for strncpy (but not for memcpy where
71638fd1498Szrj 	 the size range would have been already determined this way).  */
71738fd1498Szrj       if (dstref->sizrange[0] == 0 && dstref->sizrange[1] == maxobjsize
71838fd1498Szrj 	  && srcref->sizrange[0] == 0 && srcref->sizrange[1] == maxobjsize)
71938fd1498Szrj 	{
72038fd1498Szrj 	  dstref->sizrange[0] = bounds[0];
72138fd1498Szrj 	  dstref->sizrange[1] = bounds[1];
72238fd1498Szrj 	}
72338fd1498Szrj     }
72438fd1498Szrj 
72538fd1498Szrj   /* The size range of one reference involving the same base object
72638fd1498Szrj      can be determined from the size range of the other reference.
72738fd1498Szrj      This makes it possible to compute accurate offsets for warnings
72838fd1498Szrj      involving functions like strcpy where the length of just one of
72938fd1498Szrj      the two arguments is known (determined by tree-ssa-strlen).  */
73038fd1498Szrj   if (dstref->sizrange[0] == 0 && dstref->sizrange[1] == maxobjsize)
73138fd1498Szrj     {
73238fd1498Szrj       /* When the destination size is unknown set it to the size of
73338fd1498Szrj 	 the source.  */
73438fd1498Szrj       dstref->sizrange[0] = srcref->sizrange[0];
73538fd1498Szrj       dstref->sizrange[1] = srcref->sizrange[1];
73638fd1498Szrj     }
73738fd1498Szrj   else if (srcref->sizrange[0] == 0 && srcref->sizrange[1] == maxobjsize)
73838fd1498Szrj     {
73938fd1498Szrj       /* When the source size is unknown set it to the size of
74038fd1498Szrj 	 the destination.  */
74138fd1498Szrj       srcref->sizrange[0] = dstref->sizrange[0];
74238fd1498Szrj       srcref->sizrange[1] = dstref->sizrange[1];
74338fd1498Szrj 
74438fd1498Szrj       if (depends_p)
74538fd1498Szrj 	{
74638fd1498Szrj 	  if (dstref->strbounded_p)
74738fd1498Szrj 	    {
74838fd1498Szrj 	      /* Read access by strncpy is bounded.  */
74938fd1498Szrj 	      if (bounds[0] < srcref->sizrange[0])
75038fd1498Szrj 		srcref->sizrange[0] = bounds[0];
75138fd1498Szrj 	      if (bounds[1] < srcref->sizrange[1])
75238fd1498Szrj 		srcref->sizrange[1] = bounds[1];
75338fd1498Szrj 	    }
75438fd1498Szrj 
75538fd1498Szrj 	  /* For string functions, adjust the size range of the source
75638fd1498Szrj 	     reference by the inverse boundaries of the offset (because
75738fd1498Szrj 	     the higher the offset into the string the shorter its
75838fd1498Szrj 	     length).  */
75938fd1498Szrj 	  if (srcref->offrange[1] >= 0
76038fd1498Szrj 	      && srcref->offrange[1] < srcref->sizrange[0])
76138fd1498Szrj 	    srcref->sizrange[0] -= srcref->offrange[1];
76238fd1498Szrj 	  else
76338fd1498Szrj 	    srcref->sizrange[0] = 0;
76438fd1498Szrj 
76538fd1498Szrj 	  if (srcref->offrange[0] > 0)
76638fd1498Szrj 	    {
76738fd1498Szrj 	      if (srcref->offrange[0] < srcref->sizrange[1])
76838fd1498Szrj 		srcref->sizrange[1] -= srcref->offrange[0];
76938fd1498Szrj 	      else
77038fd1498Szrj 		srcref->sizrange[1] = 0;
77138fd1498Szrj 	    }
77238fd1498Szrj 
77338fd1498Szrj 	  dstadjust_p = true;
77438fd1498Szrj 	}
77538fd1498Szrj     }
77638fd1498Szrj 
77738fd1498Szrj   if (detect_overlap == &builtin_access::generic_overlap)
77838fd1498Szrj     {
77938fd1498Szrj       if (dstref->strbounded_p)
78038fd1498Szrj 	{
78138fd1498Szrj 	  dstref->sizrange[0] = bounds[0];
78238fd1498Szrj 	  dstref->sizrange[1] = bounds[1];
78338fd1498Szrj 
78438fd1498Szrj 	  if (dstref->sizrange[0] < srcref->sizrange[0])
78538fd1498Szrj 	    srcref->sizrange[0] = dstref->sizrange[0];
78638fd1498Szrj 
78738fd1498Szrj 	  if (dstref->sizrange[1] < srcref->sizrange[1])
78838fd1498Szrj 	    srcref->sizrange[1] = dstref->sizrange[1];
78938fd1498Szrj 	}
79038fd1498Szrj     }
79138fd1498Szrj   else if (detect_overlap == &builtin_access::strcpy_overlap)
79238fd1498Szrj     {
79338fd1498Szrj       if (!dstref->strbounded_p)
79438fd1498Szrj 	{
79538fd1498Szrj 	  /* For strcpy, adjust the destination size range to match that
79638fd1498Szrj 	     of the source computed above.  */
79738fd1498Szrj 	  if (depends_p && dstadjust_p)
79838fd1498Szrj 	    {
79938fd1498Szrj 	      dstref->sizrange[0] = srcref->sizrange[0];
80038fd1498Szrj 	      dstref->sizrange[1] = srcref->sizrange[1];
80138fd1498Szrj 	    }
80238fd1498Szrj 	}
80338fd1498Szrj     }
80438fd1498Szrj 
80538fd1498Szrj   if (dstref->strbounded_p)
80638fd1498Szrj     {
80738fd1498Szrj       /* For strncpy, adjust the destination size range to match that
80838fd1498Szrj 	 of the source computed above.  */
80938fd1498Szrj       dstref->sizrange[0] = bounds[0];
81038fd1498Szrj       dstref->sizrange[1] = bounds[1];
81138fd1498Szrj 
81238fd1498Szrj       if (bounds[0] < srcref->sizrange[0])
81338fd1498Szrj 	srcref->sizrange[0] = bounds[0];
81438fd1498Szrj 
81538fd1498Szrj       if (bounds[1] < srcref->sizrange[1])
81638fd1498Szrj 	srcref->sizrange[1] = bounds[1];
81738fd1498Szrj     }
81838fd1498Szrj }
81938fd1498Szrj 
82038fd1498Szrj offset_int
overlap_size(const offset_int a[2],const offset_int b[2],offset_int * off)82138fd1498Szrj builtin_access::overlap_size (const offset_int a[2], const offset_int b[2],
82238fd1498Szrj 			      offset_int *off)
82338fd1498Szrj {
82438fd1498Szrj   const offset_int *p = a;
82538fd1498Szrj   const offset_int *q = b;
82638fd1498Szrj 
82738fd1498Szrj   /* Point P at the bigger of the two ranges and Q at the smaller.  */
82838fd1498Szrj   if (wi::lts_p (a[1] - a[0], b[1] - b[0]))
82938fd1498Szrj     {
83038fd1498Szrj       p = b;
83138fd1498Szrj       q = a;
83238fd1498Szrj     }
83338fd1498Szrj 
83438fd1498Szrj   if (p[0] < q[0])
83538fd1498Szrj     {
83638fd1498Szrj       if (p[1] < q[0])
83738fd1498Szrj 	return 0;
83838fd1498Szrj 
83938fd1498Szrj       *off = q[0];
84038fd1498Szrj       return wi::smin (p[1], q[1]) - q[0];
84138fd1498Szrj     }
84238fd1498Szrj 
84338fd1498Szrj   if (q[1] < p[0])
84438fd1498Szrj     return 0;
84538fd1498Szrj 
84638fd1498Szrj   off[0] = p[0];
84738fd1498Szrj   return q[1] - p[0];
84838fd1498Szrj }
84938fd1498Szrj 
85038fd1498Szrj /* Return true if the bounded mempry (memcpy amd similar) or string function
85138fd1498Szrj    access (strncpy and similar) ACS overlaps.  */
85238fd1498Szrj 
85338fd1498Szrj bool
generic_overlap()85438fd1498Szrj builtin_access::generic_overlap ()
85538fd1498Szrj {
85638fd1498Szrj   builtin_access &acs = *this;
85738fd1498Szrj   const builtin_memref *dstref = acs.dstref;
85838fd1498Szrj   const builtin_memref *srcref = acs.srcref;
85938fd1498Szrj 
86038fd1498Szrj   gcc_assert (dstref->base == srcref->base);
86138fd1498Szrj 
86238fd1498Szrj   const offset_int maxobjsize = tree_to_shwi (max_object_size ());
86338fd1498Szrj 
86438fd1498Szrj   offset_int maxsize = dstref->basesize < 0 ? maxobjsize : dstref->basesize;
86538fd1498Szrj   gcc_assert (maxsize <= maxobjsize);
86638fd1498Szrj 
86738fd1498Szrj   /* Adjust the larger bounds of the offsets (which may be the first
86838fd1498Szrj      element if the lower bound is larger than the upper bound) to
86938fd1498Szrj      make them valid for the smallest access (if possible) but no smaller
87038fd1498Szrj      than the smaller bounds.  */
87138fd1498Szrj   gcc_assert (wi::les_p (acs.dstoff[0], acs.dstoff[1]));
87238fd1498Szrj 
87338fd1498Szrj   if (maxsize < acs.dstoff[1] + acs.dstsiz[0])
87438fd1498Szrj     acs.dstoff[1] = maxsize - acs.dstsiz[0];
87538fd1498Szrj   if (acs.dstoff[1] < acs.dstoff[0])
87638fd1498Szrj     acs.dstoff[1] = acs.dstoff[0];
87738fd1498Szrj 
87838fd1498Szrj   gcc_assert (wi::les_p (acs.srcoff[0], acs.srcoff[1]));
87938fd1498Szrj 
88038fd1498Szrj   if (maxsize < acs.srcoff[1] + acs.srcsiz[0])
88138fd1498Szrj     acs.srcoff[1] = maxsize - acs.srcsiz[0];
88238fd1498Szrj   if (acs.srcoff[1] < acs.srcoff[0])
88338fd1498Szrj     acs.srcoff[1] = acs.srcoff[0];
88438fd1498Szrj 
88538fd1498Szrj   /* Determine the minimum and maximum space for the access given
88638fd1498Szrj      the offsets.  */
88738fd1498Szrj   offset_int space[2];
88838fd1498Szrj   space[0] = wi::abs (acs.dstoff[0] - acs.srcoff[0]);
88938fd1498Szrj   space[1] = space[0];
89038fd1498Szrj 
89138fd1498Szrj   offset_int d = wi::abs (acs.dstoff[0] - acs.srcoff[1]);
89238fd1498Szrj   if (acs.srcsiz[0] > 0)
89338fd1498Szrj     {
89438fd1498Szrj       if (d < space[0])
89538fd1498Szrj 	space[0] = d;
89638fd1498Szrj 
89738fd1498Szrj       if (space[1] < d)
89838fd1498Szrj 	space[1] = d;
89938fd1498Szrj     }
90038fd1498Szrj   else
90138fd1498Szrj     space[1] = acs.dstsiz[1];
90238fd1498Szrj 
90338fd1498Szrj   d = wi::abs (acs.dstoff[1] - acs.srcoff[0]);
90438fd1498Szrj   if (d < space[0])
90538fd1498Szrj     space[0] = d;
90638fd1498Szrj 
90738fd1498Szrj   if (space[1] < d)
90838fd1498Szrj     space[1] = d;
90938fd1498Szrj 
91038fd1498Szrj   /* Treat raw memory functions both of whose references are bounded
91138fd1498Szrj      as special and permit uncertain overlaps to go undetected.  For
91238fd1498Szrj      all kinds of constant offset and constant size accesses, if
91338fd1498Szrj      overlap isn't certain it is not possible.  */
91438fd1498Szrj   bool overlap_possible = space[0] < acs.dstsiz[1];
91538fd1498Szrj   if (!overlap_possible)
91638fd1498Szrj     return false;
91738fd1498Szrj 
91838fd1498Szrj   bool overlap_certain = space[1] < acs.dstsiz[0];
91938fd1498Szrj 
92038fd1498Szrj   /* True when the size of one reference depends on the offset of
92138fd1498Szrj      the other.  */
92238fd1498Szrj   bool depends_p = detect_overlap != &builtin_access::generic_overlap;
92338fd1498Szrj 
92438fd1498Szrj   if (!overlap_certain)
92538fd1498Szrj     {
92638fd1498Szrj       if (!dstref->strbounded_p && !depends_p)
92738fd1498Szrj 	/* Memcpy only considers certain overlap.  */
92838fd1498Szrj 	return false;
92938fd1498Szrj 
93038fd1498Szrj       /* There's no way to distinguish an access to the same member
93138fd1498Szrj 	 of a structure from one to two distinct members of the same
93238fd1498Szrj 	 structure.  Give up to avoid excessive false positives.  */
93338fd1498Szrj       tree basetype = TREE_TYPE (dstref->base);
93438fd1498Szrj 
93538fd1498Szrj       if (POINTER_TYPE_P (basetype))
93638fd1498Szrj 	basetype = TREE_TYPE (basetype);
93738fd1498Szrj       else
93838fd1498Szrj 	while (TREE_CODE (basetype) == ARRAY_TYPE)
93938fd1498Szrj 	  basetype = TREE_TYPE (basetype);
94038fd1498Szrj 
94138fd1498Szrj       if (RECORD_OR_UNION_TYPE_P (basetype))
94238fd1498Szrj 	return false;
94338fd1498Szrj     }
94438fd1498Szrj 
94538fd1498Szrj   /* True for stpcpy and strcpy.  */
94638fd1498Szrj   bool stxcpy_p = (!dstref->strbounded_p
94738fd1498Szrj 		   && detect_overlap == &builtin_access::strcpy_overlap);
94838fd1498Szrj 
94938fd1498Szrj   if (dstref->refoff >= 0
95038fd1498Szrj       && srcref->refoff >= 0
95138fd1498Szrj       && dstref->refoff != srcref->refoff
95238fd1498Szrj       && (stxcpy_p || dstref->strbounded_p || srcref->strbounded_p))
95338fd1498Szrj     return false;
95438fd1498Szrj 
95538fd1498Szrj   offset_int siz[2] = { maxobjsize + 1, 0 };
95638fd1498Szrj 
95738fd1498Szrj   ovloff[0] = HOST_WIDE_INT_MAX;
95838fd1498Szrj   ovloff[1] = HOST_WIDE_INT_MIN;
95938fd1498Szrj 
96038fd1498Szrj   /* Adjustment to the lower bound of the offset of the overlap to
96138fd1498Szrj      account for a subset of unbounded string calls where the size
96238fd1498Szrj      of the destination string depends on the length of the source
96338fd1498Szrj      which in turn depends on the offset into it.  */
96438fd1498Szrj   bool sub1;
96538fd1498Szrj 
96638fd1498Szrj   if (stxcpy_p)
96738fd1498Szrj     {
96838fd1498Szrj       sub1 = acs.dstoff[0] <= acs.srcoff[0];
96938fd1498Szrj 
97038fd1498Szrj       /* Iterate over the extreme locations (on the horizontal axis formed
97138fd1498Szrj 	 by their offsets) and sizes of two regions and find their smallest
97238fd1498Szrj 	 and largest overlap and the corresponding offsets.  */
97338fd1498Szrj       for (unsigned i = 0; i != 2; ++i)
97438fd1498Szrj 	{
97538fd1498Szrj 	  const offset_int a[2] = {
97638fd1498Szrj 	    acs.dstoff[i], acs.dstoff[i] + acs.dstsiz[!i]
97738fd1498Szrj 	  };
97838fd1498Szrj 
97938fd1498Szrj 	  const offset_int b[2] = {
98038fd1498Szrj 	    acs.srcoff[i], acs.srcoff[i] + acs.srcsiz[!i]
98138fd1498Szrj 	  };
98238fd1498Szrj 
98338fd1498Szrj 	  offset_int off;
98438fd1498Szrj 	  offset_int sz = overlap_size (a, b, &off);
98538fd1498Szrj 	  if (sz < siz[0])
98638fd1498Szrj 	    siz[0] = sz;
98738fd1498Szrj 
98838fd1498Szrj 	  if (siz[1] <= sz)
98938fd1498Szrj 	    siz[1] = sz;
99038fd1498Szrj 
99138fd1498Szrj 	  if (sz != 0)
99238fd1498Szrj 	    {
99338fd1498Szrj 	      if (wi::lts_p (off, ovloff[0]))
99438fd1498Szrj 		ovloff[0] = off.to_shwi ();
99538fd1498Szrj 	      if (wi::lts_p (ovloff[1], off))
99638fd1498Szrj 		ovloff[1] = off.to_shwi ();
99738fd1498Szrj 	    }
99838fd1498Szrj 	}
99938fd1498Szrj     }
100038fd1498Szrj   else
100138fd1498Szrj     {
100238fd1498Szrj       sub1 = !depends_p;
100338fd1498Szrj 
100438fd1498Szrj       /* Iterate over the extreme locations (on the horizontal axis
100538fd1498Szrj 	 formed by their offsets) and sizes of two regions and find
100638fd1498Szrj 	 their smallest and largest overlap and the corresponding
100738fd1498Szrj 	 offsets.  */
100838fd1498Szrj 
100938fd1498Szrj       for (unsigned io = 0; io != 2; ++io)
101038fd1498Szrj 	for (unsigned is = 0; is != 2; ++is)
101138fd1498Szrj 	  {
101238fd1498Szrj 	    const offset_int a[2] = {
101338fd1498Szrj 	      acs.dstoff[io], acs.dstoff[io] + acs.dstsiz[is]
101438fd1498Szrj 	    };
101538fd1498Szrj 
101638fd1498Szrj 	    for (unsigned jo = 0; jo != 2; ++jo)
101738fd1498Szrj 	      for (unsigned js = 0; js != 2; ++js)
101838fd1498Szrj 		{
101938fd1498Szrj 		  if (depends_p)
102038fd1498Szrj 		    {
102138fd1498Szrj 		      /* For st{p,r}ncpy the size of the source sequence
102238fd1498Szrj 			 depends on the offset into it.  */
102338fd1498Szrj 		      if (js)
102438fd1498Szrj 			break;
102538fd1498Szrj 		      js = !jo;
102638fd1498Szrj 		    }
102738fd1498Szrj 
102838fd1498Szrj 		  const offset_int b[2] = {
102938fd1498Szrj 		    acs.srcoff[jo], acs.srcoff[jo] + acs.srcsiz[js]
103038fd1498Szrj 		  };
103138fd1498Szrj 
103238fd1498Szrj 		  offset_int off;
103338fd1498Szrj 		  offset_int sz = overlap_size (a, b, &off);
103438fd1498Szrj 		  if (sz < siz[0])
103538fd1498Szrj 		    siz[0] = sz;
103638fd1498Szrj 
103738fd1498Szrj 		  if (siz[1] <= sz)
103838fd1498Szrj 		    siz[1] = sz;
103938fd1498Szrj 
104038fd1498Szrj 		  if (sz != 0)
104138fd1498Szrj 		    {
104238fd1498Szrj 		      if (wi::lts_p (off, ovloff[0]))
104338fd1498Szrj 			ovloff[0] = off.to_shwi ();
104438fd1498Szrj 		      if (wi::lts_p (ovloff[1], off))
104538fd1498Szrj 			ovloff[1] = off.to_shwi ();
104638fd1498Szrj 		    }
104738fd1498Szrj 		}
104838fd1498Szrj 	  }
104938fd1498Szrj     }
105038fd1498Szrj 
105138fd1498Szrj   ovlsiz[0] = siz[0].to_shwi ();
105238fd1498Szrj   ovlsiz[1] = siz[1].to_shwi ();
105338fd1498Szrj 
105438fd1498Szrj   if (ovlsiz[0] == 0 && ovlsiz[1] > 1)
105538fd1498Szrj     ovloff[0] = ovloff[1] + ovlsiz[1] - 1 - sub1;
105638fd1498Szrj 
105738fd1498Szrj   return true;
105838fd1498Szrj }
105938fd1498Szrj 
106038fd1498Szrj /* Return true if the strcat-like access overlaps.  */
106138fd1498Szrj 
106238fd1498Szrj bool
strcat_overlap()106338fd1498Szrj builtin_access::strcat_overlap ()
106438fd1498Szrj {
106538fd1498Szrj   builtin_access &acs = *this;
106638fd1498Szrj   const builtin_memref *dstref = acs.dstref;
106738fd1498Szrj   const builtin_memref *srcref = acs.srcref;
106838fd1498Szrj 
106938fd1498Szrj   gcc_assert (dstref->base == srcref->base);
107038fd1498Szrj 
107138fd1498Szrj   const offset_int maxobjsize = tree_to_shwi (max_object_size ());
107238fd1498Szrj 
107338fd1498Szrj   gcc_assert (dstref->base && dstref->base == srcref->base);
107438fd1498Szrj 
107538fd1498Szrj   /* Adjust for strcat-like accesses.  */
107638fd1498Szrj 
107738fd1498Szrj   /* As a special case for strcat, set the DSTREF offsets to the length
107838fd1498Szrj      of the source string since the function starts writing at the first
107938fd1498Szrj      nul, and set the size to 1 for the length of the nul.  */
108038fd1498Szrj   acs.dstoff[0] += acs.dstsiz[0];
108138fd1498Szrj   acs.dstoff[1] += acs.dstsiz[1];
108238fd1498Szrj 
108338fd1498Szrj   bool strfunc_unknown_args = acs.dstsiz[0] == 0 && acs.dstsiz[1] != 0;
108438fd1498Szrj 
108538fd1498Szrj   /* The lower bound is zero when the size is unknown because then
108638fd1498Szrj      overlap is not certain.  */
108738fd1498Szrj   acs.dstsiz[0] = strfunc_unknown_args ? 0 : 1;
108838fd1498Szrj   acs.dstsiz[1] = 1;
108938fd1498Szrj 
109038fd1498Szrj   offset_int maxsize = dstref->basesize < 0 ? maxobjsize : dstref->basesize;
109138fd1498Szrj   gcc_assert (maxsize <= maxobjsize);
109238fd1498Szrj 
109338fd1498Szrj   /* For references to the same base object, determine if there's a pair
109438fd1498Szrj      of valid offsets into the two references such that access between
109538fd1498Szrj      them doesn't overlap.  Adjust both upper bounds to be valid for
109638fd1498Szrj      the smaller size (i.e., at most MAXSIZE - SIZE).  */
109738fd1498Szrj 
109838fd1498Szrj   if (maxsize < acs.dstoff[1] + acs.dstsiz[0])
109938fd1498Szrj     acs.dstoff[1] = maxsize - acs.dstsiz[0];
110038fd1498Szrj 
110138fd1498Szrj   if (maxsize < acs.srcoff[1] + acs.srcsiz[0])
110238fd1498Szrj     acs.srcoff[1] = maxsize - acs.srcsiz[0];
110338fd1498Szrj 
110438fd1498Szrj   /* Check to see if there's enough space for both accesses without
110538fd1498Szrj      overlap.  Determine the optimistic (maximum) amount of available
110638fd1498Szrj      space.  */
110738fd1498Szrj   offset_int space;
110838fd1498Szrj   if (acs.dstoff[0] <= acs.srcoff[0])
110938fd1498Szrj     {
111038fd1498Szrj       if (acs.dstoff[1] < acs.srcoff[1])
111138fd1498Szrj 	space = acs.srcoff[1] + acs.srcsiz[0] - acs.dstoff[0];
111238fd1498Szrj       else
111338fd1498Szrj 	space = acs.dstoff[1] + acs.dstsiz[0] - acs.srcoff[0];
111438fd1498Szrj     }
111538fd1498Szrj   else
111638fd1498Szrj     space = acs.dstoff[1] + acs.dstsiz[0] - acs.srcoff[0];
111738fd1498Szrj 
111838fd1498Szrj   /* Overlap is certain if the distance between the farthest offsets
111938fd1498Szrj      of the opposite accesses is less than the sum of the lower bounds
112038fd1498Szrj      of the sizes of the two accesses.  */
112138fd1498Szrj   bool overlap_certain = space < acs.dstsiz[0] + acs.srcsiz[0];
112238fd1498Szrj 
112338fd1498Szrj   /* For a constant-offset, constant size access, consider the largest
112438fd1498Szrj      distance between the offset bounds and the lower bound of the access
112538fd1498Szrj      size.  If the overlap isn't certain return success.  */
112638fd1498Szrj   if (!overlap_certain
112738fd1498Szrj       && acs.dstoff[0] == acs.dstoff[1]
112838fd1498Szrj       && acs.srcoff[0] == acs.srcoff[1]
112938fd1498Szrj       && acs.dstsiz[0] == acs.dstsiz[1]
113038fd1498Szrj       && acs.srcsiz[0] == acs.srcsiz[1])
113138fd1498Szrj     return false;
113238fd1498Szrj 
113338fd1498Szrj   /* Overlap is not certain but may be possible.  */
113438fd1498Szrj 
113538fd1498Szrj   offset_int access_min = acs.dstsiz[0] + acs.srcsiz[0];
113638fd1498Szrj 
113738fd1498Szrj   /* Determine the conservative (minimum) amount of space.  */
113838fd1498Szrj   space = wi::abs (acs.dstoff[0] - acs.srcoff[0]);
113938fd1498Szrj   offset_int d = wi::abs (acs.dstoff[0] - acs.srcoff[1]);
114038fd1498Szrj   if (d < space)
114138fd1498Szrj     space = d;
114238fd1498Szrj   d = wi::abs (acs.dstoff[1] - acs.srcoff[0]);
114338fd1498Szrj   if (d < space)
114438fd1498Szrj     space = d;
114538fd1498Szrj 
114638fd1498Szrj   /* For a strict test (used for strcpy and similar with unknown or
114738fd1498Szrj      variable bounds or sizes), consider the smallest distance between
114838fd1498Szrj      the offset bounds and either the upper bound of the access size
114938fd1498Szrj      if known, or the lower bound otherwise.  */
115038fd1498Szrj   if (access_min <= space && (access_min != 0 || !strfunc_unknown_args))
115138fd1498Szrj     return false;
115238fd1498Szrj 
115338fd1498Szrj   /* When strcat overlap is certain it is always a single byte:
115438fd1498Szrj      the terminating NUL, regardless of offsets and sizes.  When
115538fd1498Szrj      overlap is only possible its range is [0, 1].  */
115638fd1498Szrj   acs.ovlsiz[0] = dstref->sizrange[0] == dstref->sizrange[1] ? 1 : 0;
115738fd1498Szrj   acs.ovlsiz[1] = 1;
115838fd1498Szrj 
115938fd1498Szrj   offset_int endoff = dstref->offrange[0] + dstref->sizrange[0];
116038fd1498Szrj   if (endoff <= srcref->offrange[0])
116138fd1498Szrj     acs.ovloff[0] = wi::smin (maxobjsize, srcref->offrange[0]).to_shwi ();
116238fd1498Szrj   else
116338fd1498Szrj     acs.ovloff[0] = wi::smin (maxobjsize, endoff).to_shwi ();
116438fd1498Szrj 
116538fd1498Szrj   acs.sizrange[0] = wi::smax (wi::abs (endoff - srcref->offrange[0]) + 1,
116638fd1498Szrj 			      srcref->sizrange[0]).to_shwi ();
116738fd1498Szrj   if (dstref->offrange[0] == dstref->offrange[1])
116838fd1498Szrj     {
116938fd1498Szrj       if (srcref->offrange[0] == srcref->offrange[1])
117038fd1498Szrj 	acs.ovloff[1] = acs.ovloff[0];
117138fd1498Szrj       else
117238fd1498Szrj 	acs.ovloff[1]
117338fd1498Szrj 	  = wi::smin (maxobjsize,
117438fd1498Szrj 		      srcref->offrange[1] + srcref->sizrange[1]).to_shwi ();
117538fd1498Szrj     }
117638fd1498Szrj   else
117738fd1498Szrj     acs.ovloff[1]
117838fd1498Szrj       = wi::smin (maxobjsize,
117938fd1498Szrj 		  dstref->offrange[1] + dstref->sizrange[1]).to_shwi ();
118038fd1498Szrj 
118138fd1498Szrj   if (acs.sizrange[0] == 0)
118238fd1498Szrj     acs.sizrange[0] = 1;
118338fd1498Szrj   acs.sizrange[1] = wi::smax (acs.dstsiz[1], srcref->sizrange[1]).to_shwi ();
118438fd1498Szrj   return true;
118538fd1498Szrj }
118638fd1498Szrj 
118738fd1498Szrj /* Return true if the strcpy-like access overlaps.  */
118838fd1498Szrj 
118938fd1498Szrj bool
strcpy_overlap()119038fd1498Szrj builtin_access::strcpy_overlap ()
119138fd1498Szrj {
119238fd1498Szrj   return generic_overlap ();
119338fd1498Szrj }
119438fd1498Szrj 
119538fd1498Szrj 
119638fd1498Szrj /* Return true if DSTREF and SRCREF describe accesses that either overlap
119738fd1498Szrj    one another or that, in order not to overlap, would imply that the size
119838fd1498Szrj    of the referenced object(s) exceeds the maximum size of an object.  Set
119938fd1498Szrj    Otherwise, if DSTREF and SRCREF do not definitely overlap (even though
120038fd1498Szrj    they may overlap in a way that's not apparent from the available data),
120138fd1498Szrj    return false.  */
120238fd1498Szrj 
120338fd1498Szrj bool
overlap()120438fd1498Szrj builtin_access::overlap ()
120538fd1498Szrj {
120638fd1498Szrj   builtin_access &acs = *this;
120738fd1498Szrj 
120838fd1498Szrj   const offset_int maxobjsize = tree_to_shwi (max_object_size ());
120938fd1498Szrj 
121038fd1498Szrj   acs.sizrange[0] = wi::smax (dstref->sizrange[0],
121138fd1498Szrj 			      srcref->sizrange[0]).to_shwi ();
121238fd1498Szrj   acs.sizrange[1] = wi::smax (dstref->sizrange[1],
121338fd1498Szrj 			      srcref->sizrange[1]).to_shwi ();
121438fd1498Szrj 
121538fd1498Szrj   /* Check to see if the two references refer to regions that are
121638fd1498Szrj      too large not to overlap in the address space (whose maximum
121738fd1498Szrj      size is PTRDIFF_MAX).  */
121838fd1498Szrj   offset_int size = dstref->sizrange[0] + srcref->sizrange[0];
121938fd1498Szrj   if (maxobjsize < size)
122038fd1498Szrj     {
122138fd1498Szrj       acs.ovloff[0] = (maxobjsize - dstref->sizrange[0]).to_shwi ();
122238fd1498Szrj       acs.ovlsiz[0] = (size - maxobjsize).to_shwi ();
122338fd1498Szrj       return true;
122438fd1498Szrj     }
122538fd1498Szrj 
122638fd1498Szrj   /* If both base objects aren't known return the maximum possible
122738fd1498Szrj      offset that would make them not overlap.  */
122838fd1498Szrj   if (!dstref->base || !srcref->base)
122938fd1498Szrj     return false;
123038fd1498Szrj 
123138fd1498Szrj   /* Set the access offsets.  */
123238fd1498Szrj   acs.dstoff[0] = dstref->offrange[0];
123338fd1498Szrj   acs.dstoff[1] = dstref->offrange[1];
123438fd1498Szrj 
123538fd1498Szrj   /* If the base object is an array adjust the bounds of the offset
123638fd1498Szrj      to be non-negative and within the bounds of the array if possible.  */
123738fd1498Szrj   if (dstref->base
123838fd1498Szrj       && TREE_CODE (TREE_TYPE (dstref->base)) == ARRAY_TYPE)
123938fd1498Szrj     {
124038fd1498Szrj       if (acs.dstoff[0] < 0 && acs.dstoff[1] >= 0)
124138fd1498Szrj 	acs.dstoff[0] = 0;
124238fd1498Szrj 
124338fd1498Szrj       if (acs.dstoff[1] < acs.dstoff[0])
124438fd1498Szrj 	{
124538fd1498Szrj 	  if (tree size = TYPE_SIZE_UNIT (TREE_TYPE (dstref->base)))
124638fd1498Szrj 	    acs.dstoff[1] = wi::umin (acs.dstoff[1], wi::to_offset (size));
124738fd1498Szrj 	  else
124838fd1498Szrj 	    acs.dstoff[1] = wi::umin (acs.dstoff[1], maxobjsize);
124938fd1498Szrj 	}
125038fd1498Szrj     }
125138fd1498Szrj 
125238fd1498Szrj   acs.srcoff[0] = srcref->offrange[0];
125338fd1498Szrj   acs.srcoff[1] = srcref->offrange[1];
125438fd1498Szrj 
125538fd1498Szrj   if (srcref->base
125638fd1498Szrj       && TREE_CODE (TREE_TYPE (srcref->base)) == ARRAY_TYPE)
125738fd1498Szrj     {
125838fd1498Szrj       if (acs.srcoff[0] < 0 && acs.srcoff[1] >= 0)
125938fd1498Szrj 	acs.srcoff[0] = 0;
126038fd1498Szrj 
126138fd1498Szrj       if (tree size = TYPE_SIZE_UNIT (TREE_TYPE (srcref->base)))
126238fd1498Szrj 	acs.srcoff[1] = wi::umin (acs.srcoff[1], wi::to_offset (size));
126338fd1498Szrj       else if (acs.srcoff[1] < acs.srcoff[0])
126438fd1498Szrj 	acs.srcoff[1] = wi::umin (acs.srcoff[1], maxobjsize);
126538fd1498Szrj     }
126638fd1498Szrj 
126738fd1498Szrj   /* When the upper bound of the offset is less than the lower bound
126838fd1498Szrj      the former is the result of a negative offset being represented
126938fd1498Szrj      as a large positive value or vice versa.  The resulting range is
127038fd1498Szrj      a union of two subranges: [MIN, UB] and [LB, MAX].  Since such
127138fd1498Szrj      a union is not representable using the current data structure
127238fd1498Szrj      replace it with the full range of offsets.  */
127338fd1498Szrj   if (acs.dstoff[1] < acs.dstoff[0])
127438fd1498Szrj     {
127538fd1498Szrj       acs.dstoff[0] = -maxobjsize - 1;
127638fd1498Szrj       acs.dstoff[1] = maxobjsize;
127738fd1498Szrj     }
127838fd1498Szrj 
127938fd1498Szrj   /* Validate the offset and size of each reference on its own first.
128038fd1498Szrj      This is independent of whether or not the base objects are the
128138fd1498Szrj      same.  Normally, this would have already been detected and
128238fd1498Szrj      diagnosed by -Warray-bounds, unless it has been disabled.  */
128338fd1498Szrj   offset_int maxoff = acs.dstoff[0] + dstref->sizrange[0];
128438fd1498Szrj   if (maxobjsize < maxoff)
128538fd1498Szrj     {
128638fd1498Szrj       acs.ovlsiz[0] = (maxoff - maxobjsize).to_shwi ();
128738fd1498Szrj       acs.ovloff[0] = acs.dstoff[0].to_shwi () - acs.ovlsiz[0];
128838fd1498Szrj       return true;
128938fd1498Szrj     }
129038fd1498Szrj 
129138fd1498Szrj   /* Repeat the same as above but for the source offsets.  */
129238fd1498Szrj   if (acs.srcoff[1] < acs.srcoff[0])
129338fd1498Szrj     {
129438fd1498Szrj       acs.srcoff[0] = -maxobjsize - 1;
129538fd1498Szrj       acs.srcoff[1] = maxobjsize;
129638fd1498Szrj     }
129738fd1498Szrj 
129838fd1498Szrj   maxoff = acs.srcoff[0] + srcref->sizrange[0];
129938fd1498Szrj   if (maxobjsize < maxoff)
130038fd1498Szrj     {
130138fd1498Szrj       acs.ovlsiz[0] = (maxoff - maxobjsize).to_shwi ();
130238fd1498Szrj       acs.ovlsiz[1] = (acs.srcoff[0] + srcref->sizrange[1]
130338fd1498Szrj 		       - maxobjsize).to_shwi ();
130438fd1498Szrj       acs.ovloff[0] = acs.srcoff[0].to_shwi () - acs.ovlsiz[0];
130538fd1498Szrj       return true;
130638fd1498Szrj     }
130738fd1498Szrj 
130838fd1498Szrj   if (dstref->base != srcref->base)
130938fd1498Szrj     return false;
131038fd1498Szrj 
131138fd1498Szrj   acs.dstsiz[0] = dstref->sizrange[0];
131238fd1498Szrj   acs.dstsiz[1] = dstref->sizrange[1];
131338fd1498Szrj 
131438fd1498Szrj   acs.srcsiz[0] = srcref->sizrange[0];
131538fd1498Szrj   acs.srcsiz[1] = srcref->sizrange[1];
131638fd1498Szrj 
131738fd1498Szrj   /* Call the appropriate function to determine the overlap.  */
131838fd1498Szrj   if ((this->*detect_overlap) ())
131938fd1498Szrj     {
132038fd1498Szrj       if (!sizrange[1])
132138fd1498Szrj 	{
132238fd1498Szrj 	  /* Unless the access size range has already been set, do so here.  */
132338fd1498Szrj 	  sizrange[0] = wi::smax (acs.dstsiz[0], srcref->sizrange[0]).to_shwi ();
132438fd1498Szrj 	  sizrange[1] = wi::smax (acs.dstsiz[1], srcref->sizrange[1]).to_shwi ();
132538fd1498Szrj 	}
132638fd1498Szrj       return true;
132738fd1498Szrj     }
132838fd1498Szrj 
132938fd1498Szrj   return false;
133038fd1498Szrj }
133138fd1498Szrj 
133238fd1498Szrj /* Attempt to detect and diagnose an overlapping copy in a call expression
133338fd1498Szrj    EXPR involving an an access ACS to a built-in memory or string function.
133438fd1498Szrj    Return true when one has been detected, false otherwise.  */
133538fd1498Szrj 
133638fd1498Szrj static bool
maybe_diag_overlap(location_t loc,gcall * call,builtin_access & acs)133738fd1498Szrj maybe_diag_overlap (location_t loc, gcall *call, builtin_access &acs)
133838fd1498Szrj {
133938fd1498Szrj   if (!acs.overlap ())
134038fd1498Szrj     return false;
134138fd1498Szrj 
134238fd1498Szrj   /* For convenience.  */
134338fd1498Szrj   const builtin_memref &dstref = *acs.dstref;
134438fd1498Szrj   const builtin_memref &srcref = *acs.srcref;
134538fd1498Szrj 
134638fd1498Szrj   /* Determine the range of offsets and sizes of the overlap if it
134738fd1498Szrj      exists and issue diagnostics.  */
134838fd1498Szrj   HOST_WIDE_INT *ovloff = acs.ovloff;
134938fd1498Szrj   HOST_WIDE_INT *ovlsiz = acs.ovlsiz;
135038fd1498Szrj   HOST_WIDE_INT *sizrange = acs.sizrange;
135138fd1498Szrj 
135238fd1498Szrj   tree func = gimple_call_fndecl (call);
135338fd1498Szrj 
135438fd1498Szrj   /* To avoid a combinatorial explosion of diagnostics format the offsets
135538fd1498Szrj      or their ranges as strings and use them in the warning calls below.  */
135638fd1498Szrj   char offstr[3][64];
135738fd1498Szrj 
135838fd1498Szrj   if (dstref.offrange[0] == dstref.offrange[1]
135938fd1498Szrj       || dstref.offrange[1] > HOST_WIDE_INT_MAX)
136038fd1498Szrj     sprintf (offstr[0], HOST_WIDE_INT_PRINT_DEC,
136138fd1498Szrj 	     dstref.offrange[0].to_shwi ());
136238fd1498Szrj   else
136338fd1498Szrj     sprintf (offstr[0],
136438fd1498Szrj 	     "[" HOST_WIDE_INT_PRINT_DEC ", " HOST_WIDE_INT_PRINT_DEC "]",
136538fd1498Szrj 	     dstref.offrange[0].to_shwi (),
136638fd1498Szrj 	     dstref.offrange[1].to_shwi ());
136738fd1498Szrj 
136838fd1498Szrj   if (srcref.offrange[0] == srcref.offrange[1]
136938fd1498Szrj       || srcref.offrange[1] > HOST_WIDE_INT_MAX)
137038fd1498Szrj     sprintf (offstr[1],
137138fd1498Szrj 	     HOST_WIDE_INT_PRINT_DEC,
137238fd1498Szrj 	     srcref.offrange[0].to_shwi ());
137338fd1498Szrj   else
137438fd1498Szrj     sprintf (offstr[1],
137538fd1498Szrj 	     "[" HOST_WIDE_INT_PRINT_DEC ", " HOST_WIDE_INT_PRINT_DEC "]",
137638fd1498Szrj 	     srcref.offrange[0].to_shwi (),
137738fd1498Szrj 	     srcref.offrange[1].to_shwi ());
137838fd1498Szrj 
137938fd1498Szrj   if (ovloff[0] == ovloff[1] || !ovloff[1])
138038fd1498Szrj     sprintf (offstr[2], HOST_WIDE_INT_PRINT_DEC, ovloff[0]);
138138fd1498Szrj   else
138238fd1498Szrj     sprintf (offstr[2],
138338fd1498Szrj 	     "[" HOST_WIDE_INT_PRINT_DEC ", " HOST_WIDE_INT_PRINT_DEC "]",
138438fd1498Szrj 	     ovloff[0], ovloff[1]);
138538fd1498Szrj 
138638fd1498Szrj   const offset_int maxobjsize = tree_to_shwi (max_object_size ());
138738fd1498Szrj   bool must_overlap = ovlsiz[0] > 0;
138838fd1498Szrj 
138938fd1498Szrj   if (ovlsiz[1] == 0)
139038fd1498Szrj     ovlsiz[1] = ovlsiz[0];
139138fd1498Szrj 
139238fd1498Szrj   if (must_overlap)
139338fd1498Szrj     {
139438fd1498Szrj       /* Issue definitive "overlaps" diagnostic in this block.  */
139538fd1498Szrj 
139638fd1498Szrj       if (sizrange[0] == sizrange[1])
139738fd1498Szrj 	{
139838fd1498Szrj 	  if (ovlsiz[0] == ovlsiz[1])
139938fd1498Szrj 	    warning_at (loc, OPT_Wrestrict,
140038fd1498Szrj 			sizrange[0] == 1
140138fd1498Szrj 			? (ovlsiz[0] == 1
140238fd1498Szrj 			   ? G_("%G%qD accessing %wu byte at offsets %s "
140338fd1498Szrj 				"and %s overlaps %wu byte at offset %s")
140438fd1498Szrj 			   :  G_("%G%qD accessing %wu byte at offsets %s "
140538fd1498Szrj 				 "and %s overlaps %wu bytes at offset "
140638fd1498Szrj 				 "%s"))
140738fd1498Szrj 			: (ovlsiz[0] == 1
140838fd1498Szrj 			   ? G_("%G%qD accessing %wu bytes at offsets %s "
140938fd1498Szrj 				"and %s overlaps %wu byte at offset %s")
141038fd1498Szrj 			   : G_("%G%qD accessing %wu bytes at offsets %s "
141138fd1498Szrj 				"and %s overlaps %wu bytes at offset "
141238fd1498Szrj 				"%s")),
141338fd1498Szrj 			call, func, sizrange[0],
141438fd1498Szrj 			offstr[0], offstr[1], ovlsiz[0], offstr[2]);
141538fd1498Szrj 	  else if (ovlsiz[1] >= 0 && ovlsiz[1] < maxobjsize.to_shwi ())
141638fd1498Szrj 	    warning_n (loc, OPT_Wrestrict, sizrange[0],
141738fd1498Szrj 		       "%G%qD accessing %wu byte at offsets %s "
141838fd1498Szrj 		       "and %s overlaps between %wu and %wu bytes "
141938fd1498Szrj 		       "at offset %s",
142038fd1498Szrj 		       "%G%qD accessing %wu bytes at offsets %s "
142138fd1498Szrj 		       "and %s overlaps between %wu and %wu bytes "
142238fd1498Szrj 		       "at offset %s",
142338fd1498Szrj 		       call, func, sizrange[0], offstr[0], offstr[1],
142438fd1498Szrj 		       ovlsiz[0], ovlsiz[1], offstr[2]);
142538fd1498Szrj 	  else
142638fd1498Szrj 	    warning_n (loc, OPT_Wrestrict, sizrange[0],
142738fd1498Szrj 		       "%G%qD accessing %wu byte at offsets %s and "
142838fd1498Szrj 		       "%s overlaps %wu or more bytes at offset %s",
142938fd1498Szrj 		       "%G%qD accessing %wu bytes at offsets %s and "
143038fd1498Szrj 		       "%s overlaps %wu or more bytes at offset %s",
143138fd1498Szrj 		       call, func, sizrange[0],
143238fd1498Szrj 		       offstr[0], offstr[1], ovlsiz[0], offstr[2]);
143338fd1498Szrj 	  return true;
143438fd1498Szrj 	}
143538fd1498Szrj 
143638fd1498Szrj       if (sizrange[1] >= 0 && sizrange[1] < maxobjsize.to_shwi ())
143738fd1498Szrj 	{
143838fd1498Szrj 	  if (ovlsiz[0] == ovlsiz[1])
143938fd1498Szrj 	    warning_n (loc, OPT_Wrestrict, ovlsiz[0],
144038fd1498Szrj 		       "%G%qD accessing between %wu and %wu bytes "
144138fd1498Szrj 		       "at offsets %s and %s overlaps %wu byte at "
144238fd1498Szrj 		       "offset %s",
144338fd1498Szrj 		       "%G%qD accessing between %wu and %wu bytes "
144438fd1498Szrj 		       "at offsets %s and %s overlaps %wu bytes "
144538fd1498Szrj 		       "at offset %s",
144638fd1498Szrj 		       call, func, sizrange[0], sizrange[1],
144738fd1498Szrj 		       offstr[0], offstr[1], ovlsiz[0], offstr[2]);
144838fd1498Szrj 	  else if (ovlsiz[1] >= 0 && ovlsiz[1] < maxobjsize.to_shwi ())
144938fd1498Szrj 	    warning_at (loc, OPT_Wrestrict,
145038fd1498Szrj 			"%G%qD accessing between %wu and %wu bytes at "
145138fd1498Szrj 			"offsets %s and %s overlaps between %wu and %wu "
145238fd1498Szrj 			"bytes at offset %s",
145338fd1498Szrj 			call, func, sizrange[0], sizrange[1],
145438fd1498Szrj 			offstr[0], offstr[1], ovlsiz[0], ovlsiz[1],
145538fd1498Szrj 			offstr[2]);
145638fd1498Szrj 	  else
145738fd1498Szrj 	    warning_at (loc, OPT_Wrestrict,
145838fd1498Szrj 			"%G%qD accessing between %wu and %wu bytes at "
145938fd1498Szrj 			"offsets %s and %s overlaps %wu or more bytes "
146038fd1498Szrj 			"at offset %s",
146138fd1498Szrj 			call, func, sizrange[0], sizrange[1],
146238fd1498Szrj 			offstr[0], offstr[1], ovlsiz[0], offstr[2]);
146338fd1498Szrj 	  return true;
146438fd1498Szrj 	}
146538fd1498Szrj 
146638fd1498Szrj       if (ovlsiz[0] != ovlsiz[1])
146738fd1498Szrj 	ovlsiz[1] = maxobjsize.to_shwi ();
146838fd1498Szrj 
146938fd1498Szrj       if (ovlsiz[0] == ovlsiz[1])
147038fd1498Szrj 	warning_n (loc, OPT_Wrestrict, ovlsiz[0],
147138fd1498Szrj 		   "%G%qD accessing %wu or more bytes at offsets "
147238fd1498Szrj 		   "%s and %s overlaps %wu byte at offset %s",
147338fd1498Szrj 		   "%G%qD accessing %wu or more bytes at offsets "
147438fd1498Szrj 		   "%s and %s overlaps %wu bytes at offset %s",
147538fd1498Szrj 		   call, func, sizrange[0], offstr[0], offstr[1],
147638fd1498Szrj 		   ovlsiz[0], offstr[2]);
147738fd1498Szrj       else if (ovlsiz[1] >= 0 && ovlsiz[1] < maxobjsize.to_shwi ())
147838fd1498Szrj 	warning_at (loc, OPT_Wrestrict,
147938fd1498Szrj 		    "%G%qD accessing %wu or more bytes at offsets %s "
148038fd1498Szrj 		    "and %s overlaps between %wu and %wu bytes "
148138fd1498Szrj 		    "at offset %s",
148238fd1498Szrj 		    call, func, sizrange[0], offstr[0], offstr[1],
148338fd1498Szrj 		    ovlsiz[0], ovlsiz[1], offstr[2]);
148438fd1498Szrj       else
148538fd1498Szrj 	warning_at (loc, OPT_Wrestrict,
148638fd1498Szrj 		    "%G%qD accessing %wu or more bytes at offsets %s "
148738fd1498Szrj 		    "and %s overlaps %wu or more bytes at offset %s",
148838fd1498Szrj 		    call, func, sizrange[0], offstr[0], offstr[1],
148938fd1498Szrj 		    ovlsiz[0], offstr[2]);
149038fd1498Szrj       return true;
149138fd1498Szrj     }
149238fd1498Szrj 
149338fd1498Szrj   /* Use more concise wording when one of the offsets is unbounded
149438fd1498Szrj      to avoid confusing the user with large and mostly meaningless
149538fd1498Szrj      numbers.  */
149638fd1498Szrj   bool open_range;
149738fd1498Szrj   if (DECL_P (dstref.base) && TREE_CODE (TREE_TYPE (dstref.base)) == ARRAY_TYPE)
149838fd1498Szrj     open_range = ((dstref.offrange[0] == 0
149938fd1498Szrj 		   && dstref.offrange[1] == maxobjsize)
150038fd1498Szrj 		  || (srcref.offrange[0] == 0
150138fd1498Szrj 		      && srcref.offrange[1] == maxobjsize));
150238fd1498Szrj   else
150338fd1498Szrj     open_range = ((dstref.offrange[0] == -maxobjsize - 1
150438fd1498Szrj 		   && dstref.offrange[1] == maxobjsize)
150538fd1498Szrj 		  || (srcref.offrange[0] == -maxobjsize - 1
150638fd1498Szrj 		      && srcref.offrange[1] == maxobjsize));
150738fd1498Szrj 
150838fd1498Szrj   if (sizrange[0] == sizrange[1] || sizrange[1] == 1)
150938fd1498Szrj     {
151038fd1498Szrj       if (ovlsiz[1] == 1)
151138fd1498Szrj 	{
151238fd1498Szrj 	  if (open_range)
151338fd1498Szrj 	    warning_n (loc, OPT_Wrestrict, sizrange[1],
151438fd1498Szrj 		       "%G%qD accessing %wu byte may overlap "
151538fd1498Szrj 		       "%wu byte",
151638fd1498Szrj 		       "%G%qD accessing %wu bytes may overlap "
151738fd1498Szrj 		       "%wu byte",
151838fd1498Szrj 		       call, func, sizrange[1], ovlsiz[1]);
151938fd1498Szrj 	  else
152038fd1498Szrj 	    warning_n (loc, OPT_Wrestrict, sizrange[1],
152138fd1498Szrj 		       "%G%qD accessing %wu byte at offsets %s "
152238fd1498Szrj 		       "and %s may overlap %wu byte at offset %s",
152338fd1498Szrj 		       "%G%qD accessing %wu bytes at offsets %s "
152438fd1498Szrj 		       "and %s may overlap %wu byte at offset %s",
152538fd1498Szrj 		       call, func, sizrange[1], offstr[0], offstr[1],
152638fd1498Szrj 		       ovlsiz[1], offstr[2]);
152738fd1498Szrj 	  return true;
152838fd1498Szrj 	}
152938fd1498Szrj 
153038fd1498Szrj       if (open_range)
153138fd1498Szrj 	warning_n (loc, OPT_Wrestrict, sizrange[1],
153238fd1498Szrj 		   "%G%qD accessing %wu byte may overlap "
153338fd1498Szrj 		   "up to %wu bytes",
153438fd1498Szrj 		   "%G%qD accessing %wu bytes may overlap "
153538fd1498Szrj 		   "up to %wu bytes",
153638fd1498Szrj 		   call, func, sizrange[1], ovlsiz[1]);
153738fd1498Szrj       else
153838fd1498Szrj 	warning_n (loc, OPT_Wrestrict, sizrange[1],
153938fd1498Szrj 		   "%G%qD accessing %wu byte at offsets %s and "
154038fd1498Szrj 		   "%s may overlap up to %wu bytes at offset %s",
154138fd1498Szrj 		   "%G%qD accessing %wu bytes at offsets %s and "
154238fd1498Szrj 		   "%s may overlap up to %wu bytes at offset %s",
154338fd1498Szrj 		   call, func, sizrange[1], offstr[0], offstr[1],
154438fd1498Szrj 		   ovlsiz[1], offstr[2]);
154538fd1498Szrj       return true;
154638fd1498Szrj     }
154738fd1498Szrj 
154838fd1498Szrj   if (sizrange[1] >= 0 && sizrange[1] < maxobjsize.to_shwi ())
154938fd1498Szrj     {
155038fd1498Szrj       if (open_range)
155138fd1498Szrj 	warning_n (loc, OPT_Wrestrict, ovlsiz[1],
155238fd1498Szrj 		   "%G%qD accessing between %wu and %wu bytes "
155338fd1498Szrj 		   "may overlap %wu byte",
155438fd1498Szrj 		   "%G%qD accessing between %wu and %wu bytes "
155538fd1498Szrj 		   "may overlap up to %wu bytes",
155638fd1498Szrj 		   call, func, sizrange[0], sizrange[1], ovlsiz[1]);
155738fd1498Szrj       else
155838fd1498Szrj 	warning_n (loc, OPT_Wrestrict, ovlsiz[1],
155938fd1498Szrj 		   "%G%qD accessing between %wu and %wu bytes "
156038fd1498Szrj 		   "at offsets %s and %s may overlap %wu byte "
156138fd1498Szrj 		   "at offset %s",
156238fd1498Szrj 		   "%G%qD accessing between %wu and %wu bytes "
156338fd1498Szrj 		   "at offsets %s and %s may overlap up to %wu "
156438fd1498Szrj 		   "bytes at offset %s",
156538fd1498Szrj 		   call, func, sizrange[0], sizrange[1],
156638fd1498Szrj 		   offstr[0], offstr[1], ovlsiz[1], offstr[2]);
156738fd1498Szrj       return true;
156838fd1498Szrj     }
156938fd1498Szrj 
157038fd1498Szrj   warning_n (loc, OPT_Wrestrict, ovlsiz[1],
157138fd1498Szrj 	     "%G%qD accessing %wu or more bytes at offsets %s "
157238fd1498Szrj 	     "and %s may overlap %wu byte at offset %s",
157338fd1498Szrj 	     "%G%qD accessing %wu or more bytes at offsets %s "
157438fd1498Szrj 	     "and %s may overlap up to %wu bytes at offset %s",
157538fd1498Szrj 	     call, func, sizrange[0], offstr[0], offstr[1],
157638fd1498Szrj 	     ovlsiz[1], offstr[2]);
157738fd1498Szrj 
157838fd1498Szrj   return true;
157938fd1498Szrj }
158038fd1498Szrj 
158138fd1498Szrj /* Validate REF offsets in an EXPRession passed as an argument to a CALL
158238fd1498Szrj    to a built-in function FUNC to make sure they are within the bounds
158338fd1498Szrj    of the referenced object if its size is known, or PTRDIFF_MAX otherwise.
158438fd1498Szrj    Both initial values of the offsets and their final value computed by
158538fd1498Szrj    the function by incrementing the initial value by the size are
158638fd1498Szrj    validated.  Return true if the offsets are not valid and a diagnostic
158738fd1498Szrj    has been issued.  */
158838fd1498Szrj 
158938fd1498Szrj static bool
maybe_diag_offset_bounds(location_t loc,gcall * call,tree func,int strict,tree expr,const builtin_memref & ref)159038fd1498Szrj maybe_diag_offset_bounds (location_t loc, gcall *call, tree func, int strict,
159138fd1498Szrj 			  tree expr, const builtin_memref &ref)
159238fd1498Szrj {
159338fd1498Szrj   if (!warn_array_bounds)
159438fd1498Szrj     return false;
159538fd1498Szrj 
159638fd1498Szrj   offset_int ooboff[] = { ref.offrange[0], ref.offrange[1] };
159738fd1498Szrj   tree oobref = ref.offset_out_of_bounds (strict, ooboff);
159838fd1498Szrj   if (!oobref)
159938fd1498Szrj     return false;
160038fd1498Szrj 
160138fd1498Szrj   if (EXPR_HAS_LOCATION (expr))
160238fd1498Szrj     loc = EXPR_LOCATION (expr);
160338fd1498Szrj 
160438fd1498Szrj   loc = expansion_point_location_if_in_system_header (loc);
160538fd1498Szrj 
160638fd1498Szrj   tree type;
160738fd1498Szrj 
160838fd1498Szrj   char rangestr[2][64];
160938fd1498Szrj   if (ooboff[0] == ooboff[1]
161038fd1498Szrj       || (ooboff[0] != ref.offrange[0]
161138fd1498Szrj 	  && ooboff[0].to_shwi () >= ooboff[1].to_shwi ()))
161238fd1498Szrj     sprintf (rangestr[0], "%lli", (long long) ooboff[0].to_shwi ());
161338fd1498Szrj   else
161438fd1498Szrj     sprintf (rangestr[0], "[%lli, %lli]",
161538fd1498Szrj 	     (long long) ooboff[0].to_shwi (),
161638fd1498Szrj 	     (long long) ooboff[1].to_shwi ());
161738fd1498Szrj 
161838fd1498Szrj   if (oobref == error_mark_node)
161938fd1498Szrj     {
162038fd1498Szrj       if (ref.sizrange[0] == ref.sizrange[1])
162138fd1498Szrj 	sprintf (rangestr[1], "%lli", (long long) ref.sizrange[0].to_shwi ());
162238fd1498Szrj       else
162338fd1498Szrj 	sprintf (rangestr[1], "[%lli, %lli]",
162438fd1498Szrj 		 (long long) ref.sizrange[0].to_shwi (),
162538fd1498Szrj 		 (long long) ref.sizrange[1].to_shwi ());
162638fd1498Szrj 
162738fd1498Szrj       if (DECL_P (ref.base)
162838fd1498Szrj 	  && TREE_CODE (type = TREE_TYPE (ref.base)) == ARRAY_TYPE)
162938fd1498Szrj 	{
163038fd1498Szrj 	  if (warning_at (loc, OPT_Warray_bounds,
163138fd1498Szrj 			  "%G%qD pointer overflow between offset %s "
163238fd1498Szrj 			  "and size %s accessing array %qD with type %qT",
163338fd1498Szrj 			  call, func, rangestr[0], rangestr[1], ref.base, type))
163438fd1498Szrj 	    inform (DECL_SOURCE_LOCATION (ref.base),
163538fd1498Szrj 		    "array %qD declared here", ref.base);
163638fd1498Szrj 	  else
163738fd1498Szrj 	    warning_at (loc, OPT_Warray_bounds,
163838fd1498Szrj 			"%G%qD pointer overflow between offset %s "
163938fd1498Szrj 			"and size %s",
164038fd1498Szrj 			call, func, rangestr[0], rangestr[1]);
164138fd1498Szrj 	}
164238fd1498Szrj       else
164338fd1498Szrj 	warning_at (loc, OPT_Warray_bounds,
164438fd1498Szrj 		    "%G%qD pointer overflow between offset %s "
164538fd1498Szrj 		    "and size %s",
164638fd1498Szrj 		    call, func, rangestr[0], rangestr[1]);
164738fd1498Szrj     }
164838fd1498Szrj   else if (oobref == ref.base)
164938fd1498Szrj     {
165038fd1498Szrj       const offset_int maxobjsize = tree_to_shwi (max_object_size ());
165138fd1498Szrj 
165238fd1498Szrj       /* True when the offset formed by an access to the reference
165338fd1498Szrj 	 is out of bounds, rather than the initial offset wich is
165438fd1498Szrj 	 in bounds.  This implies access past the end.  */
165538fd1498Szrj       bool form = ooboff[0] != ref.offrange[0];
165638fd1498Szrj 
165738fd1498Szrj       if (DECL_P (ref.base))
165838fd1498Szrj 	{
165938fd1498Szrj 	  if ((ref.basesize < maxobjsize
166038fd1498Szrj 	       && warning_at (loc, OPT_Warray_bounds,
166138fd1498Szrj 			      form
166238fd1498Szrj 			      ? G_("%G%qD forming offset %s is out of "
166338fd1498Szrj 				   "the bounds [0, %wu] of object %qD with "
166438fd1498Szrj 				   "type %qT")
166538fd1498Szrj 			      : G_("%G%qD offset %s is out of the bounds "
166638fd1498Szrj 				   "[0, %wu] of object %qD with type %qT"),
166738fd1498Szrj 			      call, func, rangestr[0], ref.basesize.to_uhwi (),
166838fd1498Szrj 			      ref.base, TREE_TYPE (ref.base)))
166938fd1498Szrj 	      || warning_at (loc, OPT_Warray_bounds,
167038fd1498Szrj 			     form
167138fd1498Szrj 			     ? G_("%G%qD forming offset %s is out of "
167238fd1498Szrj 				  "the bounds of object %qD with type %qT")
167338fd1498Szrj 			     : G_("%G%qD offset %s is out of the bounds "
167438fd1498Szrj 				  "of object %qD with type %qT"),
167538fd1498Szrj 			     call, func, rangestr[0],
167638fd1498Szrj 			     ref.base, TREE_TYPE (ref.base)))
167738fd1498Szrj 	    inform (DECL_SOURCE_LOCATION (ref.base),
167838fd1498Szrj 		    "%qD declared here", ref.base);
167938fd1498Szrj 	}
168038fd1498Szrj       else if (ref.basesize < maxobjsize)
168138fd1498Szrj 	warning_at (loc, OPT_Warray_bounds,
168238fd1498Szrj 		    form
168338fd1498Szrj 		    ? G_("%G%qD forming offset %s is out of the bounds "
168438fd1498Szrj 			 "[0, %wu]")
168538fd1498Szrj 		    : G_("%G%qD offset %s is out of the bounds [0, %wu]"),
168638fd1498Szrj 		    call, func, rangestr[0], ref.basesize.to_uhwi ());
168738fd1498Szrj       else
168838fd1498Szrj 	warning_at (loc, OPT_Warray_bounds,
168938fd1498Szrj 		    form
169038fd1498Szrj 		    ? G_("%G%qD forming offset %s is out of bounds")
169138fd1498Szrj 		    : G_("%G%qD offset %s is out of bounds"),
169238fd1498Szrj 		    call, func, rangestr[0]);
169338fd1498Szrj     }
169438fd1498Szrj   else if (TREE_CODE (ref.ref) == MEM_REF)
169538fd1498Szrj     {
169638fd1498Szrj       tree type = TREE_TYPE (TREE_OPERAND (ref.ref, 0));
169738fd1498Szrj       if (POINTER_TYPE_P (type))
169838fd1498Szrj 	type = TREE_TYPE (type);
169938fd1498Szrj       type = TYPE_MAIN_VARIANT (type);
170038fd1498Szrj 
170138fd1498Szrj       warning_at (loc, OPT_Warray_bounds,
170238fd1498Szrj 		  "%G%qD offset %s from the object at %qE is out "
170338fd1498Szrj 		  "of the bounds of %qT",
170438fd1498Szrj 		  call, func, rangestr[0], ref.base, type);
170538fd1498Szrj     }
170638fd1498Szrj   else
170738fd1498Szrj     {
170838fd1498Szrj       type = TYPE_MAIN_VARIANT (TREE_TYPE (ref.ref));
170938fd1498Szrj 
171038fd1498Szrj       warning_at (loc, OPT_Warray_bounds,
171138fd1498Szrj 		"%G%qD offset %s from the object at %qE is out "
171238fd1498Szrj 		"of the bounds of referenced subobject %qD with type %qT "
171338fd1498Szrj 		"at offset %wu",
171438fd1498Szrj 		call, func, rangestr[0], ref.base, TREE_OPERAND (ref.ref, 1),
171538fd1498Szrj 		type, ref.refoff.to_uhwi ());
171638fd1498Szrj     }
171738fd1498Szrj 
171838fd1498Szrj   return true;
171938fd1498Szrj }
172038fd1498Szrj 
172138fd1498Szrj /* Check a CALL statement for restrict-violations and issue warnings
172238fd1498Szrj    if/when appropriate.  */
172338fd1498Szrj 
172438fd1498Szrj void
check_call(gcall * call)172538fd1498Szrj wrestrict_dom_walker::check_call (gcall *call)
172638fd1498Szrj {
172738fd1498Szrj   /* Avoid checking the call if it has already been diagnosed for
172838fd1498Szrj      some reason.  */
172938fd1498Szrj   if (gimple_no_warning_p (call))
173038fd1498Szrj     return;
173138fd1498Szrj 
173238fd1498Szrj   tree func = gimple_call_fndecl (call);
173338fd1498Szrj   if (!func || DECL_BUILT_IN_CLASS (func) != BUILT_IN_NORMAL)
173438fd1498Szrj     return;
173538fd1498Szrj 
173638fd1498Szrj   bool with_bounds = gimple_call_with_bounds_p (call);
173738fd1498Szrj 
173838fd1498Szrj   /* Argument number to extract from the call (depends on the built-in
173938fd1498Szrj      and its kind).  */
174038fd1498Szrj   unsigned dst_idx = -1;
174138fd1498Szrj   unsigned src_idx = -1;
174238fd1498Szrj   unsigned bnd_idx = -1;
174338fd1498Szrj 
174438fd1498Szrj   /* Is this CALL to a string function (as opposed to one to a raw
174538fd1498Szrj      memory function).  */
174638fd1498Szrj   bool strfun = true;
174738fd1498Szrj 
174838fd1498Szrj   switch (DECL_FUNCTION_CODE (func))
174938fd1498Szrj     {
175038fd1498Szrj     case BUILT_IN_MEMCPY:
175138fd1498Szrj     case BUILT_IN_MEMCPY_CHK:
175238fd1498Szrj     case BUILT_IN_MEMCPY_CHKP:
175338fd1498Szrj     case BUILT_IN_MEMCPY_CHK_CHKP:
175438fd1498Szrj     case BUILT_IN_MEMPCPY:
175538fd1498Szrj     case BUILT_IN_MEMPCPY_CHK:
175638fd1498Szrj     case BUILT_IN_MEMPCPY_CHKP:
175738fd1498Szrj     case BUILT_IN_MEMPCPY_CHK_CHKP:
175838fd1498Szrj     case BUILT_IN_MEMMOVE:
175938fd1498Szrj     case BUILT_IN_MEMMOVE_CHK:
176038fd1498Szrj     case BUILT_IN_MEMMOVE_CHKP:
176138fd1498Szrj     case BUILT_IN_MEMMOVE_CHK_CHKP:
176238fd1498Szrj       strfun = false;
176338fd1498Szrj       /* Fall through.  */
176438fd1498Szrj 
176538fd1498Szrj     case BUILT_IN_STPNCPY:
176638fd1498Szrj     case BUILT_IN_STPNCPY_CHK:
176738fd1498Szrj     case BUILT_IN_STRNCAT:
176838fd1498Szrj     case BUILT_IN_STRNCAT_CHK:
176938fd1498Szrj     case BUILT_IN_STRNCPY:
177038fd1498Szrj     case BUILT_IN_STRNCPY_CHK:
177138fd1498Szrj       dst_idx = 0;
177238fd1498Szrj       src_idx = 1 + with_bounds;
177338fd1498Szrj       bnd_idx = 2 + 2 * with_bounds;
177438fd1498Szrj       break;
177538fd1498Szrj 
177638fd1498Szrj     case BUILT_IN_STPCPY:
177738fd1498Szrj     case BUILT_IN_STPCPY_CHK:
177838fd1498Szrj     case BUILT_IN_STPCPY_CHKP:
177938fd1498Szrj     case BUILT_IN_STPCPY_CHK_CHKP:
178038fd1498Szrj     case BUILT_IN_STRCPY:
178138fd1498Szrj     case BUILT_IN_STRCPY_CHK:
178238fd1498Szrj     case BUILT_IN_STRCPY_CHKP:
178338fd1498Szrj     case BUILT_IN_STRCPY_CHK_CHKP:
178438fd1498Szrj     case BUILT_IN_STRCAT:
178538fd1498Szrj     case BUILT_IN_STRCAT_CHK:
178638fd1498Szrj     case BUILT_IN_STRCAT_CHKP:
178738fd1498Szrj     case BUILT_IN_STRCAT_CHK_CHKP:
178838fd1498Szrj       dst_idx = 0;
178938fd1498Szrj       src_idx = 1 + with_bounds;
179038fd1498Szrj       break;
179138fd1498Szrj 
179238fd1498Szrj     default:
179338fd1498Szrj       /* Handle other string functions here whose access may need
179438fd1498Szrj 	 to be validated for in-bounds offsets and non-overlapping
179538fd1498Szrj 	 copies.  (Not all _chkp functions have BUILT_IN_XXX_CHKP
179638fd1498Szrj 	 macros so they need to be handled here.)  */
179738fd1498Szrj       return;
179838fd1498Szrj     }
179938fd1498Szrj 
180038fd1498Szrj   unsigned nargs = gimple_call_num_args (call);
180138fd1498Szrj 
180238fd1498Szrj   tree dst = dst_idx < nargs ? gimple_call_arg (call, dst_idx) : NULL_TREE;
180338fd1498Szrj   tree src = src_idx < nargs ? gimple_call_arg (call, src_idx) : NULL_TREE;
180438fd1498Szrj   tree dstwr = bnd_idx < nargs ? gimple_call_arg (call, bnd_idx) : NULL_TREE;
180538fd1498Szrj 
180638fd1498Szrj   /* For string functions with an unspecified or unknown bound,
180738fd1498Szrj      assume the size of the access is one.  */
180838fd1498Szrj   if (!dstwr && strfun)
180938fd1498Szrj     dstwr = size_one_node;
181038fd1498Szrj 
181138fd1498Szrj   /* DST and SRC can be null for a call with an insufficient number
181238fd1498Szrj      of arguments to a built-in function declared without a protype.  */
181338fd1498Szrj   if (!dst || !src)
181438fd1498Szrj     return;
181538fd1498Szrj 
181638fd1498Szrj   /* DST, SRC, or DSTWR can also have the wrong type in a call to
181738fd1498Szrj      a function declared without a prototype.  Avoid checking such
181838fd1498Szrj      invalid calls.  */
181938fd1498Szrj   if (TREE_CODE (TREE_TYPE (dst)) != POINTER_TYPE
182038fd1498Szrj       || TREE_CODE (TREE_TYPE (src)) != POINTER_TYPE
182138fd1498Szrj       || (dstwr && !INTEGRAL_TYPE_P (TREE_TYPE (dstwr))))
182238fd1498Szrj     return;
182338fd1498Szrj 
182438fd1498Szrj   if (check_bounds_or_overlap (call, dst, src, dstwr, NULL_TREE))
182538fd1498Szrj     return;
182638fd1498Szrj 
182738fd1498Szrj   /* Avoid diagnosing the call again.  */
182838fd1498Szrj   gimple_set_no_warning (call, true);
182938fd1498Szrj }
183038fd1498Szrj 
183138fd1498Szrj } /* anonymous namespace */
183238fd1498Szrj 
183338fd1498Szrj /* Attempt to detect and diagnose invalid offset bounds and (except for
183438fd1498Szrj    memmove) overlapping copy in a call expression EXPR from SRC to DST
183538fd1498Szrj    and DSTSIZE and SRCSIZE bytes, respectively.  Both DSTSIZE and
183638fd1498Szrj    SRCSIZE may be NULL.  Return false when one or the other has been
183738fd1498Szrj    detected and diagnosed, true otherwise.  */
183838fd1498Szrj 
183938fd1498Szrj bool
check_bounds_or_overlap(gcall * call,tree dst,tree src,tree dstsize,tree srcsize,bool bounds_only)184038fd1498Szrj check_bounds_or_overlap (gcall *call, tree dst, tree src, tree dstsize,
184138fd1498Szrj 			 tree srcsize, bool bounds_only /* = false */)
184238fd1498Szrj {
184338fd1498Szrj   location_t loc = gimple_location (call);
184438fd1498Szrj 
184538fd1498Szrj   if (tree block = gimple_block (call))
184638fd1498Szrj     if (location_t *pbloc = block_nonartificial_location (block))
184738fd1498Szrj       loc = *pbloc;
184838fd1498Szrj 
184938fd1498Szrj   loc = expansion_point_location_if_in_system_header (loc);
185038fd1498Szrj 
185138fd1498Szrj   tree func = gimple_call_fndecl (call);
185238fd1498Szrj 
185338fd1498Szrj   builtin_memref dstref (dst, dstsize);
185438fd1498Szrj   builtin_memref srcref (src, srcsize);
185538fd1498Szrj 
185638fd1498Szrj   builtin_access acs (call, dstref, srcref);
185738fd1498Szrj 
185838fd1498Szrj   /* Set STRICT to the value of the -Warray-bounds=N argument for
185938fd1498Szrj      string functions or when N > 1.  */
186038fd1498Szrj   int strict = (acs.strict () || warn_array_bounds > 1 ? warn_array_bounds : 0);
186138fd1498Szrj 
186238fd1498Szrj   /* Validate offsets first to make sure they are within the bounds
186338fd1498Szrj      of the destination object if its size is known, or PTRDIFF_MAX
186438fd1498Szrj      otherwise.  */
186538fd1498Szrj   if (maybe_diag_offset_bounds (loc, call, func, strict, dst, dstref)
186638fd1498Szrj       || maybe_diag_offset_bounds (loc, call, func, strict, src, srcref))
186738fd1498Szrj     {
186838fd1498Szrj       gimple_set_no_warning (call, true);
186938fd1498Szrj       return false;
187038fd1498Szrj     }
187138fd1498Szrj 
187238fd1498Szrj   bool check_overlap
187338fd1498Szrj     = (warn_restrict
187438fd1498Szrj        && (bounds_only
187538fd1498Szrj 	   || (DECL_FUNCTION_CODE (func) != BUILT_IN_MEMMOVE
187638fd1498Szrj 	       && DECL_FUNCTION_CODE (func) != BUILT_IN_MEMMOVE_CHK)));
187738fd1498Szrj 
187838fd1498Szrj   if (!check_overlap)
187938fd1498Szrj     return true;
188038fd1498Szrj 
188138fd1498Szrj   if (operand_equal_p (dst, src, 0))
188238fd1498Szrj     {
188338fd1498Szrj       /* Issue -Wrestrict unless the pointers are null (those do
188438fd1498Szrj 	 not point to objects and so do not indicate an overlap;
188538fd1498Szrj 	 such calls could be the result of sanitization and jump
188638fd1498Szrj 	 threading).  */
188738fd1498Szrj       if (!integer_zerop (dst) && !gimple_no_warning_p (call))
188838fd1498Szrj 	{
188938fd1498Szrj 	  warning_at (loc, OPT_Wrestrict,
189038fd1498Szrj 		      "%G%qD source argument is the same as destination",
189138fd1498Szrj 		      call, func);
189238fd1498Szrj 	  gimple_set_no_warning (call, true);
189338fd1498Szrj 	  return false;
189438fd1498Szrj 	}
189538fd1498Szrj 
189638fd1498Szrj       return true;
189738fd1498Szrj     }
189838fd1498Szrj 
189938fd1498Szrj   /* Return false when overlap has been detected.  */
190038fd1498Szrj   if (maybe_diag_overlap (loc, call, acs))
190138fd1498Szrj     {
190238fd1498Szrj       gimple_set_no_warning (call, true);
190338fd1498Szrj       return false;
190438fd1498Szrj     }
190538fd1498Szrj 
190638fd1498Szrj   return true;
190738fd1498Szrj }
190838fd1498Szrj 
190938fd1498Szrj gimple_opt_pass *
make_pass_warn_restrict(gcc::context * ctxt)191038fd1498Szrj make_pass_warn_restrict (gcc::context *ctxt)
191138fd1498Szrj {
191238fd1498Szrj   return new pass_wrestrict (ctxt);
191338fd1498Szrj }
1914