[gcc/devel/ranger] PR middle-end/93829 - bogus -Wstringop-overflow on memcpy of a struct with a pointer member from ano

Aldy Hernandez aldyh@gcc.gnu.org
Wed Jun 17 19:20:37 GMT 2020


https://gcc.gnu.org/g:1e9369c5dcf301e090d3a83e2c210cd6b96ac08c

commit 1e9369c5dcf301e090d3a83e2c210cd6b96ac08c
Author: Martin Sebor <msebor@redhat.com>
Date:   Sun Mar 1 17:35:49 2020 -0700

    PR middle-end/93829 - bogus -Wstringop-overflow on memcpy of a struct with a pointer member from another with a long string
    
    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.

Diff:
---
 gcc/ChangeLog                                |  6 ++++
 gcc/testsuite/ChangeLog                      |  5 +++
 gcc/testsuite/gcc.dg/Wstringop-overflow-32.c | 51 ++++++++++++++++++++++++++++
 gcc/tree-ssa-strlen.c                        | 28 ++++++++++-----
 4 files changed, 81 insertions(+), 9 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2a69c680a9b..f186408e104 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index fbb604d013f..7e73cc6e34b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 00000000000..e5939567a4d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-32.c
@@ -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" }
+}
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 9a88a85b07c..b76b54efbd8 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -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;


More information about the Gcc-cvs mailing list