PR tree-optimization/79352 - -fprintf-return-value doesn't handle flexible-like array...
authorMartin Sebor <msebor@redhat.com>
Fri, 3 Feb 2017 16:38:15 +0000 (16:38 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Fri, 3 Feb 2017 16:38:15 +0000 (09:38 -0700)
gcc/ChangeLog:

PR tree-optimization/79352
* gimple-fold.c (get_range_strlen): Add argument.
(get_range_strlen): Change return type to bool.
(get_maxval_strlen): Pass in a dummy argument.
* gimple-fold.h (get_range_strlen): Change return type to bool.
* gimple-ssa-sprintf.c (get_string_length): Set unlikely counter.
* tree.h (array_at_struct_end_p): Add argument.
* tree.c (array_at_struct_end_p): Handle it.

gcc/testsuite/ChangeLog:

PR tree-optimization/79352
* gcc.dg/tree-ssa/pr79352.c: New test.

From-SVN: r245156

gcc/ChangeLog
gcc/gimple-fold.c
gcc/gimple-fold.h
gcc/gimple-ssa-sprintf.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/pr79352.c [new file with mode: 0644]
gcc/tree.c
gcc/tree.h

index 269d6197e0600afa9b20eeef7397655824d8e05c..a8203a43b42225d2aa9f0a29546006779c527ed8 100644 (file)
@@ -1,3 +1,14 @@
+2017-02-03  Martin Sebor  <msebor@redhat.com>
+
+       PR tree-optimization/79352
+       * gimple-fold.c (get_range_strlen): Add argument.
+       (get_range_strlen): Change return type to bool.
+       (get_maxval_strlen): Pass in a dummy argument.
+       * gimple-fold.h (get_range_strlen): Change return type to bool.
+       * gimple-ssa-sprintf.c (get_string_length): Set unlikely counter.
+       * tree.h (array_at_struct_end_p): Add argument.
+       * tree.c (array_at_struct_end_p): Handle it.
+
 2017-02-03  Martin Liska  <mliska@suse.cz>
 
        PR lto/66295
index ef1afd10a0092723b11aa103f0fd1e3ea5939b9a..1cd22a8bfdd3cea1e72ca6aa57eb82c6dd8bac81 100644 (file)
@@ -1177,11 +1177,15 @@ gimple_fold_builtin_memset (gimple_stmt_iterator *gsi, tree c, tree len)
    length and 2 for maximum value ARG can have.
    When FUZZY is set and the length of a string cannot be determined,
    the function instead considers as the maximum possible length the
-   size of a character array it may refer to.  */
+   size of a character array it may refer to.
+   Set *FLEXP to true if the range of the string lengths has been
+   obtained from the upper bound of an array at the end of a struct.
+   Such an array may hold a string that's longer than its upper bound
+   due to it being used as a poor-man's flexible array member.  */
 
 static bool
 get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
-                 bool fuzzy)
+                 bool fuzzy, bool *flexp)
 {
   tree var, val;
   gimple *def_stmt;
@@ -1202,7 +1206,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
          if (TREE_CODE (aop0) == INDIRECT_REF
              && TREE_CODE (TREE_OPERAND (aop0, 0)) == SSA_NAME)
            return get_range_strlen (TREE_OPERAND (aop0, 0),
-                                    length, visited, type, fuzzy);
+                                    length, visited, type, fuzzy, flexp);
        }
 
       if (type == 2)
@@ -1219,7 +1223,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
        {
          if (TREE_CODE (arg) == ADDR_EXPR)
            return get_range_strlen (TREE_OPERAND (arg, 0), length,
-                                    visited, type, fuzzy);
+                                    visited, type, fuzzy, flexp);
 
          if (TREE_CODE (arg) == COMPONENT_REF
              && TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 1))) == ARRAY_TYPE)
@@ -1228,7 +1232,12 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
                 bound on the length of the array.  This may be overly
                 optimistic if the array itself isn't NUL-terminated and
                 the caller relies on the subsequent member to contain
-                the NUL.  */
+                the NUL.
+                Set *FLEXP to true if the array whose bound is being
+                used is at the end of a struct.  */
+             if (array_at_struct_end_p (arg, true))
+               *flexp = true;
+
              arg = TREE_OPERAND (arg, 1);
              val = TYPE_SIZE_UNIT (TREE_TYPE (arg));
              if (!val || integer_zerop (val))
@@ -1295,14 +1304,14 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
             || gimple_assign_unary_nop_p (def_stmt))
           {
             tree rhs = gimple_assign_rhs1 (def_stmt);
-           return get_range_strlen (rhs, length, visited, type, fuzzy);
+           return get_range_strlen (rhs, length, visited, type, fuzzy, flexp);
           }
        else if (gimple_assign_rhs_code (def_stmt) == COND_EXPR)
          {
            tree op2 = gimple_assign_rhs2 (def_stmt);
            tree op3 = gimple_assign_rhs3 (def_stmt);
-           return get_range_strlen (op2, length, visited, type, fuzzy)
-             && get_range_strlen (op3, length, visited, type, fuzzy);
+           return get_range_strlen (op2, length, visited, type, fuzzy, flexp)
+             && get_range_strlen (op3, length, visited, type, fuzzy, flexp);
           }
         return false;
 
@@ -1325,7 +1334,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
             if (arg == gimple_phi_result (def_stmt))
               continue;
 
-           if (!get_range_strlen (arg, length, visited, type, fuzzy))
+           if (!get_range_strlen (arg, length, visited, type, fuzzy, flexp))
              {
                if (fuzzy)
                  *maxlen = build_all_ones_cst (size_type_node);
@@ -1349,19 +1358,26 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
    and array declared as 'char array[8]', MINMAXLEN[0] will be set
    to 3 and MINMAXLEN[1] to 7, the longest string that could be
    stored in array.
-*/
+   Return true if the range of the string lengths has been obtained
+   from the upper bound of an array at the end of a struct.  Such
+   an array may hold a string that's longer than its upper bound
+   due to it being used as a poor-man's flexible array member.  */
 
-void get_range_strlen (tree arg, tree minmaxlen[2])
+bool
+get_range_strlen (tree arg, tree minmaxlen[2])
 {
   bitmap visited = NULL;
 
   minmaxlen[0] = NULL_TREE;
   minmaxlen[1] = NULL_TREE;
 
-  get_range_strlen (arg, minmaxlen, &visited, 1, true);
+  bool flexarray = false;
+  get_range_strlen (arg, minmaxlen, &visited, 1, true, &flexarray);
 
   if (visited)
     BITMAP_FREE (visited);
+
+  return flexarray;
 }
 
 tree
@@ -1369,7 +1385,9 @@ get_maxval_strlen (tree arg, int type)
 {
   bitmap visited = NULL;
   tree len[2] = { NULL_TREE, NULL_TREE };
-  if (!get_range_strlen (arg, len, &visited, type, false))
+
+  bool dummy;
+  if (!get_range_strlen (arg, len, &visited, type, false, &dummy))
     len[1] = NULL_TREE;
   if (visited)
     BITMAP_FREE (visited);
index 38fb8e74e4d8c9d05bdd4f004f3f9d0651609120..e4931a1af52c233bd1137a5e4f9a797cbb11c9e8 100644 (file)
@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 
 extern tree canonicalize_constructor_val (tree, tree);
 extern tree get_symbol_constant_value (tree);
-extern void get_range_strlen (tree, tree[2]);
+extern bool get_range_strlen (tree, tree[2]);
 extern tree get_maxval_strlen (tree, int);
 extern void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree);
 extern bool fold_stmt (gimple_stmt_iterator *);
index 10c6d8e97198836ebab86aca6a1b51decaace5f9..3670bacd1f98910a5ffd7479e1e002bda605c1eb 100644 (file)
@@ -1800,7 +1800,7 @@ get_string_length (tree str)
      aren't known to point any such arrays result in LENRANGE[1] set
      to SIZE_MAX.  */
   tree lenrange[2];
-  get_range_strlen (str, lenrange);
+  bool flexarray = get_range_strlen (str, lenrange);
 
   if (lenrange [0] || lenrange [1])
     {
@@ -1843,7 +1843,11 @@ get_string_length (tree str)
          res.range.min = 0;
        }
 
-      res.range.unlikely = res.range.max;
+      /* If the range of string length has been estimated from the size
+        of an array at the end of a struct assume that it's longer than
+        the array bound says it is in case it's used as a poor man's
+        flexible array member, such as in struct S { char a[4]; };  */
+      res.range.unlikely = flexarray ? HOST_WIDE_INT_MAX : res.range.max;
 
       return res;
     }
index c5e31c7527929eb92d21bb03b754511ce82fe65a..ff8ce70fed24cbaf61e3137d8da36a987afcf49e 100644 (file)
@@ -1,3 +1,8 @@
+2017-02-03  Martin Sebor  <msebor@redhat.com>
+
+       PR tree-optimization/79352
+       * gcc.dg/tree-ssa/pr79352.c: New test.
+
 2017-02-03  Martin Liska  <mliska@suse.cz>
 
        PR lto/66295
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr79352.c b/gcc/testsuite/gcc.dg/tree-ssa/pr79352.c
new file mode 100644 (file)
index 0000000..4a153b7
--- /dev/null
@@ -0,0 +1,45 @@
+/* PR tree-optimization/79352 - -fprintf-return-value doesn't handle
+   flexible-like array members properly
+   { dg-compile }
+   { dg-options "-O2 -fdump-tree-optimized" } */
+
+struct A { int i; char a1[1]; };
+struct B { int i; char a3[3]; };
+struct C { int i; char ax[]; };
+
+int test_array_1 (int i, struct A *a)
+{
+  return __builtin_snprintf (0, 0, "%-s", a->a1);
+}
+
+int test_array_3 (int i, struct B *b)
+{
+  return __builtin_snprintf (0, 0, "%-s", b->a3);
+}
+
+int test_array_1_3 (int i, struct A *a, struct B *b)
+{
+  return __builtin_snprintf (0, 0, "%-s", i ? a->a1 : b->a3);
+}
+
+int test_string_and_array_3 (int i, struct B *b)
+{
+  return __builtin_snprintf (0, 0, "%-s", i ? "123" : b->a3);
+}
+
+int test_flexarray (struct C *c)
+{
+  return __builtin_snprintf (0, 0, "%-s", c->ax);
+}
+
+int test_array_and_flexarray (int i, struct B *b, struct C *c)
+{
+  return __builtin_snprintf (0, 0, "%-s", i ? b->a3 : c->ax);
+}
+
+int test_string_and_flexarray (int i, struct C *c)
+{
+  return __builtin_snprintf (0, 0, "%-s", i ? "123" : c->ax);
+}
+
+/* { dg-final { scan-tree-dump-times "snprintf" 7 "optimized"} } */
index 8426834342e320fc6e91de55c963c2b1c83cfcb8..804ab5ed58a95a40c09fb7229df50fc1e51e6d5a 100644 (file)
@@ -13195,13 +13195,16 @@ array_ref_up_bound (tree exp)
 
 /* Returns true if REF is an array reference to an array at the end of
    a structure.  If this is the case, the array may be allocated larger
-   than its upper bound implies.  */
+   than its upper bound implies.  When ALLOW_COMPREF is true considers
+   REF when it's a COMPONENT_REF in addition ARRAY_REF and
+   ARRAY_RANGE_REF.  */
 
 bool
-array_at_struct_end_p (tree ref)
+array_at_struct_end_p (tree ref, bool allow_compref)
 {
   if (TREE_CODE (ref) != ARRAY_REF
-      && TREE_CODE (ref) != ARRAY_RANGE_REF)
+      && TREE_CODE (ref) != ARRAY_RANGE_REF
+      && (!allow_compref || TREE_CODE (ref) != COMPONENT_REF))
     return false;
 
   while (handled_component_p (ref))
index 6341446245d54f78431e69337fff5f5f060e808a..f63a678216e411086e5c6da1aba7430eb5204bef 100644 (file)
@@ -4855,8 +4855,10 @@ extern tree array_ref_low_bound (tree);
 
 /* Returns true if REF is an array reference to an array at the end of
    a structure.  If this is the case, the array may be allocated larger
-   than its upper bound implies.  */
-extern bool array_at_struct_end_p (tree);
+   than its upper bound implies.  When second argument is true considers
+   REF when it's a COMPONENT_REF in addition ARRAY_REF and
+   ARRAY_RANGE_REF.  */
+extern bool array_at_struct_end_p (tree, bool = false);
 
 /* Return a tree representing the offset, in bytes, of the field referenced
    by EXP.  This does not include any offset in DECL_FIELD_BIT_OFFSET.  */