diff options
author | Jakub Jelinek <jakub@redhat.com> | 2019-02-26 21:36:29 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2019-02-26 21:36:29 +0100 |
commit | 9bc83f27a703bd7d2393638e0ef93f506ac8bb03 (patch) | |
tree | 7312fc231be96058723ceb7b696e739b968d5eda | |
parent | 3d7beb79e0631c7ca8532c497295af03822eeed2 (diff) | |
download | gcc-9bc83f27a703bd7d2393638e0ef93f506ac8bb03.zip gcc-9bc83f27a703bd7d2393638e0ef93f506ac8bb03.tar.gz gcc-9bc83f27a703bd7d2393638e0ef93f506ac8bb03.tar.bz2 |
re PR tree-optimization/89500 (ICE: tree check: expected integer_cst, have ssa_name in get_len, at tree.h:5653)
PR tree-optimization/89500
* tree-ssa-strlen.c (stridx_strlenloc): Adjust comment.
(handle_builtin_strlen): Remove noncst_bound variable. Always
optimize strnlen (x, 0) to 0. Optimize strnlen (x, cst) to
cst if the first cst bytes starting at x are known to be non-zero,
even if the string is not zero terminated. Don't try to modify
*si for strnlen. Update strlen_to_stridx only for strlen or if
we can prove strnlen returns the same value as strlen would.
* gcc.dg/pr89500.c: New test.
* gcc.dg/Wstringop-overflow-10.c: New test.
* gcc.dg/strlenopt-60.c: New test.
From-SVN: r269230
-rw-r--r-- | gcc/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wstringop-overflow-10.c | 34 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr89500.c | 17 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/strlenopt-60.c | 58 | ||||
-rw-r--r-- | gcc/tree-ssa-strlen.c | 48 |
6 files changed, 155 insertions, 20 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8c07ccf..b7404cc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2019-02-26 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/89500 + * tree-ssa-strlen.c (stridx_strlenloc): Adjust comment. + (handle_builtin_strlen): Remove noncst_bound variable. Always + optimize strnlen (x, 0) to 0. Optimize strnlen (x, cst) to + cst if the first cst bytes starting at x are known to be non-zero, + even if the string is not zero terminated. Don't try to modify + *si for strnlen. Update strlen_to_stridx only for strlen or if + we can prove strnlen returns the same value as strlen would. + 2019-02-26 Martin Liska <mliska@suse.cz> * alloc-pool.h (struct pool_usage): Remove extra diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c041ed6..6e3c5f7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2019-02-26 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/89500 + * gcc.dg/pr89500.c: New test. + * gcc.dg/Wstringop-overflow-10.c: New test. + * gcc.dg/strlenopt-60.c: New test. + 2019-02-26 Harald Anlauf <anlauf@gmx.de> PR fortran/89492 diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-10.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-10.c new file mode 100644 index 0000000..2e22130 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-10.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -Wstringop-overflow" } */ + +void +foo (char *a) +{ + char b[16] = "abcdefg"; + __builtin_strncpy (a, b, __builtin_strlen (b)); /* { dg-warning "specified bound depends on the length of the source argument" } */ +} + +void +bar (char *a) +{ + char b[16] = "abcdefg"; + __builtin_strncpy (a, b, __builtin_strnlen (b, 8)); /* { dg-warning "specified bound depends on the length of the source argument" } */ +} + +void +baz (char *a) +{ + char b[16] = "abcdefg"; + __builtin_strncpy (a, b, __builtin_strnlen (b, 7)); /* { dg-bogus "specified bound depends on the length of the source argument" } */ +} + +void fill (char *); + +void +qux (char *a) +{ + char b[16]; + fill (b); + __builtin_memcpy (b, "abcdefg", 7); + __builtin_strncpy (a, b, __builtin_strnlen (b, 8)); /* { dg-bogus "specified bound depends on the length of the source argument" } */ +} diff --git a/gcc/testsuite/gcc.dg/pr89500.c b/gcc/testsuite/gcc.dg/pr89500.c new file mode 100644 index 0000000..db7c27b --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr89500.c @@ -0,0 +1,17 @@ +/* PR tree-optimization/89500 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +typedef __SIZE_TYPE__ size_t; +extern size_t strlen (const char *); +extern size_t strnlen (const char *, size_t); +extern void bar (char *); + +void +foo (int *a) +{ + char c[64]; + bar (c); + a[0] = strlen (c); + a[1] = strnlen (c, 0); +} diff --git a/gcc/testsuite/gcc.dg/strlenopt-60.c b/gcc/testsuite/gcc.dg/strlenopt-60.c new file mode 100644 index 0000000..a581136 --- /dev/null +++ b/gcc/testsuite/gcc.dg/strlenopt-60.c @@ -0,0 +1,58 @@ +/* PR tree-optimization/89500 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-times "return 10;" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "return 5;" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "return 0;" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "strnlen " 1 "optimized" } } */ + +#include "strlenopt.h" + +void foo (char *); + +size_t +f1 (void) +{ + char a[10] = "0123456789"; + return strnlen (a, 10); +} + +size_t +f2 (void) +{ + char a[10] = "0123456789"; + return strnlen (a, 5); +} + +size_t +f3 (void) +{ + char a[10] = "0123456789"; + return strnlen (a, 0); +} + +size_t +f4 (void) +{ + char a[20]; + foo (a); + memcpy (a, "0123456789", 10); + return strnlen (a, 10); +} + +size_t +f5 (void) +{ + char a[20]; + foo (a); + memcpy (a, "0123456789", 10); + return strnlen (a, 14); +} + +size_t +f6 (void) +{ + char a[20]; + foo (a); + return strnlen (a, 0); +} diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c index df56970..721832e 100644 --- a/gcc/tree-ssa-strlen.c +++ b/gcc/tree-ssa-strlen.c @@ -156,7 +156,8 @@ struct decl_stridxlist_map mappings. */ static hash_map<tree_decl_hash, stridxlist> *decl_to_stridxlist_htab; -/* Hash table mapping strlen calls to stridx instances describing +/* Hash table mapping strlen (or strnlen with constant bound and return + smaller than bound) calls to stridx instances describing the calls' arguments. Non-null only when warn_stringop_truncation is non-zero. */ typedef std::pair<int, location_t> stridx_strlenloc; @@ -1269,19 +1270,33 @@ handle_builtin_strlen (gimple_stmt_iterator *gsi) tree bound = (DECL_FUNCTION_CODE (callee) == BUILT_IN_STRNLEN ? gimple_call_arg (stmt, 1) : NULL_TREE); int idx = get_stridx (src); - if (idx) + if (idx || (bound && integer_zerop (bound))) { strinfo *si = NULL; tree rhs; if (idx < 0) rhs = build_int_cst (TREE_TYPE (lhs), ~idx); + else if (idx == 0) + rhs = bound; else { rhs = NULL_TREE; si = get_strinfo (idx); if (si != NULL) - rhs = get_string_length (si); + { + rhs = get_string_length (si); + /* For strnlen, if bound is constant, even if si is not known + to be zero terminated, if we know at least bound bytes are + not zero, the return value will be bound. */ + if (rhs == NULL_TREE + && bound != NULL_TREE + && TREE_CODE (bound) == INTEGER_CST + && si->nonzero_chars != NULL_TREE + && TREE_CODE (si->nonzero_chars) == INTEGER_CST + && tree_int_cst_le (bound, si->nonzero_chars)) + rhs = bound; + } } if (rhs != NULL_TREE) { @@ -1294,18 +1309,8 @@ handle_builtin_strlen (gimple_stmt_iterator *gsi) if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs))) rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs); - /* Set for strnlen() calls with a non-constant bound. */ - bool noncst_bound = false; if (bound) - { - tree new_rhs - = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (rhs), rhs, bound); - - noncst_bound = (TREE_CODE (new_rhs) != INTEGER_CST - || tree_int_cst_lt (new_rhs, rhs)); - - rhs = new_rhs; - } + rhs = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (rhs), rhs, bound); if (!update_call_from_tree (gsi, rhs)) gimplify_and_update_call_from_tree (gsi, rhs); @@ -1317,12 +1322,9 @@ handle_builtin_strlen (gimple_stmt_iterator *gsi) print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); } - /* Avoid storing the length for calls to strnlen() with - a non-constant bound. */ - if (noncst_bound) - return; - if (si != NULL + /* Don't update anything for strnlen. */ + && bound == NULL_TREE && TREE_CODE (si->nonzero_chars) != SSA_NAME && TREE_CODE (si->nonzero_chars) != INTEGER_CST && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)) @@ -1332,7 +1334,13 @@ handle_builtin_strlen (gimple_stmt_iterator *gsi) gcc_assert (si->full_string_p); } - if (strlen_to_stridx) + if (strlen_to_stridx + && (bound == NULL_TREE + /* For strnlen record this only if the call is proven + to return the same value as strlen would. */ + || (TREE_CODE (bound) == INTEGER_CST + && TREE_CODE (rhs) == INTEGER_CST + && tree_int_cst_lt (rhs, bound)))) strlen_to_stridx->put (lhs, stridx_strlenloc (idx, loc)); return; |