--- /dev/null
+/* 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" }
+}
/* 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. */
}
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)
{
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;