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