builtins.h (c_srlen): Add argument.
authorMartin Sebor <msebor@redhat.com>
Fri, 14 Sep 2018 03:34:19 +0000 (03:34 +0000)
committerJeff Law <law@gcc.gnu.org>
Fri, 14 Sep 2018 03:34:19 +0000 (21:34 -0600)
* builtins.h (c_srlen): Add argument.
* builtins.c (warn_string_no_nul): New function.
(c_strlen): Add argument and use it.  Update recursive calls.
Pass DECL argument to string_constant to get info on non
terminated strings.  Update *NONSTR as needed.
(fold_builtin_strlen): Add argument to calls to c_strlen.
Warn for unterminated arrays.
(warn_string_no_null): Add prototype.
* expr.c (string_constant): Update arguments.  Update recursive
calls appropriately.  Detect missing NUL terminator and outermost
declaration its missing in.
Improve checks for arrays with nonzero lower bound or elements
that are not a single byte.  Simplify offset computation.
Simplify checks for non-NUL terminated strings.
* gimple-fold.c (get_range_strlen): Add argument to c_strlen call.
* gimple-ssa-sprintf.c (get_string_length): Remove unnecessary code.

* gcc.dg/warn-strlen-no-nul.c: New test.

Co-Authored-By: Bernd Edlinger <bernd.edlinger@hotmail.de>
Co-Authored-By: Jeff Law <law@redhat.com>
From-SVN: r264302

gcc/ChangeLog
gcc/builtins.c
gcc/builtins.h
gcc/expr.c
gcc/fold-const.c
gcc/gimple-fold.c
gcc/gimple-ssa-sprintf.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/warn-strlen-no-nul.c [new file with mode: 0644]
gcc/tree-ssa-strlen.c

index 038aa27f8ede5bea3aaac70eebb40710d0ffa050..4ef577f82f16d404a4642c7c0bcf984b3fdbc450 100644 (file)
@@ -1,3 +1,23 @@
+2018-09-13  Martin Sebor  <msebor@redhat.com>
+           Bernd Edlinger  <bernd.edlinger@hotmail.de>
+
+       * builtins.h (c_srlen): Add argument.
+       * builtins.c (warn_string_no_nul): New function.
+       (c_strlen): Add argument and use it.  Update recursive calls.
+       Pass DECL argument to string_constant to get info on non
+       terminated strings.  Update *NONSTR as needed.
+       (fold_builtin_strlen): Add argument to calls to c_strlen.
+       Warn for unterminated arrays.
+       (warn_string_no_null): Add prototype.
+       * expr.c (string_constant): Update arguments.  Update recursive
+       calls appropriately.  Detect missing NUL terminator and outermost
+       declaration its missing in.
+       Improve checks for arrays with nonzero lower bound or elements
+       that are not a single byte.  Simplify offset computation.
+       Simplify checks for non-NUL terminated strings.
+       * gimple-fold.c (get_range_strlen): Add argument to c_strlen call.
+       * gimple-ssa-sprintf.c (get_string_length): Remove unnecessary code.
+
 2018-09-13  Bernd Edlinger  <bernd.edlinger@hotmail.de>
 
        * builtins.c (c_strlen): Handle not zero terminated STRING_CSTs
index bef3ad2850997f616ceaa32cec026f3fbe02fc92..a345704a8f8e5aceea106a1649db4bc8f620eba4 100644 (file)
@@ -542,6 +542,27 @@ string_length (const void *ptr, unsigned eltsize, unsigned maxelts)
   return n;
 }
 
+/* For a call at LOC to a function FN that expects a string in the argument
+   ARG, issue a diagnostic due to it being a called with an argument
+   declared at NONSTR that is a character array with no terminating NUL.  */
+
+void
+warn_string_no_nul (location_t loc, const char *fn, tree arg, tree decl)
+{
+  if (TREE_NO_WARNING (arg))
+    return;
+
+  loc = expansion_point_location_if_in_system_header (loc);
+
+  if (warning_at (loc, OPT_Wstringop_overflow_,
+                 "%qs argument missing terminating nul", fn))
+    {
+      inform (DECL_SOURCE_LOCATION (decl),
+             "referenced argument declared here");
+      TREE_NO_WARNING (arg) = 1;
+    }
+}
+
 /* Compute the length of a null-terminated character string or wide
    character string handling character sizes of 1, 2, and 4 bytes.
    TREE_STRING_LENGTH is not the right way because it evaluates to
@@ -559,13 +580,18 @@ string_length (const void *ptr, unsigned eltsize, unsigned maxelts)
    accesses.  Note that this implies the result is not going to be emitted
    into the instruction stream.
 
+   If a not zero-terminated string value is encountered and NONSTR is
+   non-zero, the declaration of the string value is assigned to *NONSTR.
+   *NONSTR is accumulating, thus not cleared on success, therefore it has
+   to be initialized to NULL_TREE by the caller.
+
    ELTSIZE is 1 for normal single byte character strings, and 2 or
    4 for wide characer strings.  ELTSIZE is by default 1.
 
    The value returned is of type `ssizetype'.  */
 
 tree
-c_strlen (tree src, int only_value, unsigned eltsize)
+c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize)
 {
   gcc_checking_assert (eltsize == 1 || eltsize == 2 || eltsize == 4);
   STRIP_NOPS (src);
@@ -574,22 +600,23 @@ c_strlen (tree src, int only_value, unsigned eltsize)
     {
       tree len1, len2;
 
-      len1 = c_strlen (TREE_OPERAND (src, 1), only_value, eltsize);
-      len2 = c_strlen (TREE_OPERAND (src, 2), only_value, eltsize);
+      len1 = c_strlen (TREE_OPERAND (src, 1), only_value, nonstr, eltsize);
+      len2 = c_strlen (TREE_OPERAND (src, 2), only_value, nonstr, eltsize);
       if (tree_int_cst_equal (len1, len2))
        return len1;
     }
 
   if (TREE_CODE (src) == COMPOUND_EXPR
       && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
-    return c_strlen (TREE_OPERAND (src, 1), only_value, eltsize);
+    return c_strlen (TREE_OPERAND (src, 1), only_value, nonstr, eltsize);
 
   location_t loc = EXPR_LOC_OR_LOC (src, input_location);
 
   /* Offset from the beginning of the string in bytes.  */
   tree byteoff;
   tree memsize;
-  src = string_constant (src, &byteoff, &memsize, NULL);
+  tree decl;
+  src = string_constant (src, &byteoff, &memsize, &decl);
   if (src == 0)
     return NULL_TREE;
 
@@ -628,8 +655,14 @@ c_strlen (tree src, int only_value, unsigned eltsize)
       unsigned len = string_length (ptr, eltsize, strelts);
 
       /* Return when an embedded null character is found or none at all.  */
-      if (len + 1 < strelts || len >= maxelts)
+      if (len + 1 < strelts)
        return NULL_TREE;
+      else if (len >= maxelts)
+       {
+         if (nonstr && decl)
+           *nonstr = decl;
+         return NULL_TREE;
+       }
 
       /* For empty strings the result should be zero.  */
       if (len == 0)
@@ -694,7 +727,11 @@ c_strlen (tree src, int only_value, unsigned eltsize)
   /* Don't know what to return if there was no zero termination.
      Ideally this would turn into a gcc_checking_assert over time.  */
   if (len >= maxelts - eltoff)
-    return NULL_TREE;
+    {
+      if (nonstr && decl)
+       *nonstr = decl;
+      return NULL_TREE;
+    }
 
   return ssize_int (len);
 }
@@ -8373,11 +8410,24 @@ fold_builtin_strlen (location_t loc, tree type, tree arg)
     return NULL_TREE;
   else
     {
-      tree len = c_strlen (arg, 0);
+      tree nonstr = NULL_TREE;
+      tree len = c_strlen (arg, 0, &nonstr);
 
       if (len)
        return fold_convert_loc (loc, type, len);
 
+      if (!nonstr)
+       c_strlen (arg, 1, &nonstr); /* TODO: add test coverage here.  */
+
+      if (nonstr)
+       {
+         if (EXPR_HAS_LOCATION (arg))
+           loc = EXPR_LOCATION (arg);
+         else if (loc == UNKNOWN_LOCATION)
+           loc = input_location;
+         warn_string_no_nul (loc, "strlen", arg, nonstr);
+       }
+
       return NULL_TREE;
     }
 }
index c3d5ccbb6b6e61a8162de880772e94fba46ace51..7790c85a508ed2b0599680b9aa64a06d720304f7 100644 (file)
@@ -57,7 +57,7 @@ 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);
-extern tree c_strlen (tree, int, unsigned = 1);
+extern tree c_strlen (tree, int, tree * = NULL, unsigned = 1);
 extern void expand_builtin_setjmp_setup (rtx, rtx);
 extern void expand_builtin_setjmp_receiver (rtx);
 extern void expand_builtin_update_setjmp_buf (rtx);
@@ -103,6 +103,7 @@ extern bool target_char_cst_p (tree t, char *p);
 extern internal_fn associated_internal_fn (tree);
 extern internal_fn replacement_internal_fn (gcall *);
 
+extern void warn_string_no_nul (location_t, const char *, tree, tree);
 extern tree max_object_size ();
 
 #endif /* GCC_BUILTINS_H */
index 2d9a9eb90c3c06e33cb1dbc66044ddb0e166b0bf..67aa0520e4432a5d05a14a820b1e7b91ace03157 100644 (file)
@@ -11303,16 +11303,11 @@ is_aligning_offset (const_tree offset, const_tree exp)
 /* Return the tree node if an ARG corresponds to a string constant or zero
    if it doesn't.  If we return nonzero, set *PTR_OFFSET to the (possibly
    non-constant) offset in bytes within the string that ARG is accessing.
-   If NONSTR is non-null, consider valid even sequences of characters that
-   aren't nul-terminated strings.  In that case, if ARG refers to such
-   a sequence set *NONSTR to its declaration and clear it otherwise.
-   The type of the offset is sizetype.  If MEM_SIZE is non-zero the storage
-   size of the memory is returned.  The returned STRING_CST object is
-   valid up to TREE_STRING_LENGTH.  Bytes between TREE_STRING_LENGTH
-   and MEM_SIZE are zero.  MEM_SIZE is at least TREE_STRING_LENGTH.  */
+   If MEM_SIZE is non-zero the storage size of the memory is returned.
+   If DECL is non-zero the constant declaration is returned if available.  */
 
 tree
-string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *nonstr)
+string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
 {
   tree array;
   STRIP_NOPS (arg);
@@ -11341,6 +11336,12 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *nonstr)
 
              if (TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE)
                return NULL_TREE;
+
+             if (!integer_zerop (array_ref_low_bound (arg)))
+               return NULL_TREE;
+
+             if (!integer_onep (array_ref_element_size (arg)))
+               return NULL_TREE;
            }
        }
       array = get_addr_base_and_unit_offset (ref, &base_off);
@@ -11366,7 +11367,7 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *nonstr)
        return NULL_TREE;
 
       tree offset;
-      if (tree str = string_constant (arg0, &offset, mem_size, nonstr))
+      if (tree str = string_constant (arg0, &offset, mem_size, decl))
        {
          /* Avoid pointers to arrays (see bug 86622).  */
          if (POINTER_TYPE_P (TREE_TYPE (arg))
@@ -11396,11 +11397,7 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *nonstr)
       if (TREE_CODE (chartype) != INTEGER_TYPE)
        return NULL;
 
-      tree charsize = array_ref_element_size (arg);
-      /* Set the non-constant offset to the non-constant index scaled
-        by the size of the character type.  */
-      offset = fold_build2 (MULT_EXPR, TREE_TYPE (offset),
-                           fold_convert (sizetype, varidx), charsize);
+      offset = fold_convert (sizetype, varidx);
     }
 
   if (TREE_CODE (array) == STRING_CST)
@@ -11408,9 +11405,8 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *nonstr)
       *ptr_offset = fold_convert (sizetype, offset);
       if (mem_size)
        *mem_size = TYPE_SIZE_UNIT (TREE_TYPE (array));
-      /* This is not strictly correct.  FIXME in follow-up patch.  */
-      if (nonstr)
-       *nonstr = NULL_TREE;
+      if (decl)
+       *decl = NULL_TREE;
       gcc_checking_assert (tree_to_shwi (TYPE_SIZE_UNIT (TREE_TYPE (array)))
                           >= TREE_STRING_LENGTH (array));
       return array;
@@ -11455,23 +11451,10 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *nonstr)
   if (!init || TREE_CODE (init) != STRING_CST)
     return NULL_TREE;
 
-  /* Compute the lower bound number of elements (not bytes) in the array
-     that the string is used to initialize.  The actual size of the array
-     may be greater if the string is shorter, but the the important
-     data point is whether the literal, inlcuding the terminating nul,
-     fits the array.  */
-  unsigned HOST_WIDE_INT charsize
-    = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (init))));
-  unsigned HOST_WIDE_INT array_elts
-    = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (init))) / charsize;
-
-  /* Compute the string length in (wide) characters.  */
-  unsigned HOST_WIDE_INT length = TREE_STRING_LENGTH (init);
-
   if (mem_size)
     *mem_size = TYPE_SIZE_UNIT (TREE_TYPE (init));
-  if (nonstr)
-    *nonstr = array_elts > length ? NULL_TREE : array;
+  if (decl)
+    *decl = array;
 
   gcc_checking_assert (tree_to_shwi (TYPE_SIZE_UNIT (TREE_TYPE (init)))
                       >= TREE_STRING_LENGTH (init));
index e18ee28fe6327208033c253f8a44daaa42eb6ec0..6b4b6a423ca41e8901bb03a8945a88130aa38345 100644 (file)
@@ -14595,6 +14595,10 @@ c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */)
   unsigned HOST_WIDE_INT string_length = TREE_STRING_LENGTH (src);
   unsigned HOST_WIDE_INT string_size = tree_to_uhwi (mem_size);
 
+  /* Ideally this would turn into a gcc_checking_assert over time.  */
+  if (string_length > string_size)
+    string_length = string_size;
+
   const char *string = TREE_STRING_POINTER (src);
 
   /* Ideally this would turn into a gcc_checking_assert over time.  */
index 83230512e71b9e0afeffb2fc90bdd6c8174a16d8..36a85c7eb7fb86ea174d74fa9926c06701f69311 100644 (file)
@@ -1335,7 +1335,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
            return false;
        }
       else
-       val = c_strlen (arg, 1, eltsize);
+       val = c_strlen (arg, 1, NULL, eltsize);
 
       if (!val && fuzzy)
        {
index 91e21af209370e36009016c8e5970eac48c3fa80..9f3eebc6dbad6ff4be9191d547429a18f6cf39fd 100644 (file)
@@ -1999,13 +1999,6 @@ get_string_length (tree str, unsigned eltsize)
   if (!str)
     return fmtresult ();
 
-  if (tree slen = c_strlen (str, 1, eltsize))
-    {
-      /* Simply return the length of the string.  */
-      fmtresult res (tree_to_shwi (slen));
-      return res;
-    }
-
   /* Determine the length of the shortest and longest string referenced
      by STR.  Strings of unknown lengths are bounded by the sizes of
      arrays that subexpressions of STR may refer to.  Pointers that
index f6b0e64133369a7dd796a63f6fcf928d5661fc95..e455d8986306a33bfa4bb3bb036e88c1727bdf6d 100644 (file)
@@ -1,3 +1,8 @@
+2018-09-13  Martin Sebor  <msebor@redhat.com>
+           Jeff Law  <law@redhat.com>
+
+       * gcc.dg/warn-strlen-no-nul.c: New test.
+
 2018-09-13  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/87263
diff --git a/gcc/testsuite/gcc.dg/warn-strlen-no-nul.c b/gcc/testsuite/gcc.dg/warn-strlen-no-nul.c
new file mode 100644 (file)
index 0000000..d2bc525
--- /dev/null
@@ -0,0 +1,301 @@
+/* PR tree-optimization/86552 - missing warning for reading past the end
+   of non-string arrays
+   { dg-do compile }
+   { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */
+
+extern __SIZE_TYPE__ strlen (const char*);
+
+const char a[5] = "12345";   /* { dg-message "declared here" } */
+
+int v0 = 0;
+int v1 = 1;
+
+void sink (int, ...);
+
+#define CONCAT(a, b)   a ## b
+#define CAT(a, b)      CONCAT(a, b)
+
+#define T(str)                                         \
+  __attribute__ ((noipa))                              \
+  void CAT (test_, __LINE__) (void) {                  \
+    int i0 = 0, i1 = i0 + 1, i2 = i1 + 1, i3 = i2 + 1; \
+    sink (strlen (str), i0, i1, i2, i3);               \
+  } typedef void dummy_type
+
+T (a);                /* { dg-warning "argument missing terminating nul" }  */
+T (&a[0]);            /* { dg-warning "nul" }  */
+T (&a[0] + 1);        /* { dg-warning "nul" }  */
+T (&a[1]);            /* { dg-warning "nul" }  */
+T (&a[v0]);           /* { dg-warning "nul" }  */
+T (&a[v0] + 1);       /* { dg-warning "nul" }  */
+
+
+const char b[][5] = { /* { dg-message "declared here" } */
+  "12", "123", "1234", "54321"
+};
+
+T (b[0]);
+T (b[1]);
+T (b[2]);
+T (b[3]);             /* { dg-warning "nul" }  */
+
+T (b[i0]);
+T (b[i1]);
+T (b[i2]);
+T (b[i3]);            /* { dg-warning "nul" }  */
+
+T (b[v0]);
+
+T (&b[i2][i1]);
+T (&b[i2][i1] + i1);
+T (&b[i2][v0]);
+T (&b[i2][i1] + v0);
+
+T (&b[2][1]);
+T (&b[2][1] + i1);
+T (&b[2][i0]);
+T (&b[2][1] + i0);
+
+T (&b[2][1]);
+T (&b[2][1] + v0);
+T (&b[2][v0]);
+
+T (&b[3][1]);           /* { dg-warning "nul" }  */
+T (&b[3][1] + 1);       /* { dg-warning "nul" }  */
+T (&b[3][1] + i1);      /* { dg-warning "nul" }  */
+T (&b[3][v0]);          /* { dg-warning "nul" }  */
+T (&b[3][1] + v0);      /* { dg-warning "nul" }  */
+T (&b[3][v0] + v1);     /* { dg-warning "nul" }  */
+
+T (&b[i3][i1]);         /* { dg-warning "nul" }  */
+T (&b[i3][i1] + 1);     /* { dg-warning "nul" }  */
+T (&b[i3][i1] + i1);    /* { dg-warning "nul" }  */
+T (&b[i3][v0]);         /* { dg-warning "nul" "pr86919" { xfail *-*-* } }  */
+T (&b[i3][i1] + v0);    /* { dg-warning "nul" "pr86919" { xfail *-*-* } }  */
+T (&b[i3][v0] + v1);    /* { dg-warning "nul" "pr86919" { xfail *-*-* } }  */
+
+T (v0 ? "" : b[0]);
+T (v0 ? "" : b[1]);
+T (v0 ? "" : b[2]);
+T (v0 ? "" : b[3]);               /* { dg-warning "nul" }  */
+T (v0 ? b[0] : "");
+T (v0 ? b[1] : "");
+T (v0 ? b[2] : "");
+T (v0 ? b[3] : "");               /* { dg-warning "nul" }  */
+
+T (v0 ? "" : b[i0]);
+T (v0 ? "" : b[i1]);
+T (v0 ? "" : b[i2]);
+/* The following is diagnosed but the warning location is wrong
+   (the PRE pass loses it).  */
+T (v0 ? "" : b[i3]);              /* { dg-warning "nul" }  */
+T (v0 ? b[i0] : "");
+T (v0 ? b[i1] : "");
+T (v0 ? b[i2] : "");
+T (v0 ? b[i3] : "");              /* { dg-warning "nul" }  */
+
+T (v0 ? "1234" : b[3]);           /* { dg-warning "nul" }  */
+T (v0 ? "1234" : b[i3]);          /* { dg-warning "nul" }  */
+T (v0 ? b[3] : "1234");           /* { dg-warning "nul" }  */
+T (v0 ? b[i3] : "1234");          /* { dg-warning "nul" }  */
+
+T (v0 ? a : b[3]);                /* { dg-warning "nul" }  */
+T (v0 ? b[0] : b[2]);
+T (v0 ? b[2] : b[3]);             /* { dg-warning "nul" }  */
+T (v0 ? b[3] : b[2]);             /* { dg-warning "nul" }  */
+
+T (v0 ? a : b[i3]);               /* { dg-warning "nul" }  */
+T (v0 ? b[i0] : b[i2]);
+T (v0 ? b[i2] : b[i3]);           /* { dg-warning "nul" }  */
+T (v0 ? b[i3] : b[i2]);           /* { dg-warning "nul" }  */
+
+T (v0 ? b[0] : &b[3][0] + 1);     /* { dg-warning "nul" }  */
+T (v0 ? b[0] : &b[3][0] + i1);    /* { dg-warning "nul" }  */
+T (v0 ? b[1] : &b[3][1] + v0);    /* { dg-warning "nul" }  */
+
+T (v0 ? b[i0] : &b[i3][i0] + i1);    /* { dg-warning "nul" }  */
+T (v0 ? b[i0] : &b[i3][i0] + i1);    /* { dg-warning "nul" }  */
+T (v0 ? b[i1] : &b[i3][i1] + v0);    /* { dg-warning "nul" }  */
+
+/* It's possible to detect the missing nul in the following two
+   expressions but GCC doesn't do it yet.  */
+T (v0 ? &b[3][1] + v0 : b[2]);    /* { dg-warning "nul" "bug" }  */
+T (v0 ? &b[3][v0] : &b[3][v1]);   /* { dg-warning "nul" "bug" }  */
+
+
+struct A { char a[5], b[5]; };
+
+const struct A s = { "1234", "12345" };
+
+T (s.a);
+T (&s.a[0]);
+T (&s.a[0] + 1);
+T (&s.a[0] + v0);
+T (&s.a[1]);
+T (&s.a[1] + 1);
+T (&s.a[1] + v0);
+
+T (&s.a[i0]);
+T (&s.a[i0] + i1);
+T (&s.a[i0] + v0);
+T (&s.a[i1]);
+T (&s.a[i1] + i1);
+T (&s.a[i1] + v0);
+
+T (s.b);              /* { dg-warning "nul" }  */
+T (&s.b[0]);          /* { dg-warning "nul" }  */
+T (&s.b[0] + 1);      /* { dg-warning "nul" }  */
+T (&s.b[0] + v0);     /* { dg-warning "nul" }  */
+T (&s.b[1]);          /* { dg-warning "nul" }  */
+T (&s.b[1] + 1);      /* { dg-warning "nul" }  */
+T (&s.b[1] + i0);     /* { dg-warning "nul" }  */
+T (&s.b[1] + v0);     /* { dg-warning "nul" }  */
+
+T (&s.b[i0]);         /* { dg-warning "nul" }  */
+T (&s.b[i0] + i1);    /* { dg-warning "nul" }  */
+T (&s.b[i0] + v0);    /* { dg-warning "nul" "pr86919" { xfail *-*-* } }  */
+T (&s.b[i1]);         /* { dg-warning "nul" }  */
+T (&s.b[i1] + i1);    /* { dg-warning "nul" }  */
+T (&s.b[i1] + v0);    /* { dg-warning "nul" "pr86919" { xfail *-*-* } }  */
+
+struct B { struct A a[2]; };
+
+const struct B ba[] = {
+  { { { "123", "12345" }, { "12345", "123" } } },
+  { { { "12345", "123" }, { "123", "12345" } } },
+  { { { "1", "12" },      { "123", "1234" } } },
+  { { { "123", "1234" },  { "12345", "12" } } }
+};
+
+T (ba[0].a[0].a);
+T (&ba[0].a[0].a[0]);
+T (&ba[0].a[0].a[0] + 1);
+T (&ba[0].a[0].a[0] + v0);
+T (&ba[0].a[0].a[1]);
+T (&ba[0].a[0].a[1] + 1);
+T (&ba[0].a[0].a[1] + v0);
+
+T (ba[0].a[0].b);           /* { dg-warning "nul" }  */
+T (&ba[0].a[0].b[0]);       /* { dg-warning "nul" }  */
+T (&ba[0].a[0].b[0] + 1);   /* { dg-warning "nul" }  */
+T (&ba[0].a[0].b[0] + v0);  /* { dg-warning "nul" }  */
+T (&ba[0].a[0].b[1]);       /* { dg-warning "nul" }  */
+T (&ba[0].a[0].b[1] + 1);   /* { dg-warning "nul" }  */
+T (&ba[0].a[0].b[1] + v0);  /* { dg-warning "nul" }  */
+
+T (ba[0].a[1].a);           /* { dg-warning "nul" }  */
+T (&ba[0].a[1].a[0]);       /* { dg-warning "nul" }  */
+T (&ba[0].a[1].a[0] + 1);   /* { dg-warning "nul" }  */
+T (&ba[0].a[1].a[0] + v0);  /* { dg-warning "nul" }  */
+T (&ba[0].a[1].a[1]);       /* { dg-warning "nul" }  */
+T (&ba[0].a[1].a[1] + 1);   /* { dg-warning "nul" }  */
+T (&ba[0].a[1].a[1] + v0);  /* { dg-warning "nul" }  */
+
+T (ba[0].a[1].b);
+T (&ba[0].a[1].b[0]);
+T (&ba[0].a[1].b[0] + 1);
+T (&ba[0].a[1].b[0] + v0);
+T (&ba[0].a[1].b[1]);
+T (&ba[0].a[1].b[1] + 1);
+T (&ba[0].a[1].b[1] + v0);
+
+
+T (ba[1].a[0].a);           /* { dg-warning "nul" }  */
+T (&ba[1].a[0].a[0]);       /* { dg-warning "nul" }  */
+T (&ba[1].a[0].a[0] + 1);   /* { dg-warning "nul" }  */
+T (&ba[1].a[0].a[0] + v0);  /* { dg-warning "nul" }  */
+T (&ba[1].a[0].a[1]);       /* { dg-warning "nul" }  */
+T (&ba[1].a[0].a[1] + 1);   /* { dg-warning "nul" }  */
+T (&ba[1].a[0].a[1] + v0);  /* { dg-warning "nul" }  */
+
+T (ba[1].a[0].b);
+T (&ba[1].a[0].b[0]);
+T (&ba[1].a[0].b[0] + 1);
+T (&ba[1].a[0].b[0] + v0);
+T (&ba[1].a[0].b[1]);
+T (&ba[1].a[0].b[1] + 1);
+T (&ba[1].a[0].b[1] + v0);
+
+T (ba[1].a[1].a);
+T (&ba[1].a[1].a[0]);
+T (&ba[1].a[1].a[0] + 1);
+T (&ba[1].a[1].a[0] + v0);
+T (&ba[1].a[1].a[1]);
+T (&ba[1].a[1].a[1] + 1);
+T (&ba[1].a[1].a[1] + v0);
+
+T (ba[1].a[1].b);           /* { dg-warning "nul" }  */
+T (&ba[1].a[1].b[0]);       /* { dg-warning "nul" }  */
+T (&ba[1].a[1].b[0] + 1);   /* { dg-warning "nul" }  */
+T (&ba[1].a[1].b[0] + v0);  /* { dg-warning "nul" }  */
+T (&ba[1].a[1].b[1]);       /* { dg-warning "nul" }  */
+T (&ba[1].a[1].b[1] + 1);   /* { dg-warning "nul" }  */
+T (&ba[1].a[1].b[1] + v0);  /* { dg-warning "nul" }  */
+
+
+T (ba[2].a[0].a);
+T (&ba[2].a[0].a[0]);
+T (&ba[2].a[0].a[0] + 1);
+T (&ba[2].a[0].a[0] + v0);
+T (&ba[2].a[0].a[1]);
+T (&ba[2].a[0].a[1] + 1);
+T (&ba[2].a[0].a[1] + v0);
+
+T (ba[2].a[0].b);
+T (&ba[2].a[0].b[0]);
+T (&ba[2].a[0].b[0] + 1);
+T (&ba[2].a[0].b[0] + v0);
+T (&ba[2].a[0].b[1]);
+T (&ba[2].a[0].b[1] + 1);
+T (&ba[2].a[0].b[1] + v0);
+
+T (ba[2].a[1].a);
+T (&ba[2].a[1].a[0]);
+T (&ba[2].a[1].a[0] + 1);
+T (&ba[2].a[1].a[0] + v0);
+T (&ba[2].a[1].a[1]);
+T (&ba[2].a[1].a[1] + 1);
+T (&ba[2].a[1].a[1] + v0);
+
+
+T (ba[3].a[0].a);
+T (&ba[3].a[0].a[0]);
+T (&ba[3].a[0].a[0] + 1);
+T (&ba[3].a[0].a[0] + v0);
+T (&ba[3].a[0].a[1]);
+T (&ba[3].a[0].a[1] + 1);
+T (&ba[3].a[0].a[1] + v0);
+
+T (ba[3].a[0].b);
+T (&ba[3].a[0].b[0]);
+T (&ba[3].a[0].b[0] + 1);
+T (&ba[3].a[0].b[0] + v0);
+T (&ba[3].a[0].b[1]);
+T (&ba[3].a[0].b[1] + 1);
+T (&ba[3].a[0].b[1] + v0);
+
+T (ba[3].a[1].a);           /* { dg-warning "nul" }  */
+T (&ba[3].a[1].a[0]);      /* { dg-warning "nul" }  */
+T (&ba[3].a[1].a[0] + 1);   /* { dg-warning "nul" }  */
+T (&ba[3].a[1].a[0] + v0);  /* { dg-warning "nul" }  */
+T (&ba[3].a[1].a[1]);      /* { dg-warning "nul" }  */
+T (&ba[3].a[1].a[1] + 1);   /* { dg-warning "nul" }  */
+T (&ba[3].a[1].a[1] + v0);  /* { dg-warning "nul" }  */
+
+T (ba[3].a[1].b);
+T (&ba[3].a[1].b[0]);
+T (&ba[3].a[1].b[0] + 1);
+T (&ba[3].a[1].b[0] + v0);
+T (&ba[3].a[1].b[1]);
+T (&ba[3].a[1].b[1] + 1);
+T (&ba[3].a[1].b[1] + v0);
+
+
+T (v0 ? ba[0].a[0].a : ba[0].a[0].b);           /* { dg-warning "nul" }  */
+T (v0 ? ba[0].a[0].a : ba[0].a[0].b);           /* { dg-warning "nul" }  */
+
+T (v0 ? &ba[0].a[0].a[0] : &ba[3].a[1].a[0]);   /* { dg-warning "nul" }  */
+T (v0 ? &ba[3].a[1].a[1] :  ba[0].a[0].a);      /* { dg-warning "nul" }  */
+
+T (v0 ? ba[0].a[0].a : ba[0].a[1].b);
+T (v0 ? ba[0].a[1].b : ba[0].a[0].a);
index d625b940c1fd151096b45f130533ef7503a8c3e0..3fa5ef56f38e726276d9146e542aff324d4c8c27 100644 (file)
@@ -291,8 +291,6 @@ get_addr_stridx (tree exp, tree ptr, unsigned HOST_WIDE_INT *offset_out)
 static int
 get_stridx (tree exp)
 {
-  tree s, o;
-
   if (TREE_CODE (exp) == SSA_NAME)
     {
       if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)])
@@ -336,18 +334,10 @@ get_stridx (tree exp)
        return idx;
     }
 
-  s = string_constant (exp, &o, NULL, NULL);
-  if (s != NULL_TREE
-      && (o == NULL_TREE || tree_fits_shwi_p (o))
-      && TREE_STRING_LENGTH (s) > 0)
-    {
-      HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
-      const char *p = TREE_STRING_POINTER (s);
-      int max = TREE_STRING_LENGTH (s) - 1;
+  const char *p = c_getstr (exp);
+  if (p)
+    return ~(int) strlen (p);
 
-      if (p[max] == '\0' && offset >= 0 && offset <= max)
-       return ~(int) strlen (p + offset);
-    }
   return 0;
 }