builtins.h (c_strlen_data): Add new fields and comments.
authorMartin Sebor <msebor@redhat.com>
Sun, 23 Dec 2018 16:00:45 +0000 (16:00 +0000)
committerJeff Law <law@gcc.gnu.org>
Sun, 23 Dec 2018 16:00:45 +0000 (09:00 -0700)
* builtins.h (c_strlen_data): Add new fields and comments.
* builtins.c (unterminated_array): Change field reference from
"len" to "minlen" in c_strlen_data instance.
* gimple-fold.c (get_range_strlen): Likewise.
* gimple-ssa-sprintf.c (get_string_length): Likewise.

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

gcc/ChangeLog
gcc/builtins.c
gcc/builtins.h
gcc/gimple-fold.c
gcc/gimple-ssa-sprintf.c

index f1f9d70..cd2a294 100644 (file)
@@ -1,6 +1,12 @@
 2018-12-23  Martin Sebor  <msebor@redhat.com>
            Jeff Law  <law@redhat.com>
 
+       * builtins.h (c_strlen_data): Add new fields and comments.
+       * builtins.c (unterminated_array): Change field reference from
+       "len" to "minlen" in c_strlen_data instance.
+       * gimple-fold.c (get_range_strlen): Likewise.
+       * gimple-ssa-sprintf.c (get_string_length): Likewise.
+
        * builtins.c (unterminated_array): Rename "data" to "lendata".  Fix
        a few comments.
        (expand_builtin_strnlen, expand_builtin_stpcpy_1): Likewise.
index 0eb3df9..b56577e 100644 (file)
@@ -577,11 +577,11 @@ unterminated_array (tree exp, tree *size /* = NULL */, bool *exact /* = NULL */)
      structure if EXP references a unterminated array.  */
   c_strlen_data lendata = { };
   tree len = c_strlen (exp, 1, &lendata);
-  if (len == NULL_TREE && lendata.len && lendata.decl)
+  if (len == NULL_TREE && lendata.minlen && lendata.decl)
      {
        if (size)
        {
-         len = lendata.len;
+         len = lendata.minlen;
          if (lendata.off)
            {
              /* Constant offsets are already accounted for in LENDATA.MINLEN,
@@ -720,7 +720,7 @@ c_strlen (tree src, int only_value, c_strlen_data *data, unsigned eltsize)
        {
          data->decl = decl;
          data->off = byteoff;
-         data->len = ssize_int (len);
+         data->minlen = ssize_int (len);
          return NULL_TREE;
        }
 
@@ -794,7 +794,7 @@ c_strlen (tree src, int only_value, c_strlen_data *data, unsigned eltsize)
     {
       data->decl = decl;
       data->off = byteoff;
-      data->len = ssize_int (len);
+      data->minlen = ssize_int (len);
       return NULL_TREE;
     }
 
index cf4f9b1..472a86d 100644 (file)
@@ -57,10 +57,48 @@ extern bool get_pointer_alignment_1 (tree, unsigned int *,
                                     unsigned HOST_WIDE_INT *);
 extern unsigned int get_pointer_alignment (tree);
 extern unsigned string_length (const void*, unsigned, unsigned);
+
 struct c_strlen_data
 {
+  /* [MINLEN, MAXBOUND, MAXLEN] is a range describing the length of
+     one or more strings of possibly unknown length.  For a single
+     string of known length the range is a constant where
+     MINLEN == MAXBOUND == MAXLEN holds.
+     For other strings, MINLEN is the length of the shortest known
+     string.  MAXBOUND is the length of a string that could be stored
+     in the largest array referenced by the expression.  MAXLEN is
+     the length of the longest sequence of non-zero bytes
+     in an object referenced by the expression.  For such strings,
+     MINLEN <= MAXBOUND <= MAXLEN holds.  For example, given:
+       struct A { char a[7], b[]; };
+       extern struct A *p;
+       n = strlen (p->a);
+     the computed range will be [0, 6, ALL_ONES].
+     However, for a conditional expression involving a string
+     of known length and an array of unknown bound such as
+       n = strlen (i ? p->b : "123");
+     the range will be [3, 3, ALL_ONES].
+     MINLEN != 0 && MAXLEN == ALL_ONES indicates that MINLEN is
+     the length of the shortest known string and implies that
+     the shortest possible string referenced by the expression may
+     actually be the empty string.  This distinction is useful for
+     diagnostics.  get_range_strlen() return value distinguishes
+     between these two cases.
+     As the tighter (and more optimistic) bound, MAXBOUND is suitable
+     for diagnostics but not for optimization.
+     As the more conservative bound, MAXLEN is intended to be used
+     for optimization.  */
+  tree minlen;
+  tree maxlen;
+  tree maxbound;
+  /* When non-null, NONSTR refers to the declaration known to store
+     an unterminated constant character array, as in:
+     const char s[] = { 'a', 'b', 'c' };
+     It is used to diagnose uses of such arrays in functions such as
+     strlen() that expect a nul-terminated string as an argument.  */
   tree decl;
-  tree len;
+  /* Non-constant offset from the beginning of a string not accounted
+     for in the length range.  Used to improve diagnostics.  */
   tree off;
 };
 
index 0ba1514..b1dd441 100644 (file)
@@ -1343,8 +1343,8 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
          if (!val && lendata.decl)
            {
              *nonstr = lendata.decl;
-             *minlen = lendata.len;
-             *maxlen = lendata.len;
+             *minlen = lendata.minlen;
+             *maxlen = lendata.minlen;
              return type == 0 ? false : true;
            }
        }
index d627830..8284c76 100644 (file)
@@ -2015,12 +2015,12 @@ get_string_length (tree str, unsigned eltsize)
     }
   else if (!slen
           && data.decl
-          && data.len
-          && TREE_CODE (data.len) == INTEGER_CST)
+          && data.minlen
+          && TREE_CODE (data.minlen) == INTEGER_CST)
     {
       /* STR was not properly NUL terminated, but we have
         length information about the unterminated string.  */
-      fmtresult res (tree_to_shwi (data.len));
+      fmtresult res (tree_to_shwi (data.minlen));
       res.nonstr = data.decl;
       return res;
     }