Commit daa94de2 by Martin Sebor Committed by Martin Sebor

PR middle-end/91977 - missing -Wstringop-overflow on memcpy into a pointer plus offset

gcc/ChangeLog:

	PR middle-end/91977
	* tree-ssa-strlen.c (count_nonzero_bytes): Handle assignments with
	MEM_REF right operand.  Avoid failing for MEM_REF assignments from
	uninitialized objects.

gcc/testsuite/ChangeLog:

	PR middle-end/91977
	* gcc.dg/Wstringop-overflow-18.c: New test.

From-SVN: r276603
parent 28a5fa54
2019-10-04 Martin Sebor <msebor@redhat.com> 2019-10-04 Martin Sebor <msebor@redhat.com>
PR middle-end/91977
* tree-ssa-strlen.c (count_nonzero_bytes): Handle assignments with
MEM_REF right operand. Avoid failing for MEM_REF assignments from
uninitialized objects.
2019-10-04 Martin Sebor <msebor@redhat.com>
* builtins.c (compute_objsize): Add an argument. * builtins.c (compute_objsize): Add an argument.
* tree-object-size.c (addr_object_size): Same. * tree-object-size.c (addr_object_size): Same.
(compute_builtin_object_size): Same. (compute_builtin_object_size): Same.
......
2019-10-04 Martin Sebor <msebor@redhat.com> 2019-10-04 Martin Sebor <msebor@redhat.com>
PR middle-end/91977
* gcc.dg/Wstringop-overflow-18.c: New test.
2019-10-04 Martin Sebor <msebor@redhat.com>
* gcc.dg/Wstringop-overflow-17.c: New test. * gcc.dg/Wstringop-overflow-17.c: New test.
2019-10-04 Steven G. Kargl <kargl@gcc.gnu.org> 2019-10-04 Steven G. Kargl <kargl@gcc.gnu.org>
......
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O2 -Warray-bounds" } */ /* { dg-options "-O2 -Warray-bounds -Wno-stringop-overflow" } */
typedef struct typedef struct
{ {
......
/* PR middle-end/91977 - missing -Wstringop-overflow on memcpy into
a pointer plus offset
{ dg-do compile }
{ dg-options "-O2 -Wall -Wno-array-bounds -ftrack-macro-expansion=0" } */
#define NOIPA __attribute__ ((noipa))
#define CONCAT(a, b) a ## b
#define CAT(a, b) CONCAT (a, b)
#define S3 "123"
#define S4 "1234"
char a1[1], a2[2], a3[3], a4[4], a5[5], a6[6], a7[7], a8[8];
char b1[1], b2[2], b3[3], b4[4], b5[5], b6[6], b7[7], b8[8];
#define T(dst, src, off, n) \
NOIPA void CAT (test_on_line_, __LINE__) (const void *s) \
{ \
__builtin_memcpy (dst + off, src, n); \
} typedef void dummy_type
T (a4, s, 0, 1);
T (a4, s, 1, 1);
T (a4, s, 2, 1);
T (a4, s, 3, 1);
T (a4, s, 4, 1); // { dg-warning "writing 1 byte into a region of size 0" }
T (a4, s, 0, 2);
T (a4, s, 1, 2);
T (a4, s, 2, 2);
T (a4, s, 3, 2); // { dg-warning "writing 2 bytes into a region of size 1" }
T (a4, s, 4, 2); // { dg-warning "writing 2 bytes into a region of size 0" }
T (a4, s, 0, 3);
T (a4, s, 1, 3);
T (a4, s, 2, 3); // { dg-warning "writing 3 bytes into a region of size 2" }
T (a4, s, 3, 3); // { dg-warning "writing 3 bytes into a region of size 1" }
T (a4, s, 4, 3); // { dg-warning "writing 3 bytes into a region of size 0" }
T (a4, s, 0, 4);
T (a4, s, 1, 4); // { dg-warning "writing 4 bytes into a region of size 3" }
T (a4, s, 2, 4); // { dg-warning "writing 4 bytes into a region of size 2" }
T (a4, s, 3, 4); // { dg-warning "writing 4 bytes into a region of size 1" }
T (a4, s, 4, 4); // { dg-warning "writing 4 bytes into a region of size 0" }
T (a7, s, 3, 3);
T (a7, s, 4, 3);
T (a7, s, 5, 3); // { dg-warning "writing 3 bytes into a region of size 2" }
T (a7, s, 6, 3); // { dg-warning "writing 3 bytes into a region of size 1" }
T (a7, s, 7, 3); // { dg-warning "writing 3 bytes into a region of size 0" }
T (a7, s, 3, 4);
T (a7, s, 4, 4); // { dg-warning "writing 4 bytes into a region of size 3" }
T (a7, s, 5, 4); // { dg-warning "writing 4 bytes into a region of size 2" }
T (a7, s, 6, 4); // { dg-warning "writing 4 bytes into a region of size 1" }
T (a7, s, 7, 4); // { dg-warning "writing 4 bytes into a region of size 0" }
T (a7, s, 1, 6);
T (a7, s, 2, 6); // { dg-warning "writing 6 bytes into a region of size 5" }
T (a7, s, 3, 6); // { dg-warning "writing 6 bytes into a region of size 4" }
T (a7, s, 4, 6); // { dg-warning "writing 6 bytes into a region of size 3" }
T (a7, s, 5, 6); // { dg-warning "writing 6 bytes into a region of size 2" }
T (a7, s, 6, 6); // { dg-warning "writing 6 bytes into a region of size 1" }
T (a7, s, 7, 6); // { dg-warning "writing 6 bytes into a region of size 0" }
T (a8, s, 1, 7);
T (a8, s, 2, 7); // { dg-warning "writing 7 bytes into a region of size 6" }
T (a8, s, 3, 7); // { dg-warning "writing 7 bytes into a region of size 5" }
T (a8, s, 4, 7); // { dg-warning "writing 7 bytes into a region of size 4" }
T (a8, s, 5, 7); // { dg-warning "writing 7 bytes into a region of size 3" }
T (a8, s, 6, 7); // { dg-warning "writing 7 bytes into a region of size 2" }
T (a8, s, 7, 7); // { dg-warning "writing 7 bytes into a region of size 1" }
T (a8, s, 8, 7); // { dg-warning "writing 7 bytes into a region of size 0" }
#undef T
#define T(dst, src, off, n) \
NOIPA void CAT (test_on_line_, __LINE__) (const void *s) \
{ \
char *d = dst + off; \
__builtin_memcpy (d, src, n); \
} typedef void dummy_type
T (a4, s, 0, 1);
T (a4, s, 1, 1);
T (a4, s, 2, 1);
T (a4, s, 3, 1);
T (a4, s, 4, 1); // { dg-warning "writing 1 byte into a region of size 0" }
T (a4, s, 0, 2);
T (a4, s, 1, 2);
T (a4, s, 2, 2);
T (a4, s, 3, 2); // { dg-warning "writing 2 bytes into a region of size 1" }
T (a4, s, 4, 2); // { dg-warning "writing 2 bytes into a region of size 0" }
T (a4, s, 0, 3);
T (a4, s, 1, 3);
T (a4, s, 2, 3); // { dg-warning "writing 3 bytes into a region of size 2" }
T (a4, s, 3, 3); // { dg-warning "writing 3 bytes into a region of size 1" }
T (a4, s, 4, 3); // { dg-warning "writing 3 bytes into a region of size 0" }
T (a4, s, 0, 4);
T (a4, s, 1, 4); // { dg-warning "writing 4 bytes into a region of size 3" }
T (a4, s, 2, 4); // { dg-warning "writing 4 bytes into a region of size 2" }
T (a4, s, 3, 4); // { dg-warning "writing 4 bytes into a region of size 1" }
T (a4, s, 4, 4); // { dg-warning "writing 4 bytes into a region of size 0" }
T (a7, s, 3, 3);
T (a7, s, 4, 3);
T (a7, s, 5, 3); // { dg-warning "writing 3 bytes into a region of size 2" }
T (a7, s, 6, 3); // { dg-warning "writing 3 bytes into a region of size 1" }
T (a7, s, 7, 3); // { dg-warning "writing 3 bytes into a region of size 0" }
T (a7, s, 3, 4);
T (a7, s, 4, 4); // { dg-warning "writing 4 bytes into a region of size 3" }
T (a7, s, 5, 4); // { dg-warning "writing 4 bytes into a region of size 2" }
T (a7, s, 6, 4); // { dg-warning "writing 4 bytes into a region of size 1" }
T (a7, s, 7, 4); // { dg-warning "writing 4 bytes into a region of size 0" }
T (a7, s, 1, 6);
T (a7, s, 2, 6); // { dg-warning "writing 6 bytes into a region of size 5" }
T (a7, s, 3, 6); // { dg-warning "writing 6 bytes into a region of size 4" }
T (a7, s, 4, 6); // { dg-warning "writing 6 bytes into a region of size 3" }
T (a7, s, 5, 6); // { dg-warning "writing 6 bytes into a region of size 2" }
T (a7, s, 6, 6); // { dg-warning "writing 6 bytes into a region of size 1" }
T (a7, s, 7, 6); // { dg-warning "writing 6 bytes into a region of size 0" }
#undef T
#define T(dst, src, init, off, n) \
NOIPA void CAT (test_on_line_, __LINE__) (void) \
{ \
__builtin_strcpy (src, init); \
char *d = dst + off; \
__builtin_memcpy (d, src, n); \
} typedef void dummy_type
T (a6, b6, S4, 0, 4);
T (a6, b6, S4, 1, 4);
T (a6, b6, S4, 2, 4);
T (a6, b6, S4, 3, 4); // { dg-warning "writing 4 bytes into a region of size 3" } */
T (a6, b6, S4, 4, 4); // { dg-warning "writing 4 bytes into a region of size 2" } */
T (a6, b6, S4, 5, 4); // { dg-warning "writing 4 bytes into a region of size 1" } */
T (a6, b6, S4, 6, 4); // { dg-warning "writing 4 bytes into a region of size 0" } */
T (a7, b7, S4, 0, 4);
T (a7, b7, S4, 1, 4);
T (a7, b7, S4, 2, 4);
T (a7, b7, S4, 3, 4);
T (a7, b7, S4, 4, 4); // { dg-warning "writing 4 bytes into a region of size 3" } */
T (a7, b7, S4, 5, 4); // { dg-warning "writing 4 bytes into a region of size 2" } */
T (a7, b7, S4, 6, 4); // { dg-warning "writing 4 bytes into a region of size 1" } */
T (a7, b7, S4, 7, 4); // { dg-warning "writing 4 bytes into a region of size 0" } */
T (a8, b4, S3, 0, 4);
T (a8, b4, S3, 1, 4);
T (a8, b4, S3, 2, 4);
T (a8, b4, S3, 3, 4);
T (a8, b4, S3, 4, 4);
T (a8, b4, S3, 5, 4); // { dg-warning "writing 4 bytes into a region of size 3" } */
T (a8, b4, S3, 6, 4); // { dg-warning "writing 4 bytes into a region of size 2" } */
T (a8, b4, S3, 7, 4); // { dg-warning "writing 4 bytes into a region of size 1" } */
T (a8, b4, S3, 8, 4); // { dg-warning "writing 4 bytes into a region of size 0" } */
T (a8, b8, S3, 0, 4);
T (a8, b8, S3, 1, 4);
T (a8, b8, S3, 2, 4);
T (a8, b8, S3, 3, 4);
T (a8, b8, S3, 4, 4);
T (a8, b8, S3, 5, 4); // { dg-warning "writing 4 bytes into a region of size 3" } */
T (a8, b8, S3, 6, 4); // { dg-warning "writing 4 bytes into a region of size 2" } */
T (a8, b8, S3, 7, 4); // { dg-warning "writing 4 bytes into a region of size 1" } */
T (a8, b8, S3, 8, 4); // { dg-warning "writing 4 bytes into a region of size 0" } */
T (a8, b8, S4, 0, 4);
T (a8, b8, S4, 1, 4);
T (a8, b8, S4, 2, 4);
T (a8, b8, S4, 3, 4);
T (a8, b8, S4, 4, 4);
T (a8, b8, S4, 5, 4); // { dg-warning "writing 4 bytes into a region of size 3" } */
T (a8, b8, S4, 6, 4); // { dg-warning "writing 4 bytes into a region of size 2" } */
T (a8, b8, S4, 7, 4); // { dg-warning "writing 4 bytes into a region of size 1" } */
T (a8, b8, S4, 8, 4); // { dg-warning "writing 4 bytes into a region of size 0" } */
T (a8, b8, S4, 0, 5);
T (a8, b8, S4, 1, 5);
T (a8, b8, S4, 2, 5);
T (a8, b8, S4, 3, 5);
T (a8, b8, S4, 4, 5); // { dg-warning "writing 5 bytes into a region of size 4" } */
T (a8, b8, S4, 5, 5); // { dg-warning "writing 5 bytes into a region of size 3" } */
T (a8, b8, S4, 6, 5); // { dg-warning "writing 5 bytes into a region of size 2" } */
T (a8, b8, S4, 7, 5); // { dg-warning "writing 5 bytes into a region of size 1" } */
T (a8, b8, S4, 8, 5); // { dg-warning "writing 5 bytes into a region of size 0" } */
T (a8, b8, S4, 0, 6);
T (a8, b8, S4, 1, 6);
T (a8, b8, S4, 2, 6);
T (a8, b8, S4, 3, 6); // { dg-warning "writing 6 bytes into a region of size 5" } */
T (a8, b8, S4, 4, 6); // { dg-warning "writing 6 bytes into a region of size 4" } */
T (a8, b8, S4, 5, 6); // { dg-warning "writing 6 bytes into a region of size 3" } */
T (a8, b8, S4, 6, 6); // { dg-warning "writing 6 bytes into a region of size 2" } */
T (a8, b8, S4, 7, 6); // { dg-warning "writing 6 bytes into a region of size 1" } */
T (a8, b8, S4, 8, 6); // { dg-warning "writing 6 bytes into a region of size 0" } */
#undef T
#define T(dst, init, off, n) \
NOIPA void CAT (test_on_line_, __LINE__) (char *src) \
{ \
__builtin_strcpy (src, init); \
char *d = dst + off; \
__builtin_memcpy (d, src, n); \
} typedef void dummy_type
T (a6, S4, 0, 4);
T (a6, S4, 1, 4);
T (a6, S4, 2, 4);
T (a6, S4, 3, 4); // { dg-warning "writing 4 bytes into a region of size 3" } */
T (a6, S4, 4, 4); // { dg-warning "writing 4 bytes into a region of size 2" } */
T (a6, S4, 5, 4); // { dg-warning "writing 4 bytes into a region of size 1" } */
T (a6, S4, 6, 4); // { dg-warning "writing 4 bytes into a region of size 0" } */
T (a7, S4, 0, 4);
T (a7, S4, 1, 4);
T (a7, S4, 2, 4);
T (a7, S4, 3, 4);
T (a7, S4, 4, 4); // { dg-warning "writing 4 bytes into a region of size 3" } */
T (a7, S4, 5, 4); // { dg-warning "writing 4 bytes into a region of size 2" } */
T (a7, S4, 6, 4); // { dg-warning "writing 4 bytes into a region of size 1" } */
T (a7, S4, 7, 4); // { dg-warning "writing 4 bytes into a region of size 0" } */
T (a8, S3, 0, 4);
T (a8, S3, 1, 4);
T (a8, S3, 2, 4);
T (a8, S3, 3, 4);
T (a8, S3, 4, 4);
T (a8, S3, 5, 4); // { dg-warning "writing 4 bytes into a region of size 3" } */
T (a8, S3, 6, 4); // { dg-warning "writing 4 bytes into a region of size 2" } */
T (a8, S3, 7, 4); // { dg-warning "writing 4 bytes into a region of size 1" } */
T (a8, S3, 8, 4); // { dg-warning "writing 4 bytes into a region of size 0" } */
...@@ -3801,23 +3801,26 @@ count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset, ...@@ -3801,23 +3801,26 @@ count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset,
tree type = TREE_TYPE (exp); tree type = TREE_TYPE (exp);
if (TREE_CODE (type) == INTEGER_TYPE if (TREE_CODE (type) == INTEGER_TYPE
&& TYPE_MODE (type) == TYPE_MODE (char_type_node) && TYPE_MODE (type) == TYPE_MODE (char_type_node)
&& TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node)) && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node)
{ && tree_expr_nonzero_p (exp))
/* Determine if the character EXP is known to be non-zero {
(even if its exact value is not known) and if so, recurse /* If the character EXP is known to be non-zero (even if its
once to set the range, etc. */ exact value is not known) recurse once to set the range
if (tree_expr_nonzero_p (exp)) for an arbitrary constant. */
return count_nonzero_bytes (build_int_cst (type, 1), exp = build_int_cst (type, 1);
offset, nbytes, lenrange, return count_nonzero_bytes (exp, offset, 1, lenrange,
nulterm, allnul, allnonnul, snlim); nulterm, allnul, allnonnul, snlim);
/* Don't know whether EXP is or isn't nonzero. */
return false;
} }
gimple *stmt = SSA_NAME_DEF_STMT (exp); gimple *stmt = SSA_NAME_DEF_STMT (exp);
if (gimple_code (stmt) != GIMPLE_PHI) if (gimple_assign_single_p (stmt))
{
exp = gimple_assign_rhs1 (stmt);
if (TREE_CODE (exp) != MEM_REF)
return false; return false;
}
else if (gimple_code (stmt) == GIMPLE_PHI)
{
/* Avoid processing an SSA_NAME that has already been visited /* Avoid processing an SSA_NAME that has already been visited
or if an SSA_NAME limit has been reached. Indicate success or if an SSA_NAME limit has been reached. Indicate success
if the former and failure if the latter. */ if the former and failure if the latter. */
...@@ -3836,6 +3839,7 @@ count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset, ...@@ -3836,6 +3839,7 @@ count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset,
return true; return true;
} }
}
if (TREE_CODE (exp) == MEM_REF) if (TREE_CODE (exp) == MEM_REF)
{ {
...@@ -3897,14 +3901,25 @@ count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset, ...@@ -3897,14 +3901,25 @@ count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset,
prep = reinterpret_cast <char *>(buf); prep = reinterpret_cast <char *>(buf);
/* Try to extract the representation of the constant object /* Try to extract the representation of the constant object
or expression starting from the offset. */ or expression starting from the offset. */
nbytes = native_encode_expr (exp, buf, sizeof buf, offset); unsigned repsize = native_encode_expr (exp, buf, sizeof buf, offset);
if (repsize < nbytes)
{
/* This should only happen when REPSIZE is zero because EXP
doesn't denote an object with a known initializer, except
perhaps when the reference reads past its end. */
lenrange[0] = 0;
prep = NULL;
}
else
nbytes = repsize;
}
if (!nbytes) if (!nbytes)
return false; return false;
}
/* Compute the number of leading nonzero bytes in the representation /* Compute the number of leading nonzero bytes in the representation
and update the minimum and maximum. */ and update the minimum and maximum. */
unsigned n = strnlen (prep, nbytes); unsigned n = prep ? strnlen (prep, nbytes) : nbytes;
if (n < lenrange[0]) if (n < lenrange[0])
lenrange[0] = n; lenrange[0] = n;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment