tree-ssa-strlen.c (get_addr_stridx): Add argument and use it.
authorMartin Sebor <msebor@redhat.com>
Mon, 28 Oct 2019 23:53:08 +0000 (23:53 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Mon, 28 Oct 2019 23:53:08 +0000 (17:53 -0600)
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

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/Wstringop-overflow-20.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/strlenopt-89.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/strlenopt-90.c [new file with mode: 0644]
gcc/tree-ssa-strlen.c

index 3f4f2dc356bcae49b3735003db4c388d225db402..8b8a6c6f647d5371fb0baf3c810b9c4b5f9fbe94 100644 (file)
@@ -1,3 +1,8 @@
+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
index 8f9859f6b2230106afecd809faa461dbd0dd2a12..a3ef28625e414d70293cdb2369140bd83f4edbe4 100644 (file)
@@ -1,3 +1,9 @@
+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
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-20.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-20.c
new file mode 100644 (file)
index 0000000..4a6fe8e
--- /dev/null
@@ -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 (file)
index 0000000..ead451f
--- /dev/null
@@ -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 (file)
index 0000000..2d4dad1
--- /dev/null
@@ -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" } }  */
index 476bcf662366f8984ec602013d83e323e3edf91e..50cc442a61f75924b2a6ac3a01d6ba7fde580e55 100644 (file)
@@ -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);
     }