PR middle-end/93829 - bogus -Wstringop-overflow on memcpy of a struct with a pointer...
authorMartin Sebor <msebor@redhat.com>
Mon, 2 Mar 2020 00:35:49 +0000 (17:35 -0700)
committerMartin Sebor <msebor@redhat.com>
Mon, 2 Mar 2020 00:35:49 +0000 (17:35 -0700)
gcc/testsuite/ChangeLog:

PR middle-end/93829
* gcc.dg/Wstringop-overflow-32.c: New test.

gcc/ChangeLog:

PR middle-end/93829
* tree-ssa-strlen.c (count_nonzero_bytes): Set the size to that
  of a pointer in the outermost ADDR_EXPRs.

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/Wstringop-overflow-32.c [new file with mode: 0644]
gcc/tree-ssa-strlen.c

index 2a69c680a9b9d75edec98ba4ab44f8b40ecd5161..f186408e1045e2a69381ffe7822ae08394261db1 100644 (file)
@@ -1,3 +1,9 @@
+2020-03-01  Martin Sebor  <msebor@redhat.com>
+
+       PR middle-end/93829
+       * tree-ssa-strlen.c (count_nonzero_bytes): Set the size to that
+         of a pointer in the outermost ADDR_EXPRs.
+
 2020-02-28  Jeff Law  <law@redhat.com>
 
        * config/v850/v850.h (STATIC_CHAIN_REGNUM): Change to r19.
index fbb604d013f0b181b36cdf9786d0eee8e7d5f3ac..7e73cc6e34bda37dd9e8a8b8b8fbd5cd3b7ce22f 100644 (file)
@@ -1,3 +1,8 @@
+2020-03-01  Martin Sebor  <msebor@redhat.com>
+
+       PR middle-end/93829
+       * gcc.dg/Wstringop-overflow-32.c: New test.
+
 2020-03-01  Segher Boessenkool  <segher@kernel.crashing.org>
 
        PR testsuite/91797
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-32.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-32.c
new file mode 100644 (file)
index 0000000..e593956
--- /dev/null
@@ -0,0 +1,51 @@
+/* PR middle-end/93829 - bogus -Wstringop-overflow on memcpy of a struct
+   with a pointer member from another with a long string
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+extern void* memcpy (void*, const void*, __SIZE_TYPE__);
+
+#define S40 "0123456789012345678901234567890123456789"
+
+const char s40[] = S40;
+
+struct S
+{
+  const void *p, *q, *r;
+} s, sa[2];
+
+
+void test_lit_decl (void)
+{
+  struct S t = { 0, S40, 0 };
+
+  memcpy (&s, &t, sizeof t);    // { dg-bogus "-Wstringop-overflow" }
+}
+
+void test_str_decl (void)
+{
+  struct S t = { 0, s40, 0 };
+
+  memcpy (&s, &t, sizeof t);    // { dg-bogus "-Wstringop-overflow" }
+}
+
+
+void test_lit_ssa (int i)
+{
+  if (i < 1)
+    i = 1;
+  struct S *p = &sa[i];
+  struct S t = { 0, S40, 0 };
+
+  memcpy (p, &t, sizeof t);    // { dg-bogus "-Wstringop-overflow" }
+}
+
+void test_str_ssa (int i)
+{
+  if (i < 1)
+    i = 1;
+  struct S *p = &sa[i];
+  struct S t = { 0, s40, 0 };
+
+  memcpy (p, &t, sizeof t);    // { dg-bogus "-Wstringop-overflow" }
+}
index 9a88a85b07c056a37a18ee12a8201c5659bc8037..b76b54efbd8f84a70ed8c875f02d9bd3e5f7c959 100644 (file)
@@ -4587,12 +4587,15 @@ int ssa_name_limit_t::next_ssa_name (tree ssa_name)
 
 /* Determines the minimum and maximum number of leading non-zero bytes
    in the representation of EXP and set LENRANGE[0] and LENRANGE[1]
-   to each.  Sets LENRANGE[2] to the total number of bytes in
-   the representation.  Sets *NULTREM if the representation contains
-   a zero byte, and sets *ALLNUL if all the bytes are zero.
+   to each.
+   Sets LENRANGE[2] to the total size of the access (which may be less
+   than LENRANGE[1] when what's being referenced by EXP is a pointer
+   rather than an array).
+   Sets *NULTERM if the representation contains a zero byte, and sets
+   *ALLNUL if all the bytes are zero.
    OFFSET and NBYTES are the offset into the representation and
-   the size of the access to it determined from a MEM_REF or zero
-   for other expressions.
+   the size of the access to it determined from an ADDR_EXPR (i.e.,
+   a pointer) or MEM_REF or zero for other expressions.
    Uses RVALS to determine range information.
    Avoids recursing deeper than the limits in SNLIM allow.
    Returns true on success and false otherwise.  */
@@ -4692,7 +4695,13 @@ count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset,
     }
 
   if (TREE_CODE (exp) == ADDR_EXPR)
-    exp = TREE_OPERAND (exp, 0);
+    {
+      /* If the size of the access hasn't been determined yet it's that
+        of a pointer.  */
+      if (!nbytes)
+       nbytes = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (exp)));
+      exp = TREE_OPERAND (exp, 0);
+    }
 
   if (TREE_CODE (exp) == SSA_NAME)
     {
@@ -4788,9 +4797,10 @@ count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset,
        return false;
 
       if (!nbytes)
-       /* If NBYTES hasn't been determined earlier from MEM_REF,
-          set it here.  It includes all internal nuls, including
-          the terminating one if the string has one.  */
+       /* If NBYTES hasn't been determined earlier, either from ADDR_EXPR
+          (i.e., it's the size of a pointer), or from MEM_REF (as the size
+          of the access), set it here to the size of the string, including
+          all internal and trailing nuls if the string has any.  */
        nbytes = nchars - offset;
 
       prep = TREE_STRING_POINTER (exp) + offset;