diff options
author | Martin Sebor <msebor@redhat.com> | 2019-10-28 23:53:08 +0000 |
---|---|---|
committer | Martin Sebor <msebor@gcc.gnu.org> | 2019-10-28 17:53:08 -0600 |
commit | efe646c468656959236de0fbe2224561873fb189 (patch) | |
tree | dbf3a51d2e92be9f3a8a1d7b0358423b3a5b815a /gcc | |
parent | 02c4de7631a177ea44149332aa1294a60ed9adad (diff) | |
download | gcc-efe646c468656959236de0fbe2224561873fb189.zip gcc-efe646c468656959236de0fbe2224561873fb189.tar.gz gcc-efe646c468656959236de0fbe2224561873fb189.tar.bz2 |
tree-ssa-strlen.c (get_addr_stridx): Add argument and use it.
gcc/ChangeLog:
* tree-ssa-strlen.c (get_addr_stridx): Add argument and use it.
(handle_store): Pass argument to get_addr_stridx.
gcc/testsuite/ChangeLog:
* gcc.dg/strlenopt-89.c: New test.
* gcc.dg/strlenopt-90.c: New test.
* gcc.dg/Wstringop-overflow-20.c: New test.
From-SVN: r277546
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wstringop-overflow-20.c | 40 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/strlenopt-89.c | 89 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/strlenopt-90.c | 83 | ||||
-rw-r--r-- | gcc/tree-ssa-strlen.c | 7 |
6 files changed, 227 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3f4f2dc..8b8a6c6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,10 @@ 2019-10-28 Martin Sebor <msebor@redhat.com> + * tree-ssa-strlen.c (get_addr_stridx): Add argument and use it. + (handle_store): Pass argument to get_addr_stridx. + +2019-10-28 Martin Sebor <msebor@redhat.com> + PR tree-optimization/92226 * tree-ssa-strlen.c (compare_nonzero_chars): Return -1 also when the offset is in the open range outlined by SI's length. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8f9859f..a3ef286 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,11 @@ 2019-10-28 Martin Sebor <msebor@redhat.com> + * gcc.dg/strlenopt-89.c: New test. + * gcc.dg/strlenopt-90.c: New test. + * gcc.dg/Wstringop-overflow-20.c: New test. + +2019-10-28 Martin Sebor <msebor@redhat.com> + PR tree-optimization/92226 * gcc.dg/strlenopt-88.c: New test. diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-20.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-20.c new file mode 100644 index 0000000..4a6fe8e --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-20.c @@ -0,0 +1,40 @@ +/* PR tree-optimization/92226 - live nul char store to array eliminated + Test to verify warnings are issued for overflow detected thanks to + the enhancement committed on top of the fix for PR 92226. + { dg-do compile } + { dg-options "-O2 -Wall -Wno-array-bounds -ftrack-macro-expansion=0" } */ + +#include "strlenopt.h" + +#define NOIPA __attribute__ ((noipa)) + +#define T(MIN, MAX, SIZE, IDX) \ + NOIPA void \ + test_ ## MIN ## _ ## MAX ## _ ## SIZE ## _ ## IDX (const char *s) \ + { \ + size_t len = strlen (s); \ + if (MIN <= len && len <= MAX) \ + { \ + extern char d[]; \ + strcpy (d, s); \ + d[IDX] = 0; \ + extern char a ## SIZE[SIZE]; \ + strcpy (a ## SIZE, d); \ + } \ + } typedef void dummy_type + + +T (2, 2, 1, 0); +T (2, 2, 1, 1); // { dg-warning "writing 2 bytes into a region of size 1" } +T (2, 2, 1, 2); // { dg-warning "writing 3 bytes into a region of size 1" } + +T (2, 3, 1, 0); +T (2, 3, 1, 1); // { dg-warning "writing 2 bytes into a region of size 1" } +T (2, 3, 1, 2); // { dg-warning "writing 3 bytes into a region of size 1" "" { xfail *-*-*} } +T (2, 3, 1, 3); // { dg-warning "writing 4 bytes into a region of size 1" "" { xfail *-*-* } } + +T (5, 7, 3, 1); +T (5, 7, 3, 2); +T (5, 7, 3, 3); // { dg-warning "writing 4 bytes into a region of size 3" } +T (5, 7, 3, 4); // { dg-warning "writing 5 bytes into a region of size 3" } +T (5, 7, 3, 5); // { dg-warning "writing 6 bytes into a region of size 3" "" { xfail *-*-* } } diff --git a/gcc/testsuite/gcc.dg/strlenopt-89.c b/gcc/testsuite/gcc.dg/strlenopt-89.c new file mode 100644 index 0000000..ead451f --- /dev/null +++ b/gcc/testsuite/gcc.dg/strlenopt-89.c @@ -0,0 +1,89 @@ +/* PR tree-optimization/92226 - live nul char store to array eliminated + { dg-do compile } + { dg-options "-O2 -fdump-tree-strlen" } */ + +#include "strlenopt.h" + +#define NOIPA __attribute__ ((noipa)) + +/* Verify that the nul store into the destination is only eliminated + when overwrites the existing terminating nul added by the strcpy call. + Also verify that the second strlen call is eliminated in all cases. */ +#define T(SIZE, IDX) \ + NOIPA void test_ ## SIZE ## _store_nul_ ## IDX (const char *s) \ + { \ + extern char a ## SIZE[SIZE]; \ + char *d = a ## SIZE; \ + size_t len = SIZE - 1; \ + size_t idx = IDX; \ + if (strlen (s) == len) \ + { \ + strcpy (d, s); \ + d[idx] = 0; \ + if (strlen (d) != idx) \ + abort (); \ + } \ + } typedef void dummy_type + + +T (1, 0); // expect nul store to be eliminated + +T (2, 0); // nul store must be retained +T (2, 1); // expect nul store to be eliminated + +// Same as above but for larger arrays. +T (3, 0); +T (3, 1); +T (3, 2); + +T (4, 0); +T (4, 1); +T (4, 2); +T (4, 3); + +T (5, 0); +T (5, 1); +T (5, 2); +T (5, 3); +T (5, 4); + +T (6, 0); +T (6, 1); +T (6, 2); +T (6, 3); +T (6, 4); +T (6, 5); + +T (7, 0); +T (7, 1); +T (7, 2); +T (7, 3); +T (7, 4); +T (7, 5); +T (7, 6); + +T (8, 0); +T (8, 1); +T (8, 2); +T (8, 3); +T (8, 4); +T (8, 5); +T (8, 6); +T (8, 7); + +/* Verify that each function makes just one call to strlen to compute + the length of its argument (and not also to compute the length of + the copy): + { dg-final { scan-tree-dump-times "strlen \\(s_" 36 "strlen1" } } + { dg-final { scan-tree-dump-not "strlen \\(\\&a" "strlen1" } } + + Verify that nul stores into the last array element have been eliminated + (they are preceded by a strcpy storing into all the elements of the array: + { dg-final { scan-tree-dump-not "a1\\\] = 0;" "strlen1" } } + { dg-final { scan-tree-dump-not "a2 \\\+ 1B\\\] = 0;" "strlen1" } } + { dg-final { scan-tree-dump-not "a3 \\\+ 2B\\\] = 0;" "strlen1" } } + { dg-final { scan-tree-dump-not "a4 \\\+ 3B\\\] = 0;" "strlen1" } } + { dg-final { scan-tree-dump-not "a5 \\\+ 4B\\\] = 0;" "strlen1" } } + { dg-final { scan-tree-dump-not "a6 \\\+ 5B\\\] = 0;" "strlen1" } } + { dg-final { scan-tree-dump-not "a7 \\\+ 6B\\\] = 0;" "strlen1" } } + { dg-final { scan-tree-dump-not "a8 \\\+ 7B\\\] = 0;" "strlen1" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-90.c b/gcc/testsuite/gcc.dg/strlenopt-90.c new file mode 100644 index 0000000..2d4dad18 --- /dev/null +++ b/gcc/testsuite/gcc.dg/strlenopt-90.c @@ -0,0 +1,83 @@ +/* PR tree-optimization/92226 - live nul char store to array eliminated + { dg-do compile } + { dg-options "-O2 -fdump-tree-strlen" } */ + +#include "strlenopt.h" + +#define NOIPA __attribute__ ((noipa)) + +#define T(MIN, MAX, SIZE, IDX) \ + NOIPA void \ + test_ ## MIN ## _ ## MAX ## _ ## SIZE ## _ ## IDX (const char *s) \ + { \ + extern char a ## SIZE[SIZE]; \ + char *d = a ## SIZE; \ + size_t len = strlen (s); \ + size_t idx = IDX; \ + if (MIN <= len && len <= MAX) \ + { \ + strcpy (d, s); \ + d[idx] = 0; \ + if (strlen (d) != idx) \ + abort (); \ + } \ + } typedef void dummy_type + + +/* The final nul store must be retained but the second strlen call should + be eliminated because the final length of the destination after the nul + store must be equal to the index of the store. */ +T (0, 2, 4, 0); + +/* Not handled yet (see below): + T (0, 2, 4, 1); */ + +/* Not handled yet: in addition to the cases above, the second strlen + call can also be eliminated in those below because in both the final + length of the destination after the nul store must be in the same + range as the length of the source. + T (0, 2, 4, 2); + T (0, 2, 4, 3); */ + +T (2, 3, 4, 0); +T (2, 3, 4, 1); + +/* Not handled yet (see above): + T (2, 3, 4, 2); + T (2, 3, 4, 3); */ + +T (3, 4, 5, 0); +T (3, 4, 5, 1); +T (3, 4, 5, 2); + +/* Not handled yet (see above): + T (3, 4, 5, 3); + T (3, 4, 5, 4); */ + +T (3, 4, 6, 0); +T (3, 4, 6, 1); +T (3, 4, 6, 2); + +/* Not handled yet (see above): + T (3, 4, 6, 3); + T (3, 4, 6, 4); + T (3, 4, 6, 5); */ + + +/* Verify that each function makes just one call to strlen to compute + the length of its argument (and not also to compute the length of + the copy): + { dg-final { scan-tree-dump-times "strlen \\(s_" 9 "strlen1" } } + { dg-final { scan-tree-dump-not "strlen \\(\\&a" "strlen1" } } + + Verify that nul stores into the destination have not been eliminated: + { dg-final { scan-tree-dump-times "a4\\\] = 0;" 2 "strlen1" } } + { dg-final { scan-tree-dump-times "a4 \\\+ 1B\\\] = 0;" 1 "strlen1" } } + + { dg-final { scan-tree-dump-times "a5\\\] = 0;" 1 "strlen1" } } + { dg-final { scan-tree-dump-times "a5 \\\+ 1B\\\] = 0;" 1 "strlen1" } } + { dg-final { scan-tree-dump-times "a5 \\\+ 2B\\\] = 0;" 1 "strlen1" } } + + { dg-final { scan-tree-dump-times "a6\\\] = 0;" 1 "strlen1" } } + { dg-final { scan-tree-dump-times "a6 \\\+ 1B\\\] = 0;" 1 "strlen1" } } + { dg-final { scan-tree-dump-times "a6 \\\+ 2B\\\] = 0;" 1 "strlen1" } } */ diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c index 476bcf6..50cc442 100644 --- a/gcc/tree-ssa-strlen.c +++ b/gcc/tree-ssa-strlen.c @@ -281,7 +281,8 @@ get_next_strinfo (strinfo *si) *OFFSET_OUT. */ static int -get_addr_stridx (tree exp, tree ptr, unsigned HOST_WIDE_INT *offset_out) +get_addr_stridx (tree exp, tree ptr, unsigned HOST_WIDE_INT *offset_out, + const vr_values *rvals = NULL) { HOST_WIDE_INT off; struct stridxlist *list, *last = NULL; @@ -319,7 +320,7 @@ get_addr_stridx (tree exp, tree ptr, unsigned HOST_WIDE_INT *offset_out) unsigned HOST_WIDE_INT rel_off = (unsigned HOST_WIDE_INT) off - last->offset; strinfo *si = get_strinfo (last->idx); - if (si && compare_nonzero_chars (si, rel_off) >= 0) + if (si && compare_nonzero_chars (si, rel_off, rvals) >= 0) { if (offset_out) { @@ -4328,7 +4329,7 @@ handle_store (gimple_stmt_iterator *gsi, bool *zero_write, const vr_values *rval } else { - idx = get_addr_stridx (lhs, NULL_TREE, &offset); + idx = get_addr_stridx (lhs, NULL_TREE, &offset, rvals); if (idx > 0) si = get_strinfo (idx); } |