From 1e9369c5dcf301e090d3a83e2c210cd6b96ac08c Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Sun, 1 Mar 2020 17:35:49 -0700 Subject: [PATCH] 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. --- 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(-) create mode 100644 gcc/testsuite/gcc.dg/Wstringop-overflow-32.c 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 + + 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 * 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 + + PR middle-end/93829 + * gcc.dg/Wstringop-overflow-32.c: New test. + 2020-03-01 Segher Boessenkool 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; -- 2.30.2