PR middle-end/91582 - missing heap overflow detection for strcpy
authorMartin Sebor <msebor@redhat.com>
Thu, 5 Dec 2019 01:28:11 +0000 (01:28 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Thu, 5 Dec 2019 01:28:11 +0000 (18:28 -0700)
gcc/ChangeLog:

PR middle-end/91582
* builtins.c (gimple_call_alloc_size): New function.
(compute_objsize): Add argument.  Call gimple_call_alloc_size.
Handle variable offsets and indices.
* builtins.h (gimple_call_alloc_size): Declare.
(compute_objsize): Add argument.
* gcc/gimple-ssa-warn-restrict.c: Remove assertions.
* tree-ssa-strlen.c (handle_store): Handle calls to allocated objects.

gcc/testsuite/ChangeLog:

PR middle-end/91582
* c-c++-common/Wstringop-truncation.c: Remove xfails.
* g++.dg/warn/Wstringop-overflow-4.C: New test.
* g++.dg/ext/attr-alloc_size.C: Suppress -Warray-bounds.
* gcc.dg/Warray-bounds-56.c: New test.
* gcc.dg/Wstringop-overflow-22.c: New test.
* gcc.dg/attr-alloc_size.c: Suppress -Warray-bounds.
* gcc.dg/attr-copy-2.c: Same.
* gcc.dg/builtin-stringop-chk-5.c: Remove xfails.
* gcc.dg/builtin-stringop-chk-8.c: Same.  Correct the text of expected
warnings.
* gcc.target/i386/pr82002-2a.c: Prune expected warning.
* gcc.target/i386/pr82002-2b.c: Same.

From-SVN: r278983

17 files changed:
gcc/ChangeLog
gcc/builtins.c
gcc/builtins.h
gcc/gimple-ssa-warn-restrict.c
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/Wstringop-truncation.c
gcc/testsuite/g++.dg/ext/attr-alloc_size.C
gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/Warray-bounds-56.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wstringop-overflow-25.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/attr-alloc_size.c
gcc/testsuite/gcc.dg/attr-copy-2.c
gcc/testsuite/gcc.dg/builtin-stringop-chk-5.c
gcc/testsuite/gcc.dg/builtin-stringop-chk-8.c
gcc/testsuite/gcc.target/i386/pr82002-2a.c
gcc/testsuite/gcc.target/i386/pr82002-2b.c
gcc/tree-ssa-strlen.c

index 096c75ea80ba022b52826666f53ed84284c0ded8..7f44667ab218b2f509b80aad3d14515bb65b94e8 100644 (file)
@@ -1,3 +1,14 @@
+2019-12-03  Martin Sebor  <msebor@redhat.com>
+
+       PR middle-end/91582
+       * builtins.c (gimple_call_alloc_size): New function.
+       (compute_objsize): Add argument.  Call gimple_call_alloc_size.
+       Handle variable offsets and indices.
+       * builtins.h (gimple_call_alloc_size): Declare.
+       (compute_objsize): Add argument.
+       * gcc/gimple-ssa-warn-restrict.c: Remove assertions.
+       * tree-ssa-strlen.c (handle_store): Handle calls to allocated objects.
+
 2019-12-04  Julian Brown  <julian@codesourcery.com>
 
        * config/gcn/gcn.h (FIXED_REGISTERS): Make s6/s7 fixed registers.
index 36319a97b52271849d8fb7f6e34deb501575e237..53de17c105f996926add6fb4da549a87fdcd6145 100644 (file)
@@ -3696,6 +3696,97 @@ check_access (tree exp, tree, tree, tree dstwrite,
   return true;
 }
 
+/* If STMT is a call to an allocation function, returns the size
+   of the object allocated by the call.  */
+
+tree
+gimple_call_alloc_size (gimple *stmt)
+{
+  if (!stmt)
+    return NULL_TREE;
+
+  tree allocfntype;
+  if (tree fndecl = gimple_call_fndecl (stmt))
+    allocfntype = TREE_TYPE (fndecl);
+  else
+    allocfntype = gimple_call_fntype (stmt);
+
+  if (!allocfntype)
+    return NULL_TREE;
+
+  unsigned argidx1 = UINT_MAX, argidx2 = UINT_MAX;
+  tree at = lookup_attribute ("alloc_size", TYPE_ATTRIBUTES (allocfntype));
+  if (!at)
+    {
+      if (!gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA_WITH_ALIGN))
+       return NULL_TREE;
+
+      argidx1 = 0;
+    }
+
+  unsigned nargs = gimple_call_num_args (stmt);
+
+  if (argidx1 == UINT_MAX)
+    {
+      tree atval = TREE_VALUE (at);
+      if (!atval)
+       return NULL_TREE;
+
+      argidx1 = TREE_INT_CST_LOW (TREE_VALUE (atval)) - 1;
+      if (nargs <= argidx1)
+       return NULL_TREE;
+
+      atval = TREE_CHAIN (atval);
+      if (atval)
+       {
+         argidx2 = TREE_INT_CST_LOW (TREE_VALUE (atval)) - 1;
+         if (nargs <= argidx2)
+           return NULL_TREE;
+       }
+    }
+
+  tree size = gimple_call_arg (stmt, argidx1);
+
+  wide_int rng1[2];
+  if (TREE_CODE (size) == INTEGER_CST)
+    rng1[0] = rng1[1] = wi::to_wide (size);
+  else if (TREE_CODE (size) != SSA_NAME
+          || get_range_info (size, rng1, rng1 + 1) != VR_RANGE)
+    return NULL_TREE;
+
+  if (argidx2 > nargs && TREE_CODE (size) == INTEGER_CST)
+    return size;
+
+  /* To handle ranges do the math in wide_int and return the product
+     of the upper bounds as a constant.  Ignore anti-ranges.  */
+  tree n = argidx2 < nargs ? gimple_call_arg (stmt, argidx2) : integer_one_node;
+  wide_int rng2[2];
+  if (TREE_CODE (n) == INTEGER_CST)
+    rng2[0] = rng2[1] = wi::to_wide (n);
+  else if (TREE_CODE (n) != SSA_NAME
+          || get_range_info (n, rng2, rng2 + 1) != VR_RANGE)
+    return NULL_TREE;
+
+  /* Extend to the maximum precsion to avoid overflow.  */
+  const int prec = ADDR_MAX_PRECISION;
+  rng1[0] = wide_int::from (rng1[0], prec, UNSIGNED);
+  rng1[1] = wide_int::from (rng1[1], prec, UNSIGNED);
+  rng2[0] = wide_int::from (rng2[0], prec, UNSIGNED);
+  rng2[1] = wide_int::from (rng2[1], prec, UNSIGNED);
+
+  /* Return the lesser of SIZE_MAX and the product of the upper bounds.  */
+  rng1[0] = rng1[0] * rng2[0];
+  rng1[1] = rng1[1] * rng2[1];
+  tree size_max = TYPE_MAX_VALUE (sizetype);
+  if (wi::gtu_p (rng1[1], wi::to_wide (size_max, prec)))
+    {
+      rng1[1] = wi::to_wide (size_max);
+      return size_max;
+    }
+
+  return wide_int_to_tree (sizetype, rng1[1]);
+}
+
 /* Helper to compute the size of the object referenced by the DEST
    expression which must have pointer type, using Object Size type
    OSTYPE (only the least significant 2 bits are used).  Return
@@ -3704,16 +3795,22 @@ check_access (tree exp, tree, tree, tree dstwrite,
    a non-constant offset in some range the returned value represents
    the largest size given the smallest non-negative offset in the
    range.  If nonnull, set *PDECL to the decl of the referenced
-   subobject if it can be determined, or to null otherwise.
+   subobject if it can be determined, or to null otherwise.  Likewise,
+   when POFF is nonnull *POFF is set to the offset into *PDECL.
    The function is intended for diagnostics and should not be used
    to influence code generation or optimization.  */
 
 tree
-compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */)
+compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */,
+                tree *poff /* = NULL */)
 {
-  tree dummy = NULL_TREE;
+  tree dummy_decl = NULL_TREE;
   if (!pdecl)
-    pdecl = &dummy;
+    pdecl = &dummy_decl;
+
+  tree dummy_off = size_zero_node;
+  if (!poff)
+    poff = &dummy_off;
 
   unsigned HOST_WIDE_INT size;
 
@@ -3726,6 +3823,13 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */)
   if (TREE_CODE (dest) == SSA_NAME)
     {
       gimple *stmt = SSA_NAME_DEF_STMT (dest);
+      if (is_gimple_call (stmt))
+       {
+         /* If STMT is a call to an allocation function get the size
+            from its argument(s).  */
+         return gimple_call_alloc_size (stmt);
+       }
+
       if (!is_gimple_assign (stmt))
        return NULL_TREE;
 
@@ -3741,7 +3845,7 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */)
          tree off = gimple_assign_rhs2 (stmt);
          if (TREE_CODE (off) == INTEGER_CST)
            {
-             if (tree size = compute_objsize (dest, ostype, pdecl))
+             if (tree size = compute_objsize (dest, ostype, pdecl, poff))
                {
                  wide_int wioff = wi::to_wide (off);
                  wide_int wisiz = wi::to_wide (size);
@@ -3752,10 +3856,16 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */)
                  if (wi::sign_mask (wioff))
                    ;
                  else if (wi::ltu_p (wioff, wisiz))
-                   return wide_int_to_tree (TREE_TYPE (size),
-                                            wi::sub (wisiz, wioff));
+                   {
+                     *poff = size_binop (PLUS_EXPR, *poff, off);
+                     return wide_int_to_tree (TREE_TYPE (size),
+                                              wi::sub (wisiz, wioff));
+                   }
                  else
-                   return size_zero_node;
+                   {
+                     *poff = size_binop (PLUS_EXPR, *poff, off);
+                     return size_zero_node;
+                   }
                }
            }
          else if (TREE_CODE (off) == SSA_NAME
@@ -3777,10 +3887,18 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */)
                          || wi::sign_mask (max))
                        ;
                      else if (wi::ltu_p (min, wisiz))
-                       return wide_int_to_tree (TREE_TYPE (size),
-                                                wi::sub (wisiz, min));
+                       {
+                         *poff = size_binop (PLUS_EXPR, *poff,
+                                             wide_int_to_tree (sizetype, min));
+                         return wide_int_to_tree (TREE_TYPE (size),
+                                                  wi::sub (wisiz, min));
+                       }
                      else
-                       return size_zero_node;
+                       {
+                         *poff = size_binop (PLUS_EXPR, *poff,
+                                             wide_int_to_tree (sizetype, min));
+                         return size_zero_node;
+                       }
                    }
                }
            }
@@ -3799,19 +3917,24 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */)
     {
       tree ref = TREE_OPERAND (dest, 0);
       tree off = TREE_OPERAND (dest, 1);
-      if (tree size = compute_objsize (ref, ostype, pdecl))
+      if (tree size = compute_objsize (ref, ostype, pdecl, poff))
        {
          /* If the declaration of the destination object is known
             to have zero size, return zero.  */
-         if (integer_zerop (size))
+         if (integer_zerop (size)
+             && *pdecl && DECL_P (*pdecl)
+             && *poff && integer_zerop (*poff))
            return integer_zero_node;
 
-         if (TREE_CODE (off) != INTEGER_CST
-             || TREE_CODE (size) != INTEGER_CST)
-           return NULL_TREE;
+         /* A valid offset into a declared object cannot be negative.  */
+         if (tree_int_cst_sgn (*poff) < 0)
+           return size_zero_node;
 
+         /* Adjust SIZE either up or down by the sum of *POFF and OFF
+            above.  */
          if (TREE_CODE (dest) == ARRAY_REF)
            {
+             /* Convert the array index into a byte offset.  */
              tree eltype = TREE_TYPE (dest);
              tree tpsize = TYPE_SIZE_UNIT (eltype);
              if (tpsize && TREE_CODE (tpsize) == INTEGER_CST)
@@ -3820,9 +3943,74 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */)
                return NULL_TREE;
            }
 
-         if (tree_int_cst_lt (off, size))
-           return fold_build2 (MINUS_EXPR, size_type_node, size, off);
-         return integer_zero_node;
+         wide_int offrng[2];
+         if (TREE_CODE (off) == INTEGER_CST)
+           offrng[0] = offrng[1] = wi::to_wide (off);
+         else if (TREE_CODE (off) == SSA_NAME)
+           {
+             wide_int min, max;
+             enum value_range_kind rng
+               = get_range_info (off, offrng, offrng + 1);
+             if (rng != VR_RANGE)
+               return NULL_TREE;
+           }
+         else
+           return NULL_TREE;
+
+         /* Convert to the same precision to keep wide_int from "helpfuly"
+            crashing whenever it sees other argumments.  */
+         offrng[0] = wide_int::from (offrng[0], ADDR_MAX_BITSIZE, SIGNED);
+         offrng[1] = wide_int::from (offrng[1], ADDR_MAX_BITSIZE, SIGNED);
+
+         tree dstoff = *poff;
+         if (integer_zerop (*poff))
+           *poff = off;
+         else if (!integer_zerop (off))
+           {
+             *poff = fold_convert (ptrdiff_type_node, *poff);
+             off = fold_convert (ptrdiff_type_node, off);
+             *poff = size_binop (PLUS_EXPR, *poff, off);
+           }
+
+         if (wi::sign_mask (offrng[0]) >= 0)
+           {
+             if (TREE_CODE (size) != INTEGER_CST)
+               return NULL_TREE;
+
+             /* Return the difference between the size and the offset
+                or zero if the offset is greater.  */
+             wide_int wisize = wi::to_wide (size, ADDR_MAX_BITSIZE);
+             if (wi::ltu_p (wisize, offrng[0]))
+               return size_zero_node;
+
+             return wide_int_to_tree (sizetype, wisize - offrng[0]);
+           }
+
+         wide_int dstoffrng[2];
+         if (TREE_CODE (dstoff) == INTEGER_CST)
+           dstoffrng[0] = dstoffrng[1] = wi::to_wide (dstoff);
+         else if (TREE_CODE (dstoff) == SSA_NAME)
+           {
+             enum value_range_kind rng
+               = get_range_info (dstoff, dstoffrng, dstoffrng + 1);
+             if (rng != VR_RANGE)
+               return NULL_TREE;
+           }
+         else
+           return NULL_TREE;
+
+         dstoffrng[0] = wide_int::from (dstoffrng[0], ADDR_MAX_BITSIZE, SIGNED);
+         dstoffrng[1] = wide_int::from (dstoffrng[1], ADDR_MAX_BITSIZE, SIGNED);
+
+         wide_int declsize = wi::to_wide (size);
+         if (wi::sign_mask (dstoffrng[0]) > 0)
+           declsize += dstoffrng[0];
+
+         offrng[1] += dstoffrng[1];
+         if (wi::sign_mask (offrng[1]) < 0)
+           return size_zero_node;
+
+         return wide_int_to_tree (sizetype, declsize);
        }
 
       return NULL_TREE;
@@ -3850,9 +4038,11 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */)
     type = TREE_TYPE (type);
 
   type = TYPE_MAIN_VARIANT (type);
+  if (TREE_CODE (dest) == ADDR_EXPR)
+    dest = TREE_OPERAND (dest, 0);
 
   if (TREE_CODE (type) == ARRAY_TYPE
-      && !array_at_struct_end_p (ref))
+      && !array_at_struct_end_p (dest))
     {
       if (tree size = TYPE_SIZE_UNIT (type))
        return TREE_CODE (size) == INTEGER_CST ? size : NULL_TREE;
index aa83a46a684903ebaee19548a0eb5d6570578880..0fcccc12a3947a1aaf05e7e01fd040092f2bd354 100644 (file)
@@ -133,7 +133,8 @@ extern tree fold_call_stmt (gcall *, bool);
 extern void set_builtin_user_assembler_name (tree decl, const char *asmspec);
 extern bool is_simple_builtin (tree);
 extern bool is_inexpensive_builtin (tree);
-extern tree compute_objsize (tree, int, tree * = NULL);
+extern tree gimple_call_alloc_size (gimple *);
+extern tree compute_objsize (tree, int, tree * = NULL, tree * = NULL);
 
 extern bool readonly_data_expr (tree exp);
 extern bool init_target_chars (void);
index 2cf84b7aac244ffe8e8039fdef7ca4d7eaaf0892..9b5d1d795991651ea4080454f4a49b38d17b99d6 100644 (file)
@@ -966,7 +966,6 @@ builtin_access::generic_overlap ()
   const offset_int maxobjsize = acs.dstref->maxobjsize;
 
   offset_int maxsize = dstref->basesize < 0 ? maxobjsize : dstref->basesize;
-  gcc_assert (maxsize <= maxobjsize);
 
   /* Adjust the larger bounds of the offsets (which may be the first
      element if the lower bound is larger than the upper bound) to
@@ -1193,7 +1192,6 @@ builtin_access::strcat_overlap ()
   acs.dstsiz[1] = 1;
 
   offset_int maxsize = dstref->basesize < 0 ? maxobjsize : dstref->basesize;
-  gcc_assert (maxsize <= maxobjsize);
 
   /* For references to the same base object, determine if there's a pair
      of valid offsets into the two references such that access between
index 48a6d4501ad260b330f647ef111b05c8678c6900..477a3b23a8f9e91b4f956ea78b4d482b504000dd 100644 (file)
@@ -1,3 +1,18 @@
+2019-12-03  Martin Sebor  <msebor@redhat.com>
+
+       PR middle-end/91582
+       * c-c++-common/Wstringop-truncation.c: Remove xfails.
+       * g++.dg/warn/Wstringop-overflow-4.C: New test.
+       * gcc/testsuite/g++.dg/ext/attr-alloc_size.C: Suppress -Warray-bounds.
+       * gcc.dg/Wstringop-overflow-25.c: New test.
+       * gcc/testsuite/gcc.dg/attr-alloc_size.c: Suppress -Warray-bounds.
+       * gcc/testsuite/gcc.dg/attr-copy-2.c: Same.
+       * gcc.dg/builtin-stringop-chk-5.c: Remove xfails.
+       * gcc.dg/builtin-stringop-chk-8.c: Same.  Correct the text of expected
+       warnings.
+       * gcc.target/i386/pr82002-2a.c: Prune expected warning.
+       * gcc.target/i386/pr82002-2b.c: Same.
+
 2019-12-04  Joseph Myers  <joseph@codesourcery.com>
 
        PR c/36941
index b85711d6b3f399a476a7ae0a9cce9c03b90fd1e2..592a9494ca4c392b1ca9729100b1aca2fc73b3c5 100644 (file)
@@ -425,7 +425,7 @@ void test_strncpy_alloc (const char* s)
   size_t n = 7;
   char *d = (char *)__builtin_malloc (n);
 
-  CPY (d, s, n);                    /* { dg-warning "specified bound 7 equals destination size" "bug 79016" { xfail *-*-* } } */
+  CPY (d, s, n);                    /* { dg-warning "specified bound 7 equals destination size" } */
 
   Dest *pd = (Dest *)__builtin_malloc (sizeof *pd * n);
   CPY (pd->a5, s, 5);               /* { dg-warning "specified bound 5 equals destination size" } */
index 9a421109bdb7cb328e2aa4ce48766e667356314b..9194417aee6b73d580229c7e1f0f47f58f4c19b3 100644 (file)
@@ -1,6 +1,6 @@
 /* PR c++/87541 - ICE using a constant decl as an attribute alloc_size argument
    { dg-do compile }
-   { dg-options "-O2 -Wall" } */
+   { dg-options "-O2 -Wall -Wno-array-bounds" } */
 
 #define ALLOC_SIZE(N)   __attribute__ ((alloc_size (N)))
 
diff --git a/gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C b/gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C
new file mode 100644 (file)
index 0000000..b6fe028
--- /dev/null
@@ -0,0 +1,157 @@
+/* PR middle-end/91582 - missing heap overflow detection for strcpy
+   { dg-do compile }
+   { dg-options "-O2 -Wall -Wno-array-bounds -ftrack-macro-expansion=0" } */
+
+#include "../../gcc.dg/range.h"
+
+#define INT_MAX     __INT_MAX__
+#define INT_MIN     (-INT_MAX - 1)
+
+extern "C" char* strcpy (char*, const char*);
+
+void sink (void*);
+
+#define S36 "0123456789abcdefghijklmnopqrstuvwxyz"
+#define S(N) (S36 + sizeof S36 - N - 1)
+
+#define T(src, alloc) do {                     \
+    const char *s = src;                       \
+    char *d = (char*)alloc;                    \
+    strcpy (d, s);                             \
+    sink (d);                                  \
+  } while (0)
+
+
+void test_strcpy_new_char (size_t n)
+{
+  size_t r_0_1 = UR (0, 1);
+  size_t r_1_2 = UR (1, 2);
+  size_t r_2_3 = UR (2, 3);
+
+  T (S (0), new char[r_0_1]);
+  T (S (1), new char[r_0_1]);       // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), new char[r_1_2]);
+  T (S (1), new char[r_1_2]);
+  T (S (2), new char[r_1_2]);       // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), new char[r_2_3]);
+  T (S (2), new char[r_2_3]);
+  T (S (3), new char[r_2_3]);       // { dg-warning "\\\[-Wstringop-overflow" }
+  T (S (9), new char[r_2_3]);       // { dg-warning "\\\[-Wstringop-overflow" }
+
+  size_t r_2_smax = UR (2, SIZE_MAX);
+  T (S (0), new char[r_2_smax]);
+  T (S (1), new char[r_2_smax]);
+  T (S (2), new char[r_2_smax]);
+  T (S (3), new char[r_2_smax * 2]);
+  T (S (4), new char[r_2_smax * 2 + 1]);
+
+  T (S (1), new char[n]);
+  T (S (2), new char[n + 1]);
+  T (S (9), new char[n * 2 + 1]);
+
+  int r_imin_imax = SR (INT_MIN, INT_MAX);
+  T (S (1), new char[r_imin_imax]);
+  T (S (2), new char[r_imin_imax + 1]);
+  T (S (9), new char[r_imin_imax * 2 + 1]);
+
+  int r_0_imax = SR (0, INT_MAX);
+  T (S (1), new char[r_0_imax]);
+  T (S (2), new char[r_0_imax + 1]);
+  T (S (9), new char[r_0_imax * 2 + 1]);
+
+  int r_1_imax = SR (1, INT_MAX);
+  T (S (1), new char[r_1_imax]);
+  T (S (2), new char[r_1_imax + 1]);
+  T (S (9), new char[r_1_imax * 2 + 1]);
+
+  ptrdiff_t r_dmin_dmax = SR (DIFF_MIN, DIFF_MAX);
+  T (S (1), new char[r_dmin_dmax]);
+  T (S (2), new char[r_dmin_dmax + 1]);
+  T (S (9), new char[r_dmin_dmax * 2 + 1]);
+}
+
+
+void test_strcpy_new_char_array (size_t n)
+{
+  size_t r_0_1 = UR (0, 1);
+
+  T (S (0), new char[r_0_1][1]);
+  T (S (1), new char[r_0_1][1]);    // { dg-warning "\\\[-Wstringop-overflow" }
+  T (S (1), new char[r_0_1][2]);
+  T (S (2), new char[r_0_1][2]);    // { dg-warning "\\\[-Wstringop-overflow" }
+
+  size_t r_1_2 = UR (1, 2);
+  T (S (0), new char[r_1_2][0]);    // { dg-warning "\\\[-Wstringop-overflow" }
+  T (S (0), new char[r_1_2][1]);
+  T (S (1), new char[r_1_2][1]);
+  T (S (2), new char[r_1_2][1]);    // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), new char[r_1_2][0]);    // { dg-warning "\\\[-Wstringop-overflow" }
+  T (S (0), new char[r_1_2][1]);
+  T (S (1), new char[r_1_2][2]);
+  T (S (3), new char[r_1_2][2]);
+  T (S (4), new char[r_1_2][2]);    // { dg-warning "\\\[-Wstringop-overflow" }
+}
+
+
+#ifdef __INT16_TYPE__
+
+typedef __INT16_TYPE__ int16_t;
+
+void test_strcpy_new_int16_t (size_t n)
+{
+  size_t r_0_1 = UR (0, 1);
+  size_t r_1_2 = UR (1, 2);
+  size_t r_2_3 = UR (2, 3);
+
+  T (S (0), new int16_t[r_0_1]);
+  T (S (1), new int16_t[r_0_1]);
+  T (S (2), new int16_t[r_0_1]);      // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), new int16_t[r_1_2]);
+  T (S (1), new int16_t[r_1_2]);
+  T (S (2), new int16_t[r_1_2]);
+  T (S (3), new int16_t[r_1_2]);
+  T (S (4), new int16_t[r_1_2]);      // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), new int16_t[r_2_3]);
+  T (S (1), new int16_t[r_2_3]);
+  T (S (5), new int16_t[r_2_3]);
+  T (S (6), new int16_t[r_2_3]);      // { dg-warning "\\\[-Wstringop-overflow" }
+  T (S (9), new int16_t[r_2_3]);      // { dg-warning "\\\[-Wstringop-overflow" }
+
+  size_t r_2_smax = UR (2, SIZE_MAX);
+  T (S (0), new int16_t[r_2_smax]);
+  T (S (1), new int16_t[r_2_smax]);
+  T (S (2), new int16_t[r_2_smax]);
+  T (S (3), new int16_t[r_2_smax * 2]);
+  T (S (4), new int16_t[r_2_smax * 2 + 1]);
+
+  T (S (1), new int16_t[n]);
+  T (S (2), new int16_t[n + 1]);
+  T (S (9), new int16_t[n * 2 + 1]);
+
+  int r_imin_imax = SR (INT_MIN, INT_MAX);
+  T (S (1), new int16_t[r_imin_imax]);
+  T (S (2), new int16_t[r_imin_imax + 1]);
+  T (S (9), new int16_t[r_imin_imax * 2 + 1]);
+
+  int r_0_imax = SR (0, INT_MAX);
+  T (S (1), new int16_t[r_0_imax]);
+  T (S (2), new int16_t[r_0_imax + 1]);
+  T (S (9), new int16_t[r_0_imax * 2 + 1]);
+
+  int r_1_imax = SR (1, INT_MAX);
+  T (S (1), new int16_t[r_1_imax]);
+  T (S (2), new int16_t[r_1_imax + 1]);
+  T (S (9), new int16_t[r_1_imax * 2 + 1]);
+
+  ptrdiff_t r_dmin_dmax = SR (DIFF_MIN, DIFF_MAX);
+  T (S (1), new int16_t[r_dmin_dmax]);
+  T (S (2), new int16_t[r_dmin_dmax + 1]);
+  T (S (9), new int16_t[r_dmin_dmax * 2 + 1]);
+}
+
+#endif   // int16_t
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-56.c b/gcc/testsuite/gcc.dg/Warray-bounds-56.c
new file mode 100644 (file)
index 0000000..3d85660
--- /dev/null
@@ -0,0 +1,88 @@
+/* PR middle-end/91582 - missing heap overflow detection for strcpy
+
+   The -Warray-bounds instances here probably should be replaced by
+   -Wstringop-overflow when it detects these overflows (see also
+   the xfails in Wstringop-overflow-25.c).
+
+   { dg-do compile }
+   { dg-options "-O2 -Wall -Wno-stringop-overflow -ftrack-macro-expansion=0" } */
+
+#include "range.h"
+
+#define INT_MAX     __INT_MAX__
+#define INT_MIN     (-INT_MAX - 1)
+
+#define ATTR(...)   __attribute__ ((__VA_ARGS__))
+#define NOIPA       ATTR (noipa)
+
+extern void* malloc (size_t);
+extern char* strcpy (char*, const char*);
+
+void sink (void*);
+
+#define S36 "0123456789abcdefghijklmnopqrstuvwxyz"
+#define S(N) (S36 + sizeof S36 - N - 1)
+
+struct Flex
+{
+  char n, ax[];
+};
+
+extern struct Flex fx;
+struct Flex f1 = { 1, { 1 } };
+struct Flex f2 = { 2, { 1, 2 } };
+struct Flex f3 = { 3, { 1, 2, 3 } };
+
+#define T(src, f) do {                         \
+    char *s = src;                             \
+    char *d = f.ax;                            \
+    strcpy (d, s);                             \
+    sink (&f);                                 \
+  } while (0)
+
+NOIPA void test_strcpy_flexarray (void)
+{
+  T (S (0), fx);                // { dg-bogus "\\\[-Warray-bounds" "pr92815" { xfail *-*-*} }
+  T (S (9), fx);                // { dg-bogus "\\\[-Warray-bounds" "pr92815" { xfail *-*-*} }
+
+  T (S (0), f1);
+  T (S (1), f1);                // { dg-warning "\\\[-Warray-bounds" }
+
+  T (S (0), f2);
+  T (S (1), f2);
+  T (S (2), f2);                // { dg-warning "\\\[-Warray-bounds" }
+
+  T (S (0), f3);
+  T (S (2), f3);
+  T (S (3), f3);                // { dg-warning "\\\[-Warray-bounds" }
+  T (S (9), f3);                // { dg-warning "\\\[-Warray-bounds" }
+}
+
+#undef T
+#define T(T, src, n) do {                      \
+    char *s = src;                             \
+    typedef struct { T n, ax[]; } Flex;                \
+    Flex *p = (Flex*)malloc (sizeof *p + n);   \
+    char *d = (char*)p->ax;                    \
+    strcpy (d, s);                             \
+    sink (p);                                  \
+  } while (0)
+
+NOIPA void test_strcpy_malloc_flexarray (void)
+{
+  size_t r_0_1 = UR (0, 1);
+  size_t r_1_2 = UR (1, 2);
+  size_t r_2_3 = UR (2, 3);
+
+  T (char, S (0), r_0_1);
+  T (char, S (1), r_0_1);       // { dg-warning "\\\[-Warray-bounds" }
+
+  T (char, S (0), r_1_2);
+  T (char, S (1), r_1_2);
+  T (char, S (2), r_1_2);       // { dg-warning "\\\[-Warray-bounds" }
+
+  T (char, S (0), r_2_3);
+  T (char, S (2), r_2_3);
+  T (char, S (3), r_2_3);       // { dg-warning "\\\[-Warray-bounds" }
+  T (char, S (9), r_2_3);       // { dg-warning "\\\[-Warray-bounds" }
+}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-25.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-25.c
new file mode 100644 (file)
index 0000000..1b38dfe
--- /dev/null
@@ -0,0 +1,377 @@
+/* PR middle-end/91582 - missing heap overflow detection for strcpy
+   { dg-do compile }
+   { dg-options "-O2 -Wall -Wno-array-bounds -ftrack-macro-expansion=0" } */
+
+#include "range.h"
+
+#define INT_MAX     __INT_MAX__
+#define INT_MIN     (-INT_MAX - 1)
+
+#define ATTR(...)   __attribute__ ((__VA_ARGS__))
+#define NOIPA       ATTR (noipa)
+
+extern void* alloca (size_t);
+extern void* calloc (size_t, size_t);
+extern void* malloc (size_t);
+
+extern ATTR (alloc_size (1), malloc) void*
+  alloc1 (size_t, int);
+extern ATTR (alloc_size (2), malloc) void*
+  alloc2 (int, size_t);
+extern ATTR (alloc_size (2, 4), malloc) void*
+  alloc2_4 (int, size_t, int, size_t);
+
+extern char* strcpy (char*, const char*);
+
+void sink (void*);
+
+#define S36 "0123456789abcdefghijklmnopqrstuvwxyz"
+#define S(N) (S36 + sizeof S36 - N - 1)
+
+#define T(src, alloc) do {                     \
+    char *s = src;                             \
+    char *d = alloc;                           \
+    strcpy (d, s);                             \
+    sink (d);                                  \
+  } while (0)
+
+
+NOIPA void test_strcpy_alloca (size_t n)
+{
+  size_t r_0_1 = UR (0, 1);
+  size_t r_1_2 = UR (1, 2);
+  size_t r_2_3 = UR (2, 3);
+
+  T (S (0), alloca (r_0_1));
+  T (S (1), alloca (r_0_1));      // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), alloca (r_1_2));
+  T (S (1), alloca (r_1_2));
+  T (S (2), alloca (r_1_2));      // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), alloca (r_2_3));
+  T (S (2), alloca (r_2_3));
+  T (S (3), alloca (r_2_3));      // { dg-warning "\\\[-Wstringop-overflow" }
+  T (S (9), alloca (r_2_3));      // { dg-warning "\\\[-Wstringop-overflow" }
+
+  size_t r_2_smax = UR (2, SIZE_MAX);
+  T (S (0), alloca (r_2_smax));
+  T (S (1), alloca (r_2_smax));
+  T (S (2), alloca (r_2_smax));
+  T (S (3), alloca (r_2_smax * 2));
+  T (S (4), alloca (r_2_smax * 2 + 1));
+
+  T (S (1), alloca (n));
+  T (S (2), alloca (n + 1));
+  T (S (9), alloca (n * 2 + 1));
+
+  int r_imin_imax = SR (INT_MIN, INT_MAX);
+  T (S (1), alloca (r_imin_imax));
+  T (S (2), alloca (r_imin_imax + 1));
+  T (S (9), alloca (r_imin_imax * 2 + 1));
+
+  int r_0_imax = SR (0, INT_MAX);
+  T (S (1), alloca (r_0_imax));
+  T (S (2), alloca (r_0_imax + 1));
+  T (S (9), alloca (r_0_imax * 2 + 1));
+
+  int r_1_imax = SR (1, INT_MAX);
+  T (S (1), alloca (r_1_imax));
+  T (S (2), alloca (r_1_imax + 1));
+  T (S (9), alloca (r_1_imax * 2 + 1));
+
+  ptrdiff_t r_dmin_dmax = SR (DIFF_MIN, DIFF_MAX);
+  T (S (1), alloca (r_dmin_dmax));
+  T (S (2), alloca (r_dmin_dmax + 1));
+  T (S (9), alloca (r_dmin_dmax * 2 + 1));
+}
+
+NOIPA void test_strcpy_calloc (void)
+{
+  size_t r_1_2 = UR (1, 2);
+  size_t r_2_3 = UR (2, 3);
+
+  T (S (0), calloc (r_1_2, 1));
+  T (S (1), calloc (r_1_2, 1));
+  T (S (2), calloc (r_1_2, 1));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (2), calloc (r_2_3, 1));
+  T (S (3), calloc (r_2_3, 1));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), calloc (1, r_1_2));
+  T (S (1), calloc (1, r_1_2));
+  T (S (2), calloc (1, r_1_2));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (2), calloc (1, r_2_3));
+  T (S (3), calloc (1, r_2_3));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), calloc (r_1_2, 2));
+  T (S (1), calloc (r_1_2, 2));
+  T (S (2), calloc (r_1_2, 2));
+  T (S (3), calloc (r_1_2, 2));
+  T (S (4), calloc (r_1_2, 2));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), calloc (r_2_3, 2));
+  T (S (1), calloc (r_2_3, 2));
+  T (S (2), calloc (r_2_3, 2));
+  T (S (5), calloc (r_2_3, 2));
+  T (S (6), calloc (r_2_3, 2));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), calloc (r_1_2, 2));
+  T (S (1), calloc (r_1_2, 2));
+  T (S (2), calloc (r_1_2, 2));
+  T (S (3), calloc (r_1_2, 2));
+  T (S (4), calloc (r_1_2, 2));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), calloc (r_2_3, 2));
+  T (S (1), calloc (r_2_3, 2));
+  T (S (2), calloc (r_2_3, 2));
+  T (S (5), calloc (r_2_3, 2));
+  T (S (6), calloc (r_2_3, 2));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), calloc (r_1_2, r_2_3));
+  T (S (1), calloc (r_1_2, r_2_3));
+  T (S (2), calloc (r_1_2, r_2_3));
+  T (S (3), calloc (r_1_2, r_2_3));
+  T (S (4), calloc (r_1_2, r_2_3));
+  T (S (5), calloc (r_1_2, r_2_3));
+  T (S (6), calloc (r_1_2, r_2_3));   // { dg-warning "\\\[-Wstringop-overflow" }
+  T (S (9), calloc (r_1_2, r_2_3));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  size_t r_2_dmax = UR (2, DIFF_MAX);
+  T (S (0), calloc (0, r_2_dmax));   // { dg-warning "\\\[-Wstringop-overflow" }
+  T (S (0), calloc (1, r_2_dmax));
+  T (S (9), calloc (2, r_2_dmax));
+
+  T (S (0), calloc (r_2_dmax, r_2_dmax));
+  T (S (9), calloc (r_2_dmax, r_2_dmax));
+
+  size_t r_2_smax = UR (2, SIZE_MAX);
+  T (S (0), calloc (r_2_smax, 1));
+  T (S (9), calloc (r_2_smax, 2));
+
+  T (S (0), calloc (r_2_smax, r_2_smax));
+  T (S (9), calloc (r_2_smax, r_2_smax));
+}
+
+
+NOIPA void test_strcpy_malloc (void)
+{
+  size_t r_0_1 = UR (0, 1);
+  size_t r_1_2 = UR (1, 2);
+  size_t r_2_3 = UR (2, 3);
+
+  T (S (0), malloc (r_0_1));
+  T (S (1), malloc (r_0_1));      // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), malloc (r_1_2));
+  T (S (1), malloc (r_1_2));
+  T (S (2), malloc (r_1_2));      // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), malloc (r_2_3));
+  T (S (2), malloc (r_2_3));
+  T (S (3), malloc (r_2_3));      // { dg-warning "\\\[-Wstringop-overflow" }
+  T (S (9), malloc (r_2_3));      // { dg-warning "\\\[-Wstringop-overflow" }
+}
+
+
+NOIPA void test_strcpy_alloc1 (void)
+{
+  size_t r_0_1 = UR (0, 1);
+  size_t r_1_2 = UR (1, 2);
+  size_t r_2_3 = UR (2, 3);
+
+#define alloc1(n) alloc1 (n, 1)
+
+  T (S (0), alloc1 (r_0_1));
+  T (S (1), alloc1 (r_0_1));      // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), alloc1 (r_1_2));
+  T (S (1), alloc1 (r_1_2));
+  T (S (2), alloc1 (r_1_2));      // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), alloc1 (r_2_3));
+  T (S (2), alloc1 (r_2_3));
+  T (S (3), alloc1 (r_2_3));      // { dg-warning "\\\[-Wstringop-overflow" }
+  T (S (9), alloc1 (r_2_3));      // { dg-warning "\\\[-Wstringop-overflow" }
+}
+
+NOIPA void test_strcpy_alloc2 (void)
+{
+  size_t r_0_1 = UR (0, 1);
+  size_t r_1_2 = UR (1, 2);
+  size_t r_2_3 = UR (2, 3);
+
+#define alloc2(n) alloc2 (1, n)
+
+  T (S (0), alloc1 (r_0_1));
+  T (S (1), alloc1 (r_0_1));      // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), alloc1 (r_1_2));
+  T (S (1), alloc1 (r_1_2));
+  T (S (2), alloc1 (r_1_2));      // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), alloc1 (r_2_3));
+  T (S (2), alloc1 (r_2_3));
+  T (S (3), alloc1 (r_2_3));      // { dg-warning "\\\[-Wstringop-overflow" }
+  T (S (9), alloc1 (r_2_3));      // { dg-warning "\\\[-Wstringop-overflow" }
+}
+
+
+NOIPA void test_strcpy_alloc2_4 (void)
+{
+  size_t r_1_2 = UR (1, 2);
+  size_t r_2_3 = UR (2, 3);
+
+#define alloc2_4(n1, n2) alloc2_4 (1, n1, 2, n2)
+
+  T (S (0), alloc2_4 (r_1_2, 1));
+  T (S (1), alloc2_4 (r_1_2, 1));
+  T (S (2), alloc2_4 (r_1_2, 1));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (2), alloc2_4 (r_2_3, 1));
+  T (S (3), alloc2_4 (r_2_3, 1));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), alloc2_4 (1, r_1_2));
+  T (S (1), alloc2_4 (1, r_1_2));
+  T (S (2), alloc2_4 (1, r_1_2));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (2), alloc2_4 (1, r_2_3));
+  T (S (3), alloc2_4 (1, r_2_3));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), alloc2_4 (r_1_2, 2));
+  T (S (1), alloc2_4 (r_1_2, 2));
+  T (S (2), alloc2_4 (r_1_2, 2));
+  T (S (3), alloc2_4 (r_1_2, 2));
+  T (S (4), alloc2_4 (r_1_2, 2));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), alloc2_4 (r_2_3, 2));
+  T (S (1), alloc2_4 (r_2_3, 2));
+  T (S (2), alloc2_4 (r_2_3, 2));
+  T (S (5), alloc2_4 (r_2_3, 2));
+  T (S (6), alloc2_4 (r_2_3, 2));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), alloc2_4 (r_1_2, 2));
+  T (S (1), alloc2_4 (r_1_2, 2));
+  T (S (2), alloc2_4 (r_1_2, 2));
+  T (S (3), alloc2_4 (r_1_2, 2));
+  T (S (4), alloc2_4 (r_1_2, 2));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), alloc2_4 (r_2_3, 2));
+  T (S (1), alloc2_4 (r_2_3, 2));
+  T (S (2), alloc2_4 (r_2_3, 2));
+  T (S (5), alloc2_4 (r_2_3, 2));
+  T (S (6), alloc2_4 (r_2_3, 2));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (S (0), alloc2_4 (r_1_2, r_2_3));
+  T (S (1), alloc2_4 (r_1_2, r_2_3));
+  T (S (2), alloc2_4 (r_1_2, r_2_3));
+  T (S (3), alloc2_4 (r_1_2, r_2_3));
+  T (S (4), alloc2_4 (r_1_2, r_2_3));
+  T (S (5), alloc2_4 (r_1_2, r_2_3));
+  T (S (6), alloc2_4 (r_1_2, r_2_3));   // { dg-warning "\\\[-Wstringop-overflow" }
+  T (S (9), alloc2_4 (r_1_2, r_2_3));   // { dg-warning "\\\[-Wstringop-overflow" }
+
+  size_t r_2_dmax = UR (2, DIFF_MAX);
+  T (S (0), alloc2_4 (r_2_dmax, r_2_dmax));
+  T (S (9), alloc2_4 (r_2_dmax, r_2_dmax));
+
+  size_t r_2_smax = UR (2, SIZE_MAX);
+  T (S (0), alloc2_4 (r_2_smax, r_2_smax));
+  T (S (9), alloc2_4 (r_2_smax, r_2_smax));
+}
+
+#undef T
+#define T(T, src, n) do {                      \
+    char *s = src;                             \
+    T vla[n];                                  \
+    char *d = (char*)vla;                      \
+    strcpy (d, s);                             \
+    sink (vla);                                        \
+  } while (0)
+
+NOIPA void test_strcpy_vla (void)
+{
+  size_t r_0_1 = UR (0, 1);
+  size_t r_1_2 = UR (1, 2);
+  size_t r_2_3 = UR (2, 3);
+
+  T (char, S (0), r_0_1);
+  T (char, S (1), r_0_1);       // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (char, S (0), r_1_2);
+  T (char, S (1), r_1_2);
+  T (char, S (2), r_1_2);       // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (char, S (0), r_2_3);
+  T (char, S (2), r_2_3);
+  T (char, S (3), r_2_3);       // { dg-warning "\\\[-Wstringop-overflow" }
+  T (char, S (9), r_2_3);       // { dg-warning "\\\[-Wstringop-overflow" }
+
+#ifdef __INT16_TYPE__
+  typedef __INT16_TYPE__ int16_t;
+
+  T (int16_t, S (0), r_1_2);
+  T (int16_t, S (2), r_1_2);
+  T (int16_t, S (3), r_1_2);
+  T (int16_t, S (4), r_1_2);    // { dg-warning "\\\[-Wstringop-overflow" }
+  T (int16_t, S (5), r_1_2);    // { dg-warning "\\\[-Wstringop-overflow" }
+  T (int16_t, S (9), r_1_2);    // { dg-warning "\\\[-Wstringop-overflow" }
+
+  T (int16_t, S (0), r_2_3);
+  T (int16_t, S (2), r_2_3);
+  T (int16_t, S (3), r_2_3);
+  T (int16_t, S (4), r_2_3);
+  T (int16_t, S (5), r_2_3);
+  T (int16_t, S (6), r_2_3);    // { dg-warning "\\\[-Wstringop-overflow" }
+#endif
+
+#ifdef __INT32_TYPE__
+  typedef __INT32_TYPE__ int32_t;
+
+  T (int32_t, S ( 0), r_2_3);
+  T (int32_t, S ( 2), r_2_3);
+  T (int32_t, S ( 3), r_2_3);
+  T (int32_t, S ( 4), r_2_3);
+  T (int32_t, S ( 5), r_2_3);
+  T (int32_t, S ( 6), r_2_3);
+  T (int32_t, S (11), r_2_3);
+  T (int32_t, S (12), r_2_3);    // { dg-warning "\\\[-Wstringop-overflow" }
+  T (int32_t, S (36), r_2_3);    // { dg-warning "\\\[-Wstringop-overflow" }
+#endif
+}
+
+
+struct Flex
+{
+  char n, ax[];
+};
+
+#undef T
+#define T(T, src, n) do {                      \
+    char *s = src;                             \
+    typedef struct { T n, ax[]; } Flex;                \
+    Flex *p = (Flex*)malloc (sizeof *p + n);   \
+    char *d = (char*)p->ax;                    \
+    strcpy (d, s);                             \
+    sink (p);                                  \
+  } while (0)
+
+NOIPA void test_strcpy_malloc_flexarray (void)
+{
+  size_t r_0_1 = UR (0, 1);
+  size_t r_1_2 = UR (1, 2);
+  size_t r_2_3 = UR (2, 3);
+
+  T (char, S (0), r_0_1);
+  T (char, S (1), r_0_1);       // { dg-warning "\\\[-Wstringop-overflow" "pr92814" { xfail *-*-* } }
+
+  T (char, S (0), r_1_2);
+  T (char, S (1), r_1_2);
+  T (char, S (2), r_1_2);       // { dg-warning "\\\[-Wstringop-overflow" "pr92814" { xfail *-*-* } }
+
+  T (char, S (0), r_2_3);
+  T (char, S (2), r_2_3);
+  T (char, S (3), r_2_3);       // { dg-warning "\\\[-Wstringop-overflow" "pr92814" { xfail *-*-* } }
+  T (char, S (9), r_2_3);       // { dg-warning "\\\[-Wstringop-overflow" "pr92814" { xfail *-*-* } }
+}
index 88a777158054f95b9e850dc684edc427f5d6a254..7b0dc6e4535efdb750626e641fe43237cce27882 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */
+/* { dg-options "-O2 -Wall -Wno-array-bounds -ftrack-macro-expansion=0" } */
 
 extern void abort (void);
 
index 8564811fc0b8e3e915eaff8d1300bd025ae64b7b..f311ca32aa602a249384fcb22432157af8aebbb5 100644 (file)
@@ -2,7 +2,7 @@
    Exercise attribute copy for functions.
    { dg-do compile }
    { dg-require-alias "" }
-   { dg-options "-O2 -Wall" } */
+   { dg-options "-O2 -Wall -Wno-array-bounds" } */
 
 #define Assert(expr)   typedef char AssertExpr[2 * !!(expr) - 1]
 
index 489f88077d44f7db0ed5f0e5df33f22878a5287b..320cd51fcf2d9fd1eb3a174eb4e3011f01add4a6 100644 (file)
@@ -1,4 +1,4 @@
-/* Test exercising -Wrawmem-overflow and -Wstringop-overflow warnings.  */
+/* Test exercising -Wstringop-overflow warnings.  */
 /* { dg-do compile } */
 /* { dg-options "-O2 -Wstringop-overflow=1" } */
 
@@ -49,7 +49,7 @@ void test_memop_warn_local (const void *src)
   memcpy (a, src, n);   /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" } */
   escape (a, src);
 
-  /* At -Wrawmem-overflow=1 the destination is considered to be
+  /* At -Wstringop-overflow=1 the destination is considered to be
      the whole array and its size is therefore sizeof a.  */
   memcpy (&a[0], src, n);   /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" } */
   escape (a, src);
@@ -110,12 +110,12 @@ void test_memop_warn_alloc (const void *src)
 
   struct A *a = __builtin_malloc (sizeof *a * 2);
 
-  memcpy (a, src, n);   /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" "memcpy into allocated" { xfail *-*-*} } */
+  memcpy (a, src, n);   /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" "memcpy into allocated" } */
   escape (a, src);
 
-  /* At -Wrawmem-overflow=1 the destination is considered to be
+  /* At -Wstringop-overflow=1 the destination is considered to be
      the whole array and its size is therefore sizeof a.  */
-  memcpy (&a[0], src, n);   /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" "memcpy into allocated" { xfail *-*-*} } */
+  memcpy (&a[0], src, n);   /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" "memcpy into allocated" } */
   escape (a, src);
 
   /* Verify the same as above but by writing into the first mmeber
@@ -127,7 +127,7 @@ void test_memop_warn_alloc (const void *src)
 
   struct B *b = __builtin_malloc (sizeof *b * 2);
 
-  memcpy (&b[0], src, n);   /* { dg-warning "writing between 12 and 32 bytes into a region of size 8 overflows the destination" "memcpy into allocated" { xfail *-*-*} } */
+  memcpy (&b[0], src, n);   /* { dg-warning "writing between 12 and 32 bytes into a region of size 8 overflows the destination" "memcpy into allocated" } */
   escape (b);
 
   /* The following idiom of clearing multiple members of a struct is
index f4056f3632b771ecf9103012179572f510678e91..741c1f88eaa54763926a119b396ecec99df12f83 100644 (file)
@@ -102,9 +102,9 @@ void test_memop_warn_alloc (void *p)
 
   struct A *a = __builtin_malloc (sizeof *a * 2);
 
-  memcpy (p, a, n);   /* { dg-warning "reading between 8 and 32 bytes from region of size 4" "memcpy from allocated" { xfail *-*-*} } */
+  memcpy (p, a, n);   /* { dg-warning "reading between 8 and 32 bytes from a region of size 4" "memcpy from allocated" } */
 
-  memcpy (p, &a[0], n);   /* { dg-warning "reading between 8 and 32 bytes from a region of size 4" "memcpy from allocated" { xfail *-*-*} } */
+  memcpy (p, &a[0], n);   /* { dg-warning "reading between 8 and 32 bytes from a region of size 4" "memcpy from allocated" } */
 
   memcpy (p, &a[0].a, n);   /* { dg-warning "reading between 8 and 32 bytes from a region of size 4" "memcpy from allocated" { xfail *-*-*} } */
 
@@ -112,13 +112,13 @@ void test_memop_warn_alloc (void *p)
 
   struct B *b = __builtin_malloc (sizeof *b * 2);
 
-  memcpy (p, &b[0], n);   /* { dg-warning "reading between 12 and 32 bytes from a region of size 8" "memcpy from allocated" { xfail *-*-*} } */
+  memcpy (p, &b[0], n);   /* { dg-warning "reading between 12 and 32 bytes from a region of size 8" "memcpy from allocated" } */
 
   /* Verify memchr/memcmp.  */
   n = sizeof *b * 2 + 1;
 
-  memchr (b, 1, n);   /* { dg-warning "reading 5 bytes from a region of size 4" "memcmp from allocated" { xfail *-*-* } } */
-  memcmp (p, b, n);   /* { dg-warning "reading 5 bytes from a region of size 4" "memcmp from allocated" { xfail *-*-* } } */
+  memchr (b, 1, n);   /* { dg-warning "reading 9 bytes from a region of size 8" "memcmp from allocated" } */
+  memcmp (p, b, n);   /* { dg-warning "reading 9 bytes from a region of size 8" "memcmp from allocated" } */
 }
 
 
index c31440debe26ce8d20acfe58dce318f08f275128..dbcc105fcd2d6103187836b2594e4afd9b0c2679 100644 (file)
@@ -10,3 +10,5 @@ b ()
   a (c);
   a (c);
 }
+
+/* { dg-prune-output "\\\[-Wstringop-overflow" }  */
index 939e069517d166b236f52c6e6707026248ce690c..e1ad737263c48ee360c63c3a95f94a345184fb4e 100644 (file)
@@ -10,3 +10,5 @@ b ()
   a (c);
   a (c);
 }
+
+/* { dg-prune-output "\\\[-Wstringop-overflow" }  */
index d46586a90e5337aec7fec0a2a5440b8f3c9e4f46..beff17b37f1a046aed1bf00bde2e360befb2319e 100644 (file)
@@ -4394,8 +4394,22 @@ handle_store (gimple_stmt_iterator *gsi, bool *zero_write, const vr_values *rval
                               stmt, lenrange[2], dstsize))
                  {
                    if (decl)
-                     inform (DECL_SOURCE_LOCATION (decl),
-                             "destination object declared here");
+                     {
+                       if (TREE_CODE (decl) == SSA_NAME)
+                         {
+                           gimple *stmt = SSA_NAME_DEF_STMT (decl);
+                           if (is_gimple_call (stmt))
+                             {
+                               tree allocfn = gimple_call_fndecl (stmt);
+                               inform (gimple_location (stmt),
+                                       "destination region allocated by %qD "
+                                       "here", allocfn);
+                             }
+                         }
+                       else
+                         inform (DECL_SOURCE_LOCATION (decl),
+                                 "destination object declared here");
+                     }
                    gimple_set_no_warning (stmt, true);
                  }
              }