aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-32.c51
-rw-r--r--gcc/tree-ssa-strlen.c28
4 files changed, 81 insertions, 9 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2a69c68..f186408 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 fbb604d..7e73cc6 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 0000000..e593956
--- /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 9a88a85..b76b54e 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;