]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Avoid assuming maximum string length is constant [PR102960].
authorMartin Sebor <msebor@redhat.com>
Tue, 16 Nov 2021 16:18:25 +0000 (09:18 -0700)
committerMartin Sebor <msebor@redhat.com>
Tue, 16 Nov 2021 16:18:25 +0000 (09:18 -0700)
Resolves:
PR tree-optimization/102960 - ICE: in sign_mask, at wide-int.h:855 in GCC 10.3.0

gcc/ChangeLog:

PR tree-optimization/102960
* gimple-fold.c (get_range_strlen): Take bitmap as an argument rather
than a pointer to it.
(get_range_strlen_tree): Same.  Remove bitmap allocation.  Use
an auto_bitmap.
(get_maxval_strlen): Use an auto_bitmap.
* tree-ssa-strlen.c (get_range_strlen_dynamic): Factor out PHI
handling...
(get_range_strlen_phi): ...into this function.
Avoid assuming maximum string length is constant
(printf_strlen_execute): Dump pointer query cache contents when
details are requisted.

gcc/testsuite/ChangeLog:

PR tree-optimization/102960
* gcc.dg/Wstringop-overflow-84.c: New test.

gcc/gimple-fold.c
gcc/testsuite/gcc.dg/Wstringop-overflow-84.c [new file with mode: 0644]
gcc/tree-ssa-strlen.c

index 765726cf921586ae87fc2c4ff01287f062a001fe..ad9703ee471e548ece5427ced36a92c3a7c96264 100644 (file)
@@ -86,7 +86,7 @@ enum strlen_range_kind {
 };
 
 static bool
-get_range_strlen (tree, bitmap *, strlen_range_kind, c_strlen_data *, unsigned);
+get_range_strlen (tree, bitmap, strlen_range_kind, c_strlen_data *, unsigned);
 
 /* Return true when DECL can be referenced from current unit.
    FROM_DECL (if non-null) specify constructor of variable DECL was taken from.
@@ -1525,7 +1525,7 @@ gimple_fold_builtin_memset (gimple_stmt_iterator *gsi, tree c, tree len)
 /* Helper of get_range_strlen for ARG that is not an SSA_NAME.  */
 
 static bool
-get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind,
+get_range_strlen_tree (tree arg, bitmap visited, strlen_range_kind rkind,
                       c_strlen_data *pdata, unsigned eltsize)
 {
   gcc_assert (TREE_CODE (arg) != SSA_NAME);
@@ -1849,7 +1849,7 @@ get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind,
    Return true if *PDATA was successfully populated and false otherwise.  */
 
 static bool
-get_range_strlen (tree arg, bitmap *visited,
+get_range_strlen (tree arg, bitmap visited,
                  strlen_range_kind rkind,
                  c_strlen_data *pdata, unsigned eltsize)
 {
@@ -1863,9 +1863,7 @@ get_range_strlen (tree arg, bitmap *visited,
     return false;
 
   /* If we were already here, break the infinite cycle.  */
-  if (!*visited)
-    *visited = BITMAP_ALLOC (NULL);
-  if (!bitmap_set_bit (*visited, SSA_NAME_VERSION (arg)))
+  if (!bitmap_set_bit (visited, SSA_NAME_VERSION (arg)))
     return true;
 
   tree var = arg;
@@ -1962,10 +1960,10 @@ get_range_strlen (tree arg, bitmap *visited,
 bool
 get_range_strlen (tree arg, c_strlen_data *pdata, unsigned eltsize)
 {
-  bitmap visited = NULL;
+  auto_bitmap visited;
   tree maxbound = pdata->maxbound;
 
-  if (!get_range_strlen (arg, &visited, SRK_LENRANGE, pdata, eltsize))
+  if (!get_range_strlen (arg, visited, SRK_LENRANGE, pdata, eltsize))
     {
       /* On failure extend the length range to an impossible maximum
         (a valid MAXLEN must be less than PTRDIFF_MAX - 1).  Other
@@ -1981,9 +1979,6 @@ get_range_strlen (tree arg, c_strlen_data *pdata, unsigned eltsize)
   if (maxbound && pdata->maxbound == maxbound)
     pdata->maxbound = build_all_ones_cst (size_type_node);
 
-  if (visited)
-    BITMAP_FREE (visited);
-
   return !integer_all_onesp (pdata->maxlen);
 }
 
@@ -2005,19 +2000,16 @@ get_maxval_strlen (tree arg, strlen_range_kind rkind, tree *nonstr = NULL)
   /* ARG must have an integral type when RKIND says so.  */
   gcc_assert (rkind != SRK_INT_VALUE || INTEGRAL_TYPE_P (TREE_TYPE (arg)));
 
-  bitmap visited = NULL;
+  auto_bitmap visited;
 
   /* Reset DATA.MAXLEN if the call fails or when DATA.MAXLEN
      is unbounded.  */
   c_strlen_data lendata = { };
-  if (!get_range_strlen (arg, &visited, rkind, &lendata, /* eltsize = */1))
+  if (!get_range_strlen (arg, visited, rkind, &lendata, /* eltsize = */1))
     lendata.maxlen = NULL_TREE;
   else if (lendata.maxlen && integer_all_onesp (lendata.maxlen))
     lendata.maxlen = NULL_TREE;
 
-  if (visited)
-    BITMAP_FREE (visited);
-
   if (nonstr)
     {
       /* For callers prepared to handle unterminated arrays set
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-84.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-84.c
new file mode 100644 (file)
index 0000000..2c0f507
--- /dev/null
@@ -0,0 +1,15 @@
+/* PR middle-end/102960 - ICE: in sign_mask, at wide-int.h:855 in GCC 10.3.0
+   { dg-do compile }
+   { dg-options "-Og -Wall" } */
+
+void f (int i)
+{
+  const char *s;
+  if (i)
+    s = &"abcd"[i];
+
+  __builtin_printf ("%s", s);
+}
+
+/* The use of s in the call to sprintf should result in:
+   { dg-prune-output "-Wmaybe-uninitialized" } */
index c0ec7d20a6082b8264adfce8dba358ff989e00f3..536f796f82bd7b9d72ff05a61a4ecb7d55273562 100644 (file)
@@ -193,6 +193,8 @@ struct laststmt_struct
 } laststmt;
 
 static int get_stridx_plus_constant (strinfo *, unsigned HOST_WIDE_INT, tree);
+static bool get_range_strlen_dynamic (tree, gimple *s, c_strlen_data *,
+                                     bitmap, range_query *, unsigned *);
 
 /* Sets MINMAX to either the constant value or the range VAL is in
    and returns either the constant value or VAL on success or null
@@ -1087,6 +1089,76 @@ dump_strlen_info (FILE *fp, gimple *stmt, range_query *rvals)
     }
 }
 
+/* Helper of get_range_strlen_dynamic().  See below.  */
+
+static bool
+get_range_strlen_phi (tree src, gphi *phi,
+                     c_strlen_data *pdata, bitmap visited,
+                     range_query *rvals, unsigned *pssa_def_max)
+{
+  if (!bitmap_set_bit (visited, SSA_NAME_VERSION (src)))
+    return true;
+
+  if (*pssa_def_max == 0)
+    return false;
+
+  --*pssa_def_max;
+
+  /* Iterate over the PHI arguments and determine the minimum and maximum
+     length/size of each and incorporate them into the overall result.  */
+  for (unsigned i = 0; i != gimple_phi_num_args (phi); ++i)
+    {
+      tree arg = gimple_phi_arg_def (phi, i);
+      if (arg == gimple_phi_result (phi))
+       continue;
+
+      c_strlen_data argdata = { };
+      if (!get_range_strlen_dynamic (arg, phi, &argdata, visited, rvals,
+                                    pssa_def_max))
+       {
+         pdata->maxlen = build_all_ones_cst (size_type_node);
+         continue;
+       }
+
+      /* Set the DECL of an unterminated array this argument refers to
+        if one hasn't been found yet.  */
+      if (!pdata->decl && argdata.decl)
+       pdata->decl = argdata.decl;
+
+      if (!argdata.minlen
+         || (integer_zerop (argdata.minlen)
+             && (!argdata.maxbound
+                 || integer_all_onesp (argdata.maxbound))
+             && integer_all_onesp (argdata.maxlen)))
+       {
+         /* Set the upper bound of the length to unbounded.  */
+         pdata->maxlen = build_all_ones_cst (size_type_node);
+         continue;
+       }
+
+      /* Adjust the minimum and maximum length determined so far and
+        the upper bound on the array size.  */
+      if (!pdata->minlen
+         || tree_int_cst_lt (argdata.minlen, pdata->minlen))
+       pdata->minlen = argdata.minlen;
+
+      if (!pdata->maxlen
+         || (argdata.maxlen
+             && TREE_CODE (argdata.maxlen) == INTEGER_CST
+             && tree_int_cst_lt (pdata->maxlen, argdata.maxlen)))
+       pdata->maxlen = argdata.maxlen;
+
+      if (!pdata->maxbound
+         || TREE_CODE (pdata->maxbound) != INTEGER_CST
+         || (argdata.maxbound
+             && tree_int_cst_lt (pdata->maxbound, argdata.maxbound)
+             && !integer_all_onesp (argdata.maxbound)))
+       pdata->maxbound = argdata.maxbound;
+    }
+
+  return true;
+}
+
 /* Attempt to determine the length of the string SRC.  On success, store
    the length in *PDATA and return true.  Otherwise, return false.
    VISITED is a bitmap of visited PHI nodes.  RVALS points to the valuation
@@ -1095,7 +1167,7 @@ dump_strlen_info (FILE *fp, gimple *stmt, range_query *rvals)
 
 static bool
 get_range_strlen_dynamic (tree src, gimple *stmt,
-                         c_strlen_data *pdata, bitmap *visited,
+                         c_strlen_data *pdata, bitmap visited,
                          range_query *rvals, unsigned *pssa_def_max)
 {
   int idx = get_stridx (src, stmt);
@@ -1104,72 +1176,9 @@ get_range_strlen_dynamic (tree src, gimple *stmt,
       if (TREE_CODE (src) == SSA_NAME)
        {
          gimple *def_stmt = SSA_NAME_DEF_STMT (src);
-         if (gimple_code (def_stmt) == GIMPLE_PHI)
-           {
-             if (!*visited)
-               *visited = BITMAP_ALLOC (NULL);
-
-             if (!bitmap_set_bit (*visited, SSA_NAME_VERSION (src)))
-               return true;
-
-             if (*pssa_def_max == 0)
-               return false;
-
-             --*pssa_def_max;
-
-             /* Iterate over the PHI arguments and determine the minimum
-                and maximum length/size of each and incorporate them into
-                the overall result.  */
-             gphi *phi = as_a <gphi *> (def_stmt);
-             for (unsigned i = 0; i != gimple_phi_num_args (phi); ++i)
-               {
-                 tree arg = gimple_phi_arg_def (phi, i);
-                 if (arg == gimple_phi_result (def_stmt))
-                   continue;
-
-                 c_strlen_data argdata = { };
-                 if (get_range_strlen_dynamic (arg, phi, &argdata, visited,
-                                               rvals, pssa_def_max))
-                   {
-                     /* Set the DECL of an unterminated array this argument
-                        refers to if one hasn't been found yet.  */
-                     if (!pdata->decl && argdata.decl)
-                       pdata->decl = argdata.decl;
-
-                     if (!argdata.minlen
-                         || (integer_zerop (argdata.minlen)
-                             && (!argdata.maxbound
-                                 || integer_all_onesp (argdata.maxbound))
-                             && integer_all_onesp (argdata.maxlen)))
-                       {
-                         /* Set the upper bound of the length to unbounded.  */
-                         pdata->maxlen = build_all_ones_cst (size_type_node);
-                         continue;
-                       }
-
-                     /* Adjust the minimum and maximum length determined
-                        so far and the upper bound on the array size.  */
-                     if (!pdata->minlen
-                         || tree_int_cst_lt (argdata.minlen, pdata->minlen))
-                       pdata->minlen = argdata.minlen;
-                     if (!pdata->maxlen
-                         || (argdata.maxlen
-                             && tree_int_cst_lt (pdata->maxlen, argdata.maxlen)))
-                       pdata->maxlen = argdata.maxlen;
-                     if (!pdata->maxbound
-                         || TREE_CODE (pdata->maxbound) != INTEGER_CST
-                         || (argdata.maxbound
-                             && tree_int_cst_lt (pdata->maxbound,
-                                                 argdata.maxbound)
-                             && !integer_all_onesp (argdata.maxbound)))
-                       pdata->maxbound = argdata.maxbound;
-                   }
-                 else
-                   pdata->maxlen = build_all_ones_cst (size_type_node);
-               }
-
-             return true;
-           }
+         if (gphi *phi = dyn_cast<gphi *>(def_stmt))
+           return get_range_strlen_phi (src, phi, pdata, visited, rvals,
+                                        pssa_def_max);
        }
 
       /* Return success regardless of the result and handle *PDATA
@@ -1286,11 +1295,11 @@ void
 get_range_strlen_dynamic (tree src, gimple *stmt, c_strlen_data *pdata,
                          range_query *rvals)
 {
-  bitmap visited = NULL;
+  auto_bitmap visited;
   tree maxbound = pdata->maxbound;
 
   unsigned limit = param_ssa_name_def_chain_limit;
-  if (!get_range_strlen_dynamic (src, stmt, pdata, &visited, rvals, &limit))
+  if (!get_range_strlen_dynamic (src, stmt, pdata, visited, rvals, &limit))
     {
       /* On failure extend the length range to an impossible maximum
         (a valid MAXLEN must be less than PTRDIFF_MAX - 1).  Other
@@ -1305,9 +1314,6 @@ get_range_strlen_dynamic (tree src, gimple *stmt, c_strlen_data *pdata,
      MAXBOUND to SIZE_MAX.  Otherwise leave it null (if it is null).  */
   if (maxbound && pdata->maxbound == maxbound)
     pdata->maxbound = build_all_ones_cst (size_type_node);
-
-  if (visited)
-    BITMAP_FREE (visited);
 }
 
 /* Invalidate string length information for strings whose length might
@@ -5831,7 +5837,7 @@ printf_strlen_execute (function *fun, bool warn_only)
   walker.walk (ENTRY_BLOCK_PTR_FOR_FN (fun));
 
   if (dump_file && (dump_flags & TDF_DETAILS))
-    walker.ptr_qry.dump (dump_file);
+    walker.ptr_qry.dump (dump_file, true);
 
   ssa_ver_to_stridx.release ();
   strinfo_pool.release ();