From: Martin Sebor Date: Thu, 17 Jan 2019 16:33:55 +0000 (+0000) Subject: PR tree-optimization/88800 - Spurious -Werror=array-bounds for non-taken branch X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=213694e56e6265044bc85dbf43bda9028f05dba7;p=gcc.git 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1ca3a271a9a..9089aa1922b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2019-01-17 Martin Sebor + + 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 Kwok Cheung Yeung Julian Brown diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 2d25f9eec5f..500e551996a 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -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 (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 (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 (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 (stmt), + dest, src, len, len, + false, false)) + if (warning != OPT_Wrestrict) + return false; gimple *new_stmt; if (is_gimple_reg_type (TREE_TYPE (srcvar))) diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c index 6eb393dc8e1..42c87190dd8 100644 --- a/gcc/gimple-ssa-warn-restrict.c +++ b/gcc/gimple-ssa-warn-restrict.c @@ -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 * diff --git a/gcc/gimple-ssa-warn-restrict.h b/gcc/gimple-ssa-warn-restrict.h index 167d5843039..47835de84c6 100644 --- a/gcc/gimple-ssa-warn-restrict.h +++ b/gcc/gimple-ssa-warn-restrict.h @@ -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 */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 103a0f73bc7..31b171b628b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2019-01-17 Martin Sebor + + 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 PR target/88850 diff --git a/gcc/testsuite/c-c++-common/Wrestrict.c b/gcc/testsuite/c-c++-common/Wrestrict.c index efd72efd320..d0e3c3411fe 100644 --- a/gcc/testsuite/c-c++-common/Wrestrict.c +++ b/gcc/testsuite/c-c++-common/Wrestrict.c @@ -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. diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-37.c b/gcc/testsuite/gcc.dg/Warray-bounds-37.c new file mode 100644 index 00000000000..57d218a4fc6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-37.c @@ -0,0 +1,47 @@ +/* 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); +} diff --git a/gcc/testsuite/gcc.dg/builtin-memcpy-2.c b/gcc/testsuite/gcc.dg/builtin-memcpy-2.c new file mode 100644 index 00000000000..bddff935fc4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-memcpy-2.c @@ -0,0 +1,42 @@ +/* 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" } } */ diff --git a/gcc/testsuite/gcc.dg/builtin-memcpy.c b/gcc/testsuite/gcc.dg/builtin-memcpy.c new file mode 100644 index 00000000000..85e25396f56 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-memcpy.c @@ -0,0 +1,43 @@ +/* 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" } } */ diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c index 02ed1b4c777..df569708309 100644 --- a/gcc/tree-ssa-strlen.c +++ b/gcc/tree-ssa-strlen.c @@ -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;