]> gcc.gnu.org Git - gcc.git/commitdiff
gimple-fold.c (gimple_fold_builtin_strlen): Use set_strlen_range rather than set_rang...
authorMartin Sebor <msebor@redhat.com>
Wed, 2 Jan 2019 21:38:56 +0000 (21:38 +0000)
committerJeff Law <law@gcc.gnu.org>
Wed, 2 Jan 2019 21:38:56 +0000 (14:38 -0700)
* gimple-fold.c (gimple_fold_builtin_strlen): Use set_strlen_range
rather than set_range_info.
* tree-ssa-strlen.c (set_strlen_range): Extracted from
maybe_set_strlen_range.  Handle potentially boundary crossing
cases more conservatively.
(maybe_set_strlen_range): Parts refactored into set_strlen_range.
Call set_strlen_range.
* tree-ssa-strlen.h (set_strlen_range): Add prototype.

* gcc.dg/strlenopt-36.c: Update.
* gcc.dg/strlenopt-45.c: Update.
* gcc.c-torture/execute/strlen-5.c: New test.
* gcc.c-torture/execute/strlen-6.c: New test.
* gcc.c-torture/execute/strlen-7.c: New test.

Co-Authored-By: Jeff Law <law@redhat.com>
From-SVN: r267531

gcc/ChangeLog
gcc/gimple-fold.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/strlen-5.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/strlen-6.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/strlen-7.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/strlenopt-36.c
gcc/testsuite/gcc.dg/strlenopt-45.c
gcc/tree-ssa-strlen.c
gcc/tree-ssa-strlen.h

index b344f6be61e9366e342609b53608e11ca1268061..b4e2f25a2cc25a9efeb74205791c24d8ad7b46fb 100644 (file)
@@ -1,6 +1,16 @@
 2019-01-02  Martin Sebor  <msebor@redhat.com>
             Jeff Law  <law@redhat.com>
 
+
+       * gimple-fold.c (gimple_fold_builtin_strlen): Use set_strlen_range
+       rather than set_range_info.
+       * tree-ssa-strlen.c (set_strlen_range): Extracted from
+       maybe_set_strlen_range.  Handle potentially boundary crossing
+       cases more conservatively.
+       (maybe_set_strlen_range): Parts refactored into set_strlen_range.
+       Call set_strlen_range.
+       * tree-ssa-strlen.h (set_strlen_range): Add prototype.
+       
        PR middle-end/88663
        * gimple-fold.c (get_range_strlen): Update prototype to no longer
        need the flexp argument.
index 688daf921542659fb96d74a8737b9ed7ce7c19d5..0bb4db5e160090b4e8e632d23a96a8625d05b56c 100644 (file)
@@ -3739,10 +3739,9 @@ gimple_fold_builtin_strlen (gimple_stmt_iterator *gsi)
       return true;
     }
 
+  /* Set the strlen() range to [0, MAXLEN].  */
   if (tree lhs = gimple_call_lhs (stmt))
-    if (TREE_CODE (lhs) == SSA_NAME
-       && INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
-      set_range_info (lhs, VR_RANGE, minlen, maxlen);
+    set_strlen_range (lhs, maxlen);
 
   return false;
 }
index 40703c620172f75959d0343d6d3ef174f7eada08..1d5a8769faeb1da1a6eacacff6e7232096b16097 100644 (file)
@@ -1,3 +1,12 @@
+2019-01-02  Martin Sebor  <msebor@redhat.com>
+            Jeff Law  <law@redhat.com>
+
+       * gcc.dg/strlenopt-36.c: Update.
+       * gcc.dg/strlenopt-45.c: Update.
+       * gcc.c-torture/execute/strlen-5.c: New test.
+       * gcc.c-torture/execute/strlen-6.c: New test.
+       * gcc.c-torture/execute/strlen-7.c: New test.
+
 2019-01-02  Jakub Jelinek  <jakub@redhat.com>
 
        PR testsuite/87304
diff --git a/gcc/testsuite/gcc.c-torture/execute/strlen-5.c b/gcc/testsuite/gcc.c-torture/execute/strlen-5.c
new file mode 100644 (file)
index 0000000..9af57d5
--- /dev/null
@@ -0,0 +1,653 @@
+/* Test to verify that even strictly undefined strlen() calls with
+   unterminated character arrays yield the "expected" results when
+   the terminating nul is present in a subsequent suobobject.  */
+
+extern __SIZE_TYPE__ strlen (const char *);
+
+unsigned nfails;
+
+#define A(expr, N)                                             \
+  do {                                                         \
+    const char *s = (expr);                                    \
+    unsigned n = strlen (s);                                   \
+    ((n == N)                                                  \
+     ? 0                                                       \
+     : (__builtin_printf ("line %i: strlen (%s = \"%s\")"      \
+                         " == %u failed\n",                    \
+                         __LINE__, #expr, s, N),               \
+       ++nfails));                                             \
+  } while (0)
+
+
+int idx;
+
+
+const char ca[][4] = {
+  { '1', '2', '3', '4' }, { '5' },
+  { '1', '2', '3', '4' }, { '5', '6' },
+  { '1', '2', '3', '4' }, { '5', '6', '7' },
+  { '1', '2', '3', '4' }, { '5', '6', '7', '8' },
+  { '9' }
+};
+
+static void test_const_global_arrays (void)
+{
+  A (ca[0], 5);
+  A (&ca[0][0], 5);
+  A (&ca[0][1], 4);
+  A (&ca[0][3], 2);
+
+  int i = 0;
+  A (ca[i], 5);
+  A (&ca[i][0], 5);
+  A (&ca[i][1], 4);
+  A (&ca[i][3], 2);
+
+  int j = i;
+  A (&ca[i][i], 5);
+  A (&ca[i][j + 1], 4);
+  A (&ca[i][j + 2], 3);
+
+  A (&ca[idx][i], 5);
+  A (&ca[idx][j + 1], 4);
+  A (&ca[idx][j + 2], 3);
+
+  A (&ca[idx][idx], 5);
+  A (&ca[idx][idx + 1], 4);
+  A (&ca[idx][idx + 2], 3);
+
+  A (&ca[0][++j], 4);
+  A (&ca[0][++j], 3);
+  A (&ca[0][++j], 2);
+
+  if (j != 3)
+    ++nfails;
+}
+
+
+static void test_const_local_arrays (void)
+{
+  const char a[][4] = {
+    { '1', '2', '3', '4' }, { '5' },
+    { '1', '2', '3', '4' }, { '5', '6' },
+    { '1', '2', '3', '4' }, { '5', '6', '7' },
+    { '1', '2', '3', '4' }, { '5', '6', '7', '8' },
+    { '9' }
+  };
+
+  A (a[0], 5);
+  A (&a[0][0], 5);
+  A (&a[0][1], 4);
+  A (&a[0][3], 2);
+
+  int i = 0;
+  A (a[i], 5);
+  A (&a[i][0], 5);
+  A (&a[i][1], 4);
+  A (&a[i][3], 2);
+
+  int j = i;
+  A (&a[i][i], 5);
+  A (&a[i][j + 1], 4);
+  A (&a[i][j + 2], 3);
+
+  A (&a[idx][i], 5);
+  A (&a[idx][j + 1], 4);
+  A (&a[idx][j + 2], 3);
+
+  A (&a[idx][idx], 5);
+  A (&a[idx][idx + 1], 4);
+  A (&a[idx][idx + 2], 3);
+
+  A (&a[0][++j], 4);
+  A (&a[0][++j], 3);
+  A (&a[0][++j], 2);
+
+  if (j != 3)
+    ++nfails;
+}
+
+
+char va[][4] = {
+  { '1', '2', '3', '4' }, { '5' },
+  { '1', '2', '3', '4' }, { '5', '6' },
+  { '1', '2', '3', '4' }, { '5', '6', '7' },
+  { '1', '2', '3', '4' }, { '5', '6', '7', '8' },
+  { '9' }
+};
+
+static void test_nonconst_global_arrays (void)
+{
+  {
+    A (va[0], 5);
+    A (&va[0][0], 5);
+    A (&va[0][1], 4);
+    A (&va[0][3], 2);
+
+    int i = 0;
+    A (va[i], 5);
+    A (&va[i][0], 5);
+    A (&va[i][1], 4);
+    A (&va[i][3], 2);
+
+    int j = i;
+    A (&va[i][i], 5);
+    A (&va[i][j + 1], 4);
+    A (&va[i][j + 2], 3);
+
+    A (&va[idx][i], 5);
+    A (&va[idx][j + 1], 4);
+    A (&va[idx][j + 2], 3);
+
+    A (&va[idx][idx], 5);
+    A (&va[idx][idx + 1], 4);
+    A (&va[idx][idx + 2], 3);
+  }
+
+  {
+    A (va[2], 6);
+    A (&va[2][0], 6);
+    A (&va[2][1], 5);
+    A (&va[2][3], 3);
+
+    int i = 2;
+    A (va[i], 6);
+    A (&va[i][0], 6);
+    A (&va[i][1], 5);
+    A (&va[i][3], 3);
+
+    int j = i - 1;
+    A (&va[i][j - 1], 6);
+    A (&va[i][j], 5);
+    A (&va[i][j + 1], 4);
+
+    A (&va[idx + 2][i - 1], 5);
+    A (&va[idx + 2][j], 5);
+    A (&va[idx + 2][j + 1], 4);
+  }
+
+  int j = 0;
+
+  A (&va[0][++j], 4);
+  A (&va[0][++j], 3);
+  A (&va[0][++j], 2);
+
+  if (j != 3)
+    ++nfails;
+}
+
+
+static void test_nonconst_local_arrays (void)
+{
+  char a[][4] = {
+    { '1', '2', '3', '4' }, { '5' },
+    { '1', '2', '3', '4' }, { '5', '6' },
+    { '1', '2', '3', '4' }, { '5', '6', '7' },
+    { '1', '2', '3', '4' }, { '5', '6', '7', '8' },
+    { '9' }
+  };
+
+  A (a[0], 5);
+  A (&a[0][0], 5);
+  A (&a[0][1], 4);
+  A (&a[0][3], 2);
+
+  int i = 0;
+  A (a[i], 5);
+  A (&a[i][0], 5);
+  A (&a[i][1], 4);
+  A (&a[i][3], 2);
+
+  int j = i;
+  A (&a[i][i], 5);
+  A (&a[i][j + 1], 4);
+  A (&a[i][j + 2], 3);
+
+  A (&a[idx][i], 5);
+  A (&a[idx][j + 1], 4);
+  A (&a[idx][j + 2], 3);
+
+  A (&a[idx][idx], 5);
+  A (&a[idx][idx + 1], 4);
+  A (&a[idx][idx + 2], 3);
+
+  A (&a[0][++j], 4);
+  A (&a[0][++j], 3);
+  A (&a[0][++j], 2);
+
+  if (j != 3)
+    ++nfails;
+}
+
+
+struct MemArrays { char a[4], b[4]; };
+
+const struct MemArrays cma[] = {
+  { { '1', '2', '3', '4' }, { '5' } },
+  { { '1', '2', '3', '4' }, { '5', '6' } },
+  { { '1', '2', '3', '4' }, { '5', '6' } },
+  { { '1', '2', '3', '4' }, { '5', '6', '7' } },
+  { { '1', '2', '3', '4' }, { '5', '6', '7', '8' } },
+  { { '9' }, { '\0' } }
+};
+
+static void test_const_global_member_arrays (void)
+{
+  {
+    A (cma[0].a, 5);
+    A (&cma[0].a[0], 5);
+    A (&cma[0].a[1], 4);
+    A (&cma[0].a[2], 3);
+
+    int i = 0;
+    A (cma[i].a, 5);
+    A (&cma[i].a[0], 5);
+    A (&cma[i].a[1], 4);
+    A (&cma[i].a[2], 3);
+
+    int j = i;
+    A (&cma[i].a[j], 5);
+    A (&cma[i].a[j + 1], 4);
+    A (&cma[i].a[j + 2], 3);
+
+    A (&cma[idx].a[i], 5);
+    A (&cma[idx].a[j + 1], 4);
+    A (&cma[idx].a[j + 2], 3);
+
+    A (&cma[idx].a[idx], 5);
+    A (&cma[idx].a[idx + 1], 4);
+    A (&cma[idx].a[idx + 2], 3);
+  }
+
+  {
+    A (cma[1].a, 6);
+    A (&cma[1].a[0], 6);
+    A (&cma[1].a[1], 5);
+    A (&cma[1].a[2], 4);
+
+    int i = 1;
+    A (cma[i].a, 6);
+    A (&cma[i].a[0], 6);
+    A (&cma[i].a[1], 5);
+    A (&cma[i].a[2], 4);
+
+    int j = i - 1;
+    A (&cma[i].a[j], 6);
+    A (&cma[i].a[j + 1], 5);
+    A (&cma[i].a[j + 2], 4);
+
+    A (&cma[idx + 1].a[j], 6);
+    A (&cma[idx + 1].a[j + 1], 5);
+    A (&cma[idx + 1].a[j + 2], 4);
+
+    A (&cma[idx + 1].a[idx], 6);
+    A (&cma[idx + 1].a[idx + 1], 5);
+    A (&cma[idx + 1].a[idx + 2], 4);
+  }
+
+  {
+    A (cma[4].a, 9);
+    A (&cma[4].a[0], 9);
+    A (&cma[4].a[1], 8);
+    A (&cma[4].b[0], 5);
+
+    int i = 4;
+    A (cma[i].a, 9);
+    A (&cma[i].a[0], 9);
+    A (&cma[i].a[1], 8);
+    A (&cma[i].b[0], 5);
+
+    int j = i - 1;
+    A (&cma[i].a[j], 6);
+    A (&cma[i].a[j + 1], 5);
+    A (&cma[i].b[j - 2], 4);
+
+    A (&cma[idx + 4].a[j], 6);
+    A (&cma[idx + 4].a[j + 1], 5);
+    A (&cma[idx + 4].b[j - 2], 4);
+
+    A (&cma[idx + 4].a[idx], 9);
+    A (&cma[idx + 4].a[idx + 1], 8);
+    A (&cma[idx + 4].b[idx + 1], 4);
+  }
+}
+
+
+static void test_const_local_member_arrays (void)
+{
+  const struct MemArrays ma[] = {
+    { { '1', '2', '3', '4' }, { '5' } },
+    { { '1', '2', '3', '4' }, { '5', '6' } },
+    { { '1', '2', '3', '4' }, { '5', '6' } },
+    { { '1', '2', '3', '4' }, { '5', '6', '7' } },
+    { { '1', '2', '3', '4' }, { '5', '6', '7', '8' } },
+    { { '9' }, { '\0' } }
+  };
+
+  {
+    A (ma[0].a, 5);
+    A (&ma[0].a[0], 5);
+    A (&ma[0].a[1], 4);
+    A (&ma[0].a[2], 3);
+
+    int i = 0;
+    A (ma[i].a, 5);
+    A (&ma[i].a[0], 5);
+    A (&ma[i].a[1], 4);
+    A (&ma[i].a[2], 3);
+
+    int j = i;
+    A (&ma[i].a[j], 5);
+    A (&ma[i].a[j + 1], 4);
+    A (&ma[i].a[j + 2], 3);
+
+    A (&ma[idx].a[i], 5);
+    A (&ma[idx].a[j + 1], 4);
+    A (&ma[idx].a[j + 2], 3);
+
+    A (&ma[idx].a[idx], 5);
+    A (&ma[idx].a[idx + 1], 4);
+    A (&ma[idx].a[idx + 2], 3);
+  }
+
+  {
+    A (ma[1].a, 6);
+    A (&ma[1].a[0], 6);
+    A (&ma[1].a[1], 5);
+    A (&ma[1].a[2], 4);
+
+    int i = 1;
+    A (ma[i].a, 6);
+    A (&ma[i].a[0], 6);
+    A (&ma[i].a[1], 5);
+    A (&ma[i].a[2], 4);
+
+    int j = i - 1;
+    A (&ma[i].a[j], 6);
+    A (&ma[i].a[j + 1], 5);
+    A (&ma[i].a[j + 2], 4);
+
+    A (&ma[idx + 1].a[j], 6);
+    A (&ma[idx + 1].a[j + 1], 5);
+    A (&ma[idx + 1].a[j + 2], 4);
+
+    A (&ma[idx + 1].a[idx], 6);
+    A (&ma[idx + 1].a[idx + 1], 5);
+    A (&ma[idx + 1].a[idx + 2], 4);
+  }
+
+  {
+    A (ma[4].a, 9);
+    A (&ma[4].a[0], 9);
+    A (&ma[4].a[1], 8);
+    A (&ma[4].b[0], 5);
+
+    int i = 4;
+    A (ma[i].a, 9);
+    A (&ma[i].a[0], 9);
+    A (&ma[i].a[1], 8);
+    A (&ma[i].b[0], 5);
+
+    int j = i - 1;
+    A (&ma[i].a[j], 6);
+    A (&ma[i].a[j + 1], 5);
+    A (&ma[i].b[j - 2], 4);
+
+    A (&ma[idx + 4].a[j], 6);
+    A (&ma[idx + 4].a[j + 1], 5);
+    A (&ma[idx + 4].b[j - 2], 4);
+
+    A (&ma[idx + 4].a[idx], 9);
+    A (&ma[idx + 4].a[idx + 1], 8);
+    A (&ma[idx + 4].b[idx + 1], 4);
+  }
+}
+
+struct MemArrays vma[] = {
+  { { '1', '2', '3', '4' }, { '5' } },
+  { { '1', '2', '3', '4' }, { '5', '6' } },
+  { { '1', '2', '3', '4' }, { '5', '6' } },
+  { { '1', '2', '3', '4' }, { '5', '6', '7' } },
+  { { '1', '2', '3', '4' }, { '5', '6', '7', '8' } },
+  { { '9' }, { '\0' } }
+};
+
+static void test_nonconst_global_member_arrays (void)
+{
+  {
+    A (vma[0].a, 5);
+    A (&vma[0].a[0], 5);
+    A (&vma[0].a[1], 4);
+    A (&vma[0].a[2], 3);
+
+    int i = 0;
+    A (vma[i].a, 5);
+    A (&vma[i].a[0], 5);
+    A (&vma[i].a[1], 4);
+    A (&vma[i].a[2], 3);
+
+    int j = i;
+    A (&vma[i].a[j], 5);
+    A (&vma[i].a[j + 1], 4);
+    A (&vma[i].a[j + 2], 3);
+
+    A (&vma[idx].a[i], 5);
+    A (&vma[idx].a[j + 1], 4);
+    A (&vma[idx].a[j + 2], 3);
+
+    A (&vma[idx].a[idx], 5);
+    A (&vma[idx].a[idx + 1], 4);
+    A (&vma[idx].a[idx + 2], 3);
+  }
+
+  {
+    A (vma[1].a, 6);
+    A (&vma[1].a[0], 6);
+    A (&vma[1].a[1], 5);
+    A (&vma[1].a[2], 4);
+
+    int i = 1;
+    A (vma[i].a, 6);
+    A (&vma[i].a[0], 6);
+    A (&vma[i].a[1], 5);
+    A (&vma[i].a[2], 4);
+
+    int j = i - 1;
+    A (&vma[i].a[j], 6);
+    A (&vma[i].a[j + 1], 5);
+    A (&vma[i].a[j + 2], 4);
+
+    A (&vma[idx + 1].a[j], 6);
+    A (&vma[idx + 1].a[j + 1], 5);
+    A (&vma[idx + 1].a[j + 2], 4);
+
+    A (&vma[idx + 1].a[idx], 6);
+    A (&vma[idx + 1].a[idx + 1], 5);
+    A (&vma[idx + 1].a[idx + 2], 4);
+  }
+
+  {
+    A (vma[4].a, 9);
+    A (&vma[4].a[0], 9);
+    A (&vma[4].a[1], 8);
+    A (&vma[4].b[0], 5);
+
+    int i = 4;
+    A (vma[i].a, 9);
+    A (&vma[i].a[0], 9);
+    A (&vma[i].a[1], 8);
+    A (&vma[i].b[0], 5);
+
+    int j = i - 1;
+    A (&vma[i].a[j], 6);
+    A (&vma[i].a[j + 1], 5);
+    A (&vma[i].b[j - 2], 4);
+
+    A (&vma[idx + 4].a[j], 6);
+    A (&vma[idx + 4].a[j + 1], 5);
+    A (&vma[idx + 4].b[j - 2], 4);
+
+    A (&vma[idx + 4].a[idx], 9);
+    A (&vma[idx + 4].a[idx + 1], 8);
+    A (&vma[idx + 4].b[idx + 1], 4);
+  }
+}
+
+
+static void test_nonconst_local_member_arrays (void)
+{
+  struct MemArrays ma[] = {
+    { { '1', '2', '3', '4' }, { '5' } },
+    { { '1', '2', '3', '4' }, { '5', '6' } },
+    { { '1', '2', '3', '4' }, { '5', '6' } },
+    { { '1', '2', '3', '4' }, { '5', '6', '7' } },
+    { { '1', '2', '3', '4' }, { '5', '6', '7', '8' } },
+    { { '9' }, { '\0' } }
+  };
+
+  {
+    A (ma[0].a, 5);
+    A (&ma[0].a[0], 5);
+    A (&ma[0].a[1], 4);
+    A (&ma[0].a[2], 3);
+
+    int i = 0;
+    A (ma[i].a, 5);
+    A (&ma[i].a[0], 5);
+    A (&ma[i].a[1], 4);
+    A (&ma[i].a[2], 3);
+
+    int j = i;
+    A (&ma[i].a[j], 5);
+    A (&ma[i].a[j + 1], 4);
+    A (&ma[i].a[j + 2], 3);
+
+    A (&ma[idx].a[i], 5);
+    A (&ma[idx].a[j + 1], 4);
+    A (&ma[idx].a[j + 2], 3);
+
+    A (&ma[idx].a[idx], 5);
+    A (&ma[idx].a[idx + 1], 4);
+    A (&ma[idx].a[idx + 2], 3);
+  }
+
+  {
+    A (ma[1].a, 6);
+    A (&ma[1].a[0], 6);
+    A (&ma[1].a[1], 5);
+    A (&ma[1].a[2], 4);
+
+    int i = 1;
+    A (ma[i].a, 6);
+    A (&ma[i].a[0], 6);
+    A (&ma[i].a[1], 5);
+    A (&ma[i].a[2], 4);
+
+    int j = i - 1;
+    A (&ma[i].a[j], 6);
+    A (&ma[i].a[j + 1], 5);
+    A (&ma[i].a[j + 2], 4);
+
+    A (&ma[idx + 1].a[j], 6);
+    A (&ma[idx + 1].a[j + 1], 5);
+    A (&ma[idx + 1].a[j + 2], 4);
+
+    A (&ma[idx + 1].a[idx], 6);
+    A (&ma[idx + 1].a[idx + 1], 5);
+    A (&ma[idx + 1].a[idx + 2], 4);
+  }
+
+  {
+    A (ma[4].a, 9);
+    A (&ma[4].a[0], 9);
+    A (&ma[4].a[1], 8);
+    A (&ma[4].b[0], 5);
+
+    int i = 4;
+    A (ma[i].a, 9);
+    A (&ma[i].a[0], 9);
+    A (&ma[i].a[1], 8);
+    A (&ma[i].b[0], 5);
+
+    int j = i - 1;
+    A (&ma[i].a[j], 6);
+    A (&ma[i].a[j + 1], 5);
+    A (&ma[i].b[j - 2], 4);
+
+    A (&ma[idx + 4].a[j], 6);
+    A (&ma[idx + 4].a[j + 1], 5);
+    A (&ma[idx + 4].b[j - 2], 4);
+
+    A (&ma[idx + 4].a[idx], 9);
+    A (&ma[idx + 4].a[idx + 1], 8);
+    A (&ma[idx + 4].b[idx + 1], 4);
+  }
+}
+
+
+union UnionMemberArrays
+{
+  struct { char a[4], b[4]; } a;
+  struct { char a[8]; } c;
+};
+
+const union UnionMemberArrays cu = {
+  { { '1', '2', '3', '4' }, { '5', } }
+};
+
+static void test_const_union_member_arrays (void)
+{
+  A (cu.a.a, 5);
+  A (cu.a.b, 1);
+  A (cu.c.a, 5);
+
+  const union UnionMemberArrays clu = {
+    { { '1', '2', '3', '4' }, { '5', '6' } }
+  };
+
+  A (clu.a.a, 6);
+  A (clu.a.b, 2);
+  A (clu.c.a, 6);
+}
+
+
+union UnionMemberArrays vu = {
+  { { '1', '2', '3', '4' }, { '5', '6' } }
+};
+
+static void test_nonconst_union_member_arrays (void)
+{
+  A (vu.a.a, 6);
+  A (vu.a.b, 2);
+  A (vu.c.a, 6);
+
+  union UnionMemberArrays lvu = {
+    { { '1', '2', '3', '4' }, { '5', '6', '7' } }
+  };
+
+  A (lvu.a.a, 7);
+  A (lvu.a.b, 3);
+  A (lvu.c.a, 7);
+}
+
+
+int main (void)
+{
+  test_const_global_arrays ();
+  test_const_local_arrays ();
+
+  test_nonconst_global_arrays ();
+  test_nonconst_local_arrays ();
+
+  test_const_global_member_arrays ();
+  test_const_local_member_arrays ();
+
+  test_nonconst_global_member_arrays ();
+  test_nonconst_local_member_arrays ();
+
+  test_const_union_member_arrays ();
+  test_nonconst_union_member_arrays ();
+
+  if (nfails)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/strlen-6.c b/gcc/testsuite/gcc.c-torture/execute/strlen-6.c
new file mode 100644 (file)
index 0000000..1df5b21
--- /dev/null
@@ -0,0 +1,113 @@
+/* Test to verify that strlen() calls with conditional expressions
+   and unterminated arrays or pointers to such things as arguments
+   are evaluated without making assumptions about array sizes.  */
+
+extern __SIZE_TYPE__ strlen (const char *);
+
+unsigned nfails;
+
+#define A(expr, N)                                             \
+  do {                                                         \
+    const char *_s = (expr);                                   \
+    unsigned _n = strlen (_s);                                 \
+    ((_n == N)                                                 \
+     ? 0                                                       \
+     : (__builtin_printf ("line %i: strlen ((%s) = (\"%s\"))"  \
+                         " == %u failed\n",                    \
+                         __LINE__, #expr, _s, N),              \
+       ++nfails));                                             \
+  } while (0)
+
+
+volatile int i0 = 0;
+
+const char ca[2][3] = { "12" };
+const char cb[2][3] = { { '1', '2', '3', }, { '4' } };
+
+char va[2][3] = { "123" };
+char vb[2][3] = { { '1', '2', '3', }, { '4', '5' } };
+
+const char *s = "123456";
+
+
+static void test_binary_cond_expr_global (void)
+{
+  A (i0 ? "1" : ca[0], 2);
+  A (i0 ? ca[0] : "123", 3);
+
+  /* The call to strlen (cb[0]) is strictly undefined because the array
+     isn't nul-terminated.  This test verifies that the strlen range
+     optimization doesn't assume that the argument is necessarily nul
+     terminated.
+     Ditto for strlen (vb[0]).  */
+  A (i0 ? "1" : cb[0], 4);              /* GCC 8.2 failure */
+  A (i0 ? cb[0] : "12", 2);
+
+  A (i0 ? "1" : va[0], 3);              /* GCC 8.2 failure */
+  A (i0 ? va[0] : "1234", 4);
+
+  A (i0 ? "1" : vb[0], 5);              /* GCC 8.2 failure */
+  A (i0 ? vb[0] : "12", 2);
+}
+
+
+static void test_binary_cond_expr_local (void)
+{
+  const char lca[2][3] = { "12" };
+  const char lcb[2][3] = { { '1', '2', '3', }, { '4' } };
+
+  char lva[2][3] = { "123" };
+  char lvb[2][3] = { { '1', '2', '3', }, { '4', '5' } };
+
+  /* Also undefined as above.  */
+  A (i0 ? "1" : lca[0], 2);
+  A (i0 ? lca[0] : "123", 3);
+
+  A (i0 ? "1" : lcb[0], 4);             /* GCC 8.2 failure */
+  A (i0 ? lcb[0] : "12", 2);
+
+  A (i0 ? "1" : lva[0], 3);             /* GCC 8.2 failure */
+  A (i0 ? lva[0] : "1234", 4);
+
+  A (i0 ? "1" : lvb[0], 5);             /* GCC 8.2 failure */
+  A (i0 ? lvb[0] : "12", 2);
+}
+
+
+static void test_ternary_cond_expr (void)
+{
+  /* Also undefined.  */
+  A (i0 == 0 ? s : i0 == 1 ? vb[0] : "123", 6);
+  A (i0 == 0 ? vb[0] : i0 == 1 ? s : "123", 5);
+  A (i0 == 0 ? "123" : i0 == 1 ? s : vb[0], 3);
+}
+
+
+const char (*pca)[3] = &ca[0];
+const char (*pcb)[3] = &cb[0];
+
+char (*pva)[3] = &va[0];
+char (*pvb)[3] = &vb[0];
+
+static void test_binary_cond_expr_arrayptr (void)
+{
+  /* Also undefined.  */
+  A (i0 ? *pca : *pcb, 4);              /* GCC 8.2 failure */
+  A (i0 ? *pcb : *pca, 2);
+
+  A (i0 ? *pva : *pvb, 5);              /* GCC 8.2 failure */
+  A (i0 ? *pvb : *pva, 3);
+}
+
+
+int main (void)
+{
+  test_binary_cond_expr_global ();
+  test_binary_cond_expr_local ();
+
+  test_ternary_cond_expr ();
+  test_binary_cond_expr_arrayptr ();
+
+  if (nfails)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/strlen-7.c b/gcc/testsuite/gcc.c-torture/execute/strlen-7.c
new file mode 100644 (file)
index 0000000..884db65
--- /dev/null
@@ -0,0 +1,37 @@
+/* Test to verify that a strlen() call with a pointer to a dynamic type
+   doesn't make assumptions based on the static type of the original
+   pointer.  See g++.dg/init/strlen.C for the corresponding C++ test.  */
+
+struct A { int i; char a[1]; void (*p)(); };
+struct B { char a[sizeof (struct A) - __builtin_offsetof (struct A, a)]; };
+
+__attribute__ ((noipa)) void
+init (char *d, const char *s)
+{
+  __builtin_strcpy (d, s);
+}
+
+struct B b;
+
+__attribute__ ((noipa)) void
+test_dynamic_type (struct A *p)
+{
+  /* The following call is undefined because it writes past the end
+     of the p->a subobject, but the corresponding GIMPLE considers
+     it valid and there's apparently no way to distinguish invalid
+     cases from ones like it that might be valid.  If/when GIMPLE
+     changes to make this possible this test can be removed.  */
+  char *q = (char*)__builtin_memcpy (p->a, &b, sizeof b);
+
+  init (q, "foobar");
+
+  if (6 != __builtin_strlen (q))
+    __builtin_abort();
+}
+
+int main (void)
+{
+  struct A *p = (struct A*)__builtin_malloc (sizeof *p);
+  test_dynamic_type (p);
+  return 0;
+}
index d6fcca26b976bc79a5ce50635ab99618cad78aa4..56e59a431a49c668b9e9b3e97fbb709363c852c0 100644 (file)
@@ -9,23 +9,6 @@ extern char a7[7], a6[6], a5[5], a4[4], a3[3], a2[2], a1[1];
 extern char a0[0];   /* Intentionally not tested here.  */
 extern char ax[];    /* Same.  */
 
-struct MemArrays {
-  char a7[7], a6[6], a5[5], a4[4], a3[3], a2[2], a1[1];
-  char a0[0];   /* Not tested here.  */
-};
-
-struct NestedMemArrays {
-  struct { char a7[7]; } ma7;
-  struct { char a6[6]; } ma6;
-  struct { char a5[5]; } ma5;
-  struct { char a4[4]; } ma4;
-  struct { char a3[3]; } ma3;
-  struct { char a2[2]; } ma2;
-  struct { char a1[1]; } ma1;
-  struct { char a0[0]; } ma0;
-  char last;
-};
-
 extern void failure_on_line (int);
 
 #define TEST_FAIL(line)                                        \
@@ -51,36 +34,4 @@ void test_array (void)
     T (strlen (a1) == 0);  */
 }
 
-void test_memarray (struct MemArrays *ma)
-{
-  T (strlen (ma->a7) < sizeof ma->a7);
-  T (strlen (ma->a6) < sizeof ma->a6);
-  T (strlen (ma->a5) < sizeof ma->a5);
-  T (strlen (ma->a4) < sizeof ma->a4);
-  T (strlen (ma->a3) < sizeof ma->a3);
-
-  /* The following two calls are folded too early which defeats
-     the strlen() optimization.
-  T (strlen (ma->a2) == 1);
-  T (strlen (ma->a1) == 0);  */
-}
-
-/* Verify that the range of strlen(A) of a last struct member is
-   set even when the array is the sole member of a struct as long
-   as the struct itself is a member of another struct.  The converse
-   is tested in stlenopt-37.c.  */
-void test_nested_memarray (struct NestedMemArrays *ma)
-{
-  T (strlen (ma->ma7.a7) < sizeof ma->ma7.a7);
-  T (strlen (ma->ma6.a6) < sizeof ma->ma6.a6);
-  T (strlen (ma->ma5.a5) < sizeof ma->ma5.a5);
-  T (strlen (ma->ma4.a4) < sizeof ma->ma4.a4);
-  T (strlen (ma->ma3.a3) < sizeof ma->ma3.a3);
-
-  /* The following two calls are folded too early which defeats
-     the strlen() optimization.
-  T (strlen (ma->ma2.a2) == 1);
-  T (strlen (ma->ma1.a1) == 0);  */
-}
-
 /* { dg-final { scan-tree-dump-not "failure_on_line" "optimized" } } */
index bd9b197a75d6913407ead49dc303903a81c7b5ad..31c1e538f6ff28470d3f739d320159294c44ccca 100644 (file)
@@ -2,7 +2,7 @@
    Test to verify that strnlen built-in expansion works correctly
    in the absence of tree strlen optimization.
    { dg-do compile }
-   { dg-options "-O2 -Wall -fdump-tree-optimized" } */
+   { dg-options "-O2 -Wall -Wno-stringop-overflow -fdump-tree-optimized" } */
 
 #include "strlenopt.h"
 
@@ -85,19 +85,19 @@ void elim_strnlen_arr_cst (void)
   ELIM (strnlen (a3_7[0], 1) < 2);
   ELIM (strnlen (a3_7[0], 2) < 3);
   ELIM (strnlen (a3_7[0], 3) < 4);
-  ELIM (strnlen (a3_7[0], 9) < 8);
-  ELIM (strnlen (a3_7[0], PTRDIFF_MAX) < 8);
-  ELIM (strnlen (a3_7[0], SIZE_MAX) < 8);
-  ELIM (strnlen (a3_7[0], -1) < 8);
+  ELIM (strnlen (a3_7[0], 9) <= 9);
+  ELIM (strnlen (a3_7[0], PTRDIFF_MAX) <= sizeof a3_7);
+  ELIM (strnlen (a3_7[0], SIZE_MAX) <= sizeof a3_7);
+  ELIM (strnlen (a3_7[0], -1) <= sizeof a3_7);
 
   ELIM (strnlen (a3_7[2], 0) == 0);
   ELIM (strnlen (a3_7[2], 1) < 2);
   ELIM (strnlen (a3_7[2], 2) < 3);
   ELIM (strnlen (a3_7[2], 3) < 4);
-  ELIM (strnlen (a3_7[2], 9) < 8);
-  ELIM (strnlen (a3_7[2], PTRDIFF_MAX) < 8);
-  ELIM (strnlen (a3_7[2], SIZE_MAX) < 8);
-  ELIM (strnlen (a3_7[2], -1) < 8);
+  ELIM (strnlen (a3_7[2], 9) <= 9);
+  ELIM (strnlen (a3_7[2], PTRDIFF_MAX) < sizeof a3_7);
+  ELIM (strnlen (a3_7[2], SIZE_MAX) < sizeof a3_7);
+  ELIM (strnlen (a3_7[2], -1) < sizeof a3_7);
 
   ELIM (strnlen ((char*)a3_7, 0) == 0);
   ELIM (strnlen ((char*)a3_7, 1) < 2);
@@ -105,123 +105,19 @@ void elim_strnlen_arr_cst (void)
   ELIM (strnlen ((char*)a3_7, 3) < 4);
   ELIM (strnlen ((char*)a3_7, 9) < 10);
   ELIM (strnlen ((char*)a3_7, 19) < 20);
-  ELIM (strnlen ((char*)a3_7, 21) < 22);
-  ELIM (strnlen ((char*)a3_7, 23) < 22);
-  ELIM (strnlen ((char*)a3_7, PTRDIFF_MAX) < 22);
-  ELIM (strnlen ((char*)a3_7, SIZE_MAX) < 22);
-  ELIM (strnlen ((char*)a3_7, -1) < 22);
+  ELIM (strnlen ((char*)a3_7, 21) <= sizeof a3_7);
+  ELIM (strnlen ((char*)a3_7, 23) <= sizeof a3_7);
+  ELIM (strnlen ((char*)a3_7, PTRDIFF_MAX) <= sizeof a3_7);
+  ELIM (strnlen ((char*)a3_7, SIZE_MAX) <= sizeof a3_7);
+  ELIM (strnlen ((char*)a3_7, -1) <= sizeof a3_7);
 
   ELIM (strnlen (ax, 0) == 0);
   ELIM (strnlen (ax, 1) < 2);
   ELIM (strnlen (ax, 2) < 3);
   ELIM (strnlen (ax, 9) < 10);
-  ELIM (strnlen (a3, PTRDIFF_MAX) <= PTRDIFF_MAX);
-  ELIM (strnlen (a3, SIZE_MAX) < PTRDIFF_MAX);
-  ELIM (strnlen (a3, -1) < PTRDIFF_MAX);
-}
-
-struct MemArrays
-{
-  char c;
-  char a0[0];
-  char a1[1];
-  char a3[3];
-  char a5[5];
-  char a3_7[3][7];
-  char ax[1];
-};
-
-void elim_strnlen_memarr_cst (struct MemArrays *p, int i)
-{
-  ELIM (strnlen (&p->c, 0) == 0);
-  ELIM (strnlen (&p->c, 1) < 2);
-  ELIM (strnlen (&p->c, 9) == 0);
-  ELIM (strnlen (&p->c, PTRDIFF_MAX) == 0);
-  ELIM (strnlen (&p->c, SIZE_MAX) == 0);
-  ELIM (strnlen (&p->c, -1) == 0);
-
-  /* Other accesses to internal zero-length arrays are undefined.  */
-  ELIM (strnlen (p->a0, 0) == 0);
-
-  ELIM (strnlen (p->a1, 0) == 0);
-  ELIM (strnlen (p->a1, 1) < 2);
-  ELIM (strnlen (p->a1, 9) == 0);
-  ELIM (strnlen (p->a1, PTRDIFF_MAX) == 0);
-  ELIM (strnlen (p->a1, SIZE_MAX) == 0);
-  ELIM (strnlen (p->a1, -1) == 0);
-
-  ELIM (strnlen (p->a3, 0) == 0);
-  ELIM (strnlen (p->a3, 1) < 2);
-  ELIM (strnlen (p->a3, 2) < 3);
-  ELIM (strnlen (p->a3, 3) < 4);
-  ELIM (strnlen (p->a3, 9) < 4);
-  ELIM (strnlen (p->a3, PTRDIFF_MAX) < 4);
-  ELIM (strnlen (p->a3, SIZE_MAX) < 4);
-  ELIM (strnlen (p->a3, -1) < 4);
-
-  ELIM (strnlen (p[i].a3, 0) == 0);
-  ELIM (strnlen (p[i].a3, 1) < 2);
-  ELIM (strnlen (p[i].a3, 2) < 3);
-  ELIM (strnlen (p[i].a3, 3) < 4);
-  ELIM (strnlen (p[i].a3, 9) < 4);
-  ELIM (strnlen (p[i].a3, PTRDIFF_MAX) < 4);
-  ELIM (strnlen (p[i].a3, SIZE_MAX) < 4);
-  ELIM (strnlen (p[i].a3, -1) < 4);
-
-  ELIM (strnlen (p->a3_7[0], 0) == 0);
-  ELIM (strnlen (p->a3_7[0], 1) < 2);
-  ELIM (strnlen (p->a3_7[0], 2) < 3);
-  ELIM (strnlen (p->a3_7[0], 3) < 4);
-  ELIM (strnlen (p->a3_7[0], 9) < 8);
-  ELIM (strnlen (p->a3_7[0], PTRDIFF_MAX) < 8);
-  ELIM (strnlen (p->a3_7[0], SIZE_MAX) < 8);
-  ELIM (strnlen (p->a3_7[0], -1) < 8);
-
-  ELIM (strnlen (p->a3_7[2], 0) == 0);
-  ELIM (strnlen (p->a3_7[2], 1) < 2);
-  ELIM (strnlen (p->a3_7[2], 2) < 3);
-  ELIM (strnlen (p->a3_7[2], 3) < 4);
-  ELIM (strnlen (p->a3_7[2], 9) < 8);
-  ELIM (strnlen (p->a3_7[2], PTRDIFF_MAX) < 8);
-  ELIM (strnlen (p->a3_7[2], SIZE_MAX) < 8);
-  ELIM (strnlen (p->a3_7[2], -1) < 8);
-
-  ELIM (strnlen (p->a3_7[i], 0) == 0);
-  ELIM (strnlen (p->a3_7[i], 1) < 2);
-  ELIM (strnlen (p->a3_7[i], 2) < 3);
-  ELIM (strnlen (p->a3_7[i], 3) < 4);
-
-#if 0
-  /* This is tranformed into strnlen ((char*)p + offsetof (a3_7[i]), N)
-     which makes it impssible to determine the size of the array.  */
-  ELIM (strnlen (p->a3_7[i], 9) < 8);
-  ELIM (strnlen (p->a3_7[i], PTRDIFF_MAX) < 8);
-  ELIM (strnlen (p->a3_7[i], SIZE_MAX) < 8);
-  ELIM (strnlen (p->a3_7[i], -1) < 8);
-#else
-  ELIM (strnlen (p->a3_7[i], 9) < 10);
-  ELIM (strnlen (p->a3_7[i], 19) < 20);
-#endif
-
-  ELIM (strnlen ((char*)p->a3_7, 0) == 0);
-  ELIM (strnlen ((char*)p->a3_7, 1) < 2);
-  ELIM (strnlen ((char*)p->a3_7, 2) < 3);
-  ELIM (strnlen ((char*)p->a3_7, 3) < 4);
-  ELIM (strnlen ((char*)p->a3_7, 9) < 10);
-  ELIM (strnlen ((char*)p->a3_7, 19) < 20);
-  ELIM (strnlen ((char*)p->a3_7, 21) < 22);
-  ELIM (strnlen ((char*)p->a3_7, 23) < 22);
-  ELIM (strnlen ((char*)p->a3_7, PTRDIFF_MAX) < 22);
-  ELIM (strnlen ((char*)p->a3_7, SIZE_MAX) < 22);
-  ELIM (strnlen ((char*)p->a3_7, -1) < 22);
-
-  ELIM (strnlen (p->ax, 0) == 0);
-  ELIM (strnlen (p->ax, 1) < 2);
-  ELIM (strnlen (p->ax, 2) < 3);
-  ELIM (strnlen (p->ax, 9) < 10);
-  ELIM (strnlen (p->a3, PTRDIFF_MAX) <= PTRDIFF_MAX);
-  ELIM (strnlen (p->a3, SIZE_MAX) < PTRDIFF_MAX);
-  ELIM (strnlen (p->a3, -1) < PTRDIFF_MAX);
+  ELIM (strnlen (ax, PTRDIFF_MAX) < PTRDIFF_MAX);
+  ELIM (strnlen (ax, SIZE_MAX) < PTRDIFF_MAX);
+  ELIM (strnlen (ax, -1) < PTRDIFF_MAX);
 }
 
 
index f64bc9bea79725b53151c513eb374a89598462fa..55fba88e0f4f7377735d54bb6a79388c90435f15 100644 (file)
@@ -1121,67 +1121,23 @@ adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
   update_stmt (last.stmt);
 }
 
-/* For an LHS that is an SSA_NAME and for strlen() or strnlen() argument
-   SRC, set LHS range info to [0, min (N, BOUND)] if SRC refers to
-   a character array A[N] with unknown length bounded by N, and for
-   strnlen(), by min (N, BOUND).  */
-
-static tree
-maybe_set_strlen_range (tree lhs, tree src, tree bound)
+/* For an LHS that is an SSA_NAME that is the result of a strlen()
+   call, or when BOUND is non-null, of a strnlen() call, set LHS
+   range info to [0, min (MAX, BOUND)] when the range includes more
+   than one value and return LHS.  Otherwise, when the range
+   [MIN, MAX] is such that MIN == MAX, return the tree representation
+   of (MIN). The latter allows callers to fold suitable strnlen() calls
+   to constants.  */
+
+tree
+set_strlen_range (tree lhs, wide_int max, tree bound /* = NULL_TREE */)
 {
   if (TREE_CODE (lhs) != SSA_NAME
       || !INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
     return NULL_TREE;
 
-  if (TREE_CODE (src) == SSA_NAME)
-    {
-      gimple *def = SSA_NAME_DEF_STMT (src);
-      if (is_gimple_assign (def)
-         && gimple_assign_rhs_code (def) == ADDR_EXPR)
-       src = gimple_assign_rhs1 (def);
-    }
-
-  wide_int max = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node));
   wide_int min = wi::zero (max.get_precision ());
 
-  if (TREE_CODE (src) == ADDR_EXPR)
-    {
-      /* The last array member of a struct can be bigger than its size
-        suggests if it's treated as a poor-man's flexible array member.  */
-      src = TREE_OPERAND (src, 0);
-      bool src_is_array = TREE_CODE (TREE_TYPE (src)) == ARRAY_TYPE;
-      if (src_is_array
-         && TREE_CODE (src) != MEM_REF
-         && !array_at_struct_end_p (src))
-       {
-         tree type = TREE_TYPE (src);
-         if (tree size = TYPE_SIZE_UNIT (type))
-           if (size && TREE_CODE (size) == INTEGER_CST)
-             max = wi::to_wide (size);
-
-         /* For strlen() the upper bound above is equal to
-            the longest string that can be stored in the array
-            (i.e., it accounts for the terminating nul.  For
-            strnlen() bump up the maximum by one since the array
-            need not be nul-terminated.  */
-         if (!bound && max != 0)
-           --max;
-       }
-      else
-       {
-         if (TREE_CODE (src) == COMPONENT_REF && !src_is_array)
-           src = TREE_OPERAND (src, 1);
-         if (DECL_P (src))
-           {
-             /* Handle the unlikely case of strlen (&c) where c is some
-                variable.  */
-             if (tree size = DECL_SIZE_UNIT (src))
-               if (TREE_CODE (size) == INTEGER_CST)
-                 max = wi::to_wide (size);
-           }
-       }
-    }
-
   if (bound)
     {
       /* For strnlen, adjust MIN and MAX as necessary.  If the bound
@@ -1205,7 +1161,7 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
            {
              /* For a bound in a known range, adjust the range determined
                 above as necessary.  For a bound in some anti-range or
-                in an unknown range, use the range determined above.  */
+                in an unknown range, use the range determined by callers.  */
              if (wi::ltu_p (minbound, min))
                min = minbound;
              if (wi::ltu_p (maxbound, max))
@@ -1221,6 +1177,79 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
   return lhs;
 }
 
+/* For an LHS that is an SSA_NAME and for strlen() or strnlen() argument
+   SRC, set LHS range info to [0, min (N, BOUND)] if SRC refers to
+   a character array A[N] with unknown length bounded by N, and for
+   strnlen(), by min (N, BOUND).  */
+
+static tree
+maybe_set_strlen_range (tree lhs, tree src, tree bound)
+{
+  if (TREE_CODE (lhs) != SSA_NAME
+      || !INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
+    return NULL_TREE;
+
+  if (TREE_CODE (src) == SSA_NAME)
+    {
+      gimple *def = SSA_NAME_DEF_STMT (src);
+      if (is_gimple_assign (def)
+         && gimple_assign_rhs_code (def) == ADDR_EXPR)
+       src = gimple_assign_rhs1 (def);
+    }
+
+  /* The longest string is PTRDIFF_MAX - 1 bytes including the final
+     NUL so that the difference between a pointer to just past it and
+     one to its beginning is positive.  */
+  wide_int max = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node)) - 2;
+
+  if (TREE_CODE (src) == ADDR_EXPR)
+    {
+      /* The last array member of a struct can be bigger than its size
+        suggests if it's treated as a poor-man's flexible array member.  */
+      src = TREE_OPERAND (src, 0);
+      if (TREE_CODE (src) != MEM_REF
+         && !array_at_struct_end_p (src))
+       {
+         tree type = TREE_TYPE (src);
+         tree size = TYPE_SIZE_UNIT (type);
+         if (size
+             && TREE_CODE (size) == INTEGER_CST
+             && !integer_zerop (size))
+           {
+             /* Even though such uses of strlen would be undefined,
+                avoid relying on arrays of arrays in case some genius
+                decides to call strlen on an unterminated array element
+                that's followed by a terminated one.  Likewise, avoid
+                assuming that a struct array member is necessarily
+                nul-terminated (the nul may be in the member that
+                follows).  In those cases, assume that the length
+                of the string stored in such an array is bounded
+                by the size of the enclosing object if one can be
+                determined.  */
+             tree base = get_base_address (src);
+             if (VAR_P (base))
+               {
+                 if (tree size = DECL_SIZE_UNIT (base))
+                   if (size
+                       && TREE_CODE (size) == INTEGER_CST
+                       && TREE_CODE (TREE_TYPE (base)) != POINTER_TYPE)
+                     max = wi::to_wide (size);
+               }
+           }
+
+         /* For strlen() the upper bound above is equal to
+            the longest string that can be stored in the array
+            (i.e., it accounts for the terminating nul.  For
+            strnlen() bump up the maximum by one since the array
+            need not be nul-terminated.  */
+         if (!bound && max != 0)
+           --max;
+       }
+    }
+
+  return set_strlen_range (lhs, max, bound);
+}
+
 /* Handle a strlen call.  If strlen of the argument is known, replace
    the strlen call with the known value, otherwise remember that strlen
    of the argument is stored in the lhs SSA_NAME.  */
index 6b1b819fffdd43b63bd87e133badc5422b23dc60..0b68465eb2babcc84c92874139de3dd973a36696 100644 (file)
@@ -23,5 +23,6 @@
 
 extern bool is_strlen_related_p (tree, tree);
 extern bool maybe_diag_stxncpy_trunc (gimple_stmt_iterator, tree, tree);
+extern tree set_strlen_range (tree, wide_int, tree = NULL_TREE);
 
 #endif   // GCC_TREE_SSA_STRLEN_H
This page took 0.121568 seconds and 5 git commands to generate.