Commit 213694e5 by Martin Sebor Committed by Martin Sebor

PR tree-optimization/88800 - Spurious -Werror=array-bounds for non-taken branch

gcc/ChangeLog:

	PR tree-optimization/88800
	* gimple-fold.c (gimple_fold_builtin_memory_op): Avoid checking
	NO_WARNING bit here.  Avoid folding out-of-bounds calls.
	* gimple-ssa-warn-restrict.c (maybe_diag_offset_bounds): Remove
	redundant argument.  Add new argument and issue diagnostics under
	its control.  Detect out-of-bounds access even with warnings
	disabled.
	(check_bounds_or_overlap): Change return type.  Add argument.
	(wrestrict_dom_walker::check_call): Adjust.
	* gimple-ssa-warn-restrict.h (check_bounds_or_overlap): Add argument.
	* tree-ssa-strlen.c (handle_builtin_strcpy): Adjust to change in
	check_bounds_or_overlap's return value.
	(handle_builtin_stxncpy): Same.
	(handle_builtin_strcat): Same.

gcc/testsuite/ChangeLog:

	PR tree-optimization/88800
	* c-c++-common/Wrestrict.c: Adjust.
	* gcc.dg/Warray-bounds-37.c: New test.
	* gcc.dg/builtin-memcpy-2.c: New test.
	* gcc.dg/builtin-memcpy.c: New test.

From-SVN: r268037
parent 16d46c7b
2019-01-17 Martin Sebor <msebor@redhat.com>
PR tree-optimization/88800
* gimple-fold.c (gimple_fold_builtin_memory_op): Avoid checking
NO_WARNING bit here. Avoid folding out-of-bounds calls.
* gimple-ssa-warn-restrict.c (maybe_diag_offset_bounds): Remove
redundant argument. Add new argument and issue diagnostics under
its control. Detect out-of-bounds access even with warnings
disabled.
(check_bounds_or_overlap): Change return type. Add argument.
(wrestrict_dom_walker::check_call): Adjust.
* gimple-ssa-warn-restrict.h (check_bounds_or_overlap): Add argument.
* tree-ssa-strlen.c (handle_builtin_strcpy): Adjust to change in
check_bounds_or_overlap's return value.
(handle_builtin_stxncpy): Same.
(handle_builtin_strcat): Same.
2019-01-17 Andrew Stubbs <ams@codesourcery.com>
Kwok Cheung Yeung <kcy@codesourcery.com>
Julian Brown <julian@codesourcery.com>
......
......@@ -697,8 +697,6 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
tree destvar, srcvar;
location_t loc = gimple_location (stmt);
bool nowarn = gimple_no_warning_p (stmt);
/* If the LEN parameter is a constant zero or in range where
the only valid value is zero, return DEST. */
if (size_must_be_zero_p (len))
......@@ -766,12 +764,16 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
unsigned ilen = tree_to_uhwi (len);
if (pow2p_hwi (ilen))
{
/* Detect invalid bounds and overlapping copies and issue
either -Warray-bounds or -Wrestrict. */
if (!nowarn
&& check_bounds_or_overlap (as_a <gcall *>(stmt),
dest, src, len, len))
gimple_set_no_warning (stmt, true);
/* Detect out-of-bounds accesses without issuing warnings.
Avoid folding out-of-bounds copies but to avoid false
positives for unreachable code defer warning until after
DCE has worked its magic.
-Wrestrict is still diagnosed. */
if (int warning = check_bounds_or_overlap (as_a <gcall *>(stmt),
dest, src, len, len,
false, false))
if (warning != OPT_Wrestrict)
return false;
scalar_int_mode mode;
tree type = lang_hooks.types.type_for_size (ilen * 8, 1);
......@@ -1038,10 +1040,16 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
}
}
/* Detect invalid bounds and overlapping copies and issue either
-Warray-bounds or -Wrestrict. */
if (!nowarn)
check_bounds_or_overlap (as_a <gcall *>(stmt), dest, src, len, len);
/* Same as above, detect out-of-bounds accesses without issuing
warnings. Avoid folding out-of-bounds copies but to avoid
false positives for unreachable code defer warning until
after DCE has worked its magic.
-Wrestrict is still diagnosed. */
if (int warning = check_bounds_or_overlap (as_a <gcall *>(stmt),
dest, src, len, len,
false, false))
if (warning != OPT_Wrestrict)
return false;
gimple *new_stmt;
if (is_gimple_reg_type (TREE_TYPE (srcvar)))
......
......@@ -1329,6 +1329,9 @@ maybe_diag_overlap (location_t loc, gimple *call, builtin_access &acs)
if (!acs.overlap ())
return false;
if (gimple_no_warning_p (call))
return true;
/* For convenience. */
const builtin_memref &dstref = *acs.dstref;
const builtin_memref &srcref = *acs.srcref;
......@@ -1568,7 +1571,7 @@ maybe_diag_overlap (location_t loc, gimple *call, builtin_access &acs)
return true;
}
/* Validate REF offsets in an EXPRession passed as an argument to a CALL
/* Validate REF offsets in an expression passed as an argument to a CALL
to a built-in function FUNC to make sure they are within the bounds
of the referenced object if its size is known, or PTRDIFF_MAX otherwise.
Both initial values of the offsets and their final value computed by
......@@ -1578,21 +1581,27 @@ maybe_diag_overlap (location_t loc, gimple *call, builtin_access &acs)
static bool
maybe_diag_offset_bounds (location_t loc, gimple *call, tree func, int strict,
tree expr, const builtin_memref &ref)
const builtin_memref &ref, bool do_warn)
{
if (!warn_array_bounds)
/* Check for out-bounds pointers regardless of warning options since
the result is used to make codegen decisions. */
offset_int ooboff[] = { ref.offrange[0], ref.offrange[1] };
tree oobref = ref.offset_out_of_bounds (strict, ooboff);
if (!oobref)
return false;
if (ref.ref && TREE_NO_WARNING (ref.ref))
/* Return true without issuing a warning. */
if (!do_warn)
return true;
if (!warn_array_bounds)
return false;
offset_int ooboff[] = { ref.offrange[0], ref.offrange[1] };
tree oobref = ref.offset_out_of_bounds (strict, ooboff);
if (!oobref)
if (ref.ref && TREE_NO_WARNING (ref.ref))
return false;
if (EXPR_HAS_LOCATION (expr))
loc = EXPR_LOCATION (expr);
if (EXPR_HAS_LOCATION (ref.ptr))
loc = EXPR_LOCATION (ref.ptr);
loc = expansion_point_location_if_in_system_header (loc);
......@@ -1811,7 +1820,7 @@ wrestrict_dom_walker::check_call (gimple *call)
|| (dstwr && !INTEGRAL_TYPE_P (TREE_TYPE (dstwr))))
return;
if (check_bounds_or_overlap (call, dst, src, dstwr, NULL_TREE))
if (!check_bounds_or_overlap (call, dst, src, dstwr, NULL_TREE))
return;
/* Avoid diagnosing the call again. */
......@@ -1823,12 +1832,14 @@ wrestrict_dom_walker::check_call (gimple *call)
/* Attempt to detect and diagnose invalid offset bounds and (except for
memmove) overlapping copy in a call expression EXPR from SRC to DST
and DSTSIZE and SRCSIZE bytes, respectively. Both DSTSIZE and
SRCSIZE may be NULL. Return false when one or the other has been
detected and diagnosed, true otherwise. */
SRCSIZE may be NULL. DO_WARN is false to detect either problem
without issue a warning. Return the OPT_Wxxx constant corresponding
to the warning if one has been detected and zero otherwise. */
bool
int
check_bounds_or_overlap (gimple *call, tree dst, tree src, tree dstsize,
tree srcsize, bool bounds_only /* = false */)
tree srcsize, bool bounds_only /* = false */,
bool do_warn /* = true */)
{
location_t loc = gimple_nonartificial_location (call);
loc = expansion_point_location_if_in_system_header (loc);
......@@ -1847,11 +1858,12 @@ check_bounds_or_overlap (gimple *call, tree dst, tree src, tree dstsize,
/* Validate offsets first to make sure they are within the bounds
of the destination object if its size is known, or PTRDIFF_MAX
otherwise. */
if (maybe_diag_offset_bounds (loc, call, func, strict, dst, dstref)
|| maybe_diag_offset_bounds (loc, call, func, strict, src, srcref))
if (maybe_diag_offset_bounds (loc, call, func, strict, dstref, do_warn)
|| maybe_diag_offset_bounds (loc, call, func, strict, srcref, do_warn))
{
gimple_set_no_warning (call, true);
return false;
if (do_warn)
gimple_set_no_warning (call, true);
return OPT_Warray_bounds;
}
bool check_overlap
......@@ -1861,7 +1873,7 @@ check_bounds_or_overlap (gimple *call, tree dst, tree src, tree dstsize,
&& DECL_FUNCTION_CODE (func) != BUILT_IN_MEMMOVE_CHK)));
if (!check_overlap)
return true;
return 0;
if (operand_equal_p (dst, src, 0))
{
......@@ -1875,20 +1887,20 @@ check_bounds_or_overlap (gimple *call, tree dst, tree src, tree dstsize,
"%G%qD source argument is the same as destination",
call, func);
gimple_set_no_warning (call, true);
return false;
return OPT_Wrestrict;
}
return true;
return 0;
}
/* Return false when overlap has been detected. */
if (maybe_diag_overlap (loc, call, acs))
{
gimple_set_no_warning (call, true);
return false;
return OPT_Wrestrict;
}
return true;
return 0;
}
gimple_opt_pass *
......
......@@ -20,7 +20,7 @@
#ifndef GIMPLE_SSA_WARN_RESTRICT_H
extern bool check_bounds_or_overlap (gimple *, tree, tree, tree, tree,
bool = false);
extern int check_bounds_or_overlap (gimple *, tree, tree, tree, tree,
bool = false, bool = true);
#endif /* GIMPLE_SSA_WARN_RESTRICT_H */
2019-01-17 Martin Sebor <msebor@redhat.com>
PR tree-optimization/88800
* c-c++-common/Wrestrict.c: Adjust.
* gcc.dg/Warray-bounds-37.c: New test.
* gcc.dg/builtin-memcpy-2.c: New test.
* gcc.dg/builtin-memcpy.c: New test.
2019-01-17 Tamar Christina <tamar.christina@arm.com>
PR target/88850
......
......@@ -636,7 +636,7 @@ void test_strcpy_cst (ptrdiff_t i)
T ("012", a, a + 3);
/* The following doesn't overlap but it should trigger -Wstringop-overflow
for reading past the end. */
T ("012", a, a + sizeof a);
T ("012", a, a + sizeof a); /* { dg-warning "\\\[-Wstringop-overflow" "pr81437" { xfail *-*-* } } */
/* The terminating nul written to d[2] overwrites s[0]. */
T ("0123", a, a + 2); /* { dg-warning "accessing 3 bytes at offsets 0 and 2 overlaps 1 byte at offset 2" } */
......@@ -651,9 +651,9 @@ void test_strcpy_cst (ptrdiff_t i)
T ("012", a + 2, a); /* { dg-warning "accessing 4 bytes at offsets 2 and 0 overlaps 2 bytes at offset 2" "strcpy" } */
T ("012", a + 3, a); /* { dg-warning "accessing 4 bytes at offsets 3 and 0 overlaps 1 byte at offset 3" "strcpy" } */
T ("012", a + 4, a);
/* The following doesn't overlap but it should trigger -Wstrinop-ovewrflow
/* The following doesn't overlap but it triggers -Wstringop-overflow
for writing past the end. */
T ("012", a + sizeof a, a);
T ("012", a + sizeof a, a); /* { dg-warning "\\\[-Wstringop-overflow" } */
}
/* Exercise strcpy with constant or known arguments offset by a range.
......
/* PR tree-optimization/88800 - Spurious -Werror=array-bounds for non-taken
branch
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
extern void* memmove (void*, const void*, __SIZE_TYPE__);
struct A
{
const char *s;
int n;
};
void f (void*);
struct B
{
char d[5];
int n;
};
__attribute__ ((always_inline)) inline void
g (struct B *p, struct A a)
{
int i = a.n;
if (i <= 5)
p->n = i;
else {
p->n = -1;
f (p);
}
if (p->n >= 0)
memmove (p->d, a.s, a.n); /* { dg-bogus "\\\[-Warray-bounds" } */
}
void h (void)
{
char c[8] = "";
struct A a;
a.s = c;
a.n = 8;
struct B b;
g (&b, a);
}
/* PR tree-optimization/88800 - Spurious -Werror=array-bounds for non-taken
branch
Verify that out-of-bounds memcpy calls are not folded even when
warnings are disabled.
{ dg-do compile }
{ dg-options "-O2 -w -fdump-tree-optimized" } */
extern void* memcpy (void*, const void*, __SIZE_TYPE__);
char a1[1], a2[2], a4[4], a8[8], a16[16], a32[32];
void f1 (const void *p)
{
memcpy (a1, p, sizeof a1 * 2);
}
void f2 (const void *p)
{
memcpy (a2, p, sizeof a2 * 2);
}
void f4 (const void *p)
{
memcpy (a4, p, sizeof a4 * 2);
}
void f8 (const void *p)
{
memcpy (a8, p, sizeof a8 * 2);
}
void f16 (const void *p)
{
memcpy (a16, p, sizeof a16 * 2);
}
void f32 (const void *p)
{
memcpy (a32, p, sizeof a32 * 2);
}
/* { dg-final { scan-tree-dump-times "memcpy" 6 "optimized" } } */
/* PR tree-optimization/88800 - Spurious -Werror=array-bounds for non-taken
branch
Verify that out-of-bounds memcpy calls are not folded when warnings are
enabled (builtin-memcpy-2.c verifies they're not folded with warnings
disabled).
{ dg-do compile }
{ dg-options "-O2 -Wall -fdump-tree-optimized" } */
extern void* memcpy (void*, const void*, __SIZE_TYPE__);
char a1[1], a2[2], a4[4], a8[8], a16[16], a32[32];
void f1 (const void *p)
{
memcpy (a1, p, sizeof a1 * 2); /* { dg-warning "\\\[-Warray-bounds" } */
}
void f2 (const void *p)
{
memcpy (a2, p, sizeof a2 * 2); /* { dg-warning "\\\[-Warray-bounds" } */
}
void f4 (const void *p)
{
memcpy (a4, p, sizeof a4 * 2); /* { dg-warning "\\\[-Warray-bounds" } */
}
void f8 (const void *p)
{
memcpy (a8, p, sizeof a8 * 2); /* { dg-warning "\\\[-Warray-bounds" } */
}
void f16 (const void *p)
{
memcpy (a16, p, sizeof a16 * 2); /* { dg-warning "\\\[-Warray-bounds" } */
}
void f32 (const void *p)
{
memcpy (a32, p, sizeof a32 * 2); /* { dg-warning "\\\[-Warray-bounds" } */
}
/* { dg-final { scan-tree-dump-times "memcpy" 6 "optimized" } } */
......@@ -1742,7 +1742,7 @@ handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
if (const strinfo *chksi = olddsi ? olddsi : dsi)
if (si
&& !check_bounds_or_overlap (stmt, chksi->ptr, si->ptr, NULL_TREE, len))
&& check_bounds_or_overlap (stmt, chksi->ptr, si->ptr, NULL_TREE, len))
{
gimple_set_no_warning (stmt, true);
set_no_warning = true;
......@@ -2214,7 +2214,7 @@ handle_builtin_stxncpy (built_in_function, gimple_stmt_iterator *gsi)
else
srcsize = NULL_TREE;
if (!check_bounds_or_overlap (stmt, dst, src, dstsize, srcsize))
if (check_bounds_or_overlap (stmt, dst, src, dstsize, srcsize))
{
gimple_set_no_warning (stmt, true);
return;
......@@ -2512,7 +2512,7 @@ handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
tree sptr = si && si->ptr ? si->ptr : src;
if (!check_bounds_or_overlap (stmt, dst, sptr, NULL_TREE, slen))
if (check_bounds_or_overlap (stmt, dst, sptr, NULL_TREE, slen))
{
gimple_set_no_warning (stmt, true);
set_no_warning = true;
......@@ -2622,7 +2622,7 @@ handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
tree sptr = si && si->ptr ? si->ptr : src;
if (!check_bounds_or_overlap (stmt, dst, sptr, dstlen, srcsize))
if (check_bounds_or_overlap (stmt, dst, sptr, dstlen, srcsize))
{
gimple_set_no_warning (stmt, true);
set_no_warning = true;
......
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