PR tree-optimization/84480 - bogus -Wstringop-truncation despite assignment with...
authorMartin Sebor <msebor@redhat.com>
Thu, 22 Feb 2018 17:35:29 +0000 (17:35 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Thu, 22 Feb 2018 17:35:29 +0000 (10:35 -0700)
gcc/ChangeLog:

PR tree-optimization/84480
* gimple-fold.c (gimple_fold_builtin_strcpy): Move warnings
to maybe_diag_stxncpy_trunc.  Call it.
* tree-ssa-strlen.c (maybe_diag_stxncpy_trunc): Integrate warnings
from gimple_fold_builtin_strcpy.  Print inlining stack.
(handle_builtin_stxncpy): Print inlining stack.
* tree-ssa-strlen.h (maybe_diag_stxncpy_trunc): Declare.

gcc/testsuite/ChangeLog:

PR tree-optimization/84480
* c-c++-common/Wstringop-truncation.c: Adjust text of expected warnings.
* g++.dg/warn/Wstringop-truncation-1.C: New test.

From-SVN: r257910

gcc/ChangeLog
gcc/gimple-fold.c
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/Wstringop-truncation.c
gcc/testsuite/g++.dg/warn/Wstringop-truncation-1.C [new file with mode: 0644]
gcc/tree-ssa-strlen.c
gcc/tree-ssa-strlen.h [new file with mode: 0644]

index 1868bb6d83f6ac457fa2d6beb7c1960dc1125eac..9e737edec021dc21378996c3bed3111c9e0d1ea6 100644 (file)
@@ -1,3 +1,13 @@
+2018-02-22  Martin Sebor  <msebor@redhat.com>
+
+       PR tree-optimization/84480
+       * gimple-fold.c (gimple_fold_builtin_strcpy): Move warnings
+       to maybe_diag_stxncpy_trunc.  Call it.
+       * tree-ssa-strlen.c (maybe_diag_stxncpy_trunc): Integrate warnings
+       from gimple_fold_builtin_strcpy.  Print inlining stack.
+       (handle_builtin_stxncpy): Print inlining stack.
+       * tree-ssa-strlen.h (maybe_diag_stxncpy_trunc): Declare.
+
 2018-02-22  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR target/84176
index 0b7553160b53036b119ffbaa6beb974d99e1eee6..8257873dd20ce40cfd04ab1834df37b419d3e28a 100644 (file)
@@ -65,6 +65,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "intl.h"
 #include "calls.h"
 #include "tree-vector-builder.h"
+#include "tree-ssa-strlen.h"
 
 /* Return true when DECL can be referenced from current unit.
    FROM_DECL (if non-null) specify constructor of variable DECL was taken from.
@@ -1710,37 +1711,8 @@ gimple_fold_builtin_strncpy (gimple_stmt_iterator *gsi,
   if (tree_int_cst_lt (ssize, len))
     return false;
 
-  if (!nonstring)
-    {
-      if (tree_int_cst_lt (len, slen))
-       {
-         tree fndecl = gimple_call_fndecl (stmt);
-         gcall *call = as_a <gcall *> (stmt);
-
-         warning_at (loc, OPT_Wstringop_truncation,
-                     (tree_int_cst_equal (size_one_node, len)
-                      ? G_("%G%qD output truncated copying %E byte "
-                           "from a string of length %E")
-                      : G_("%G%qD output truncated copying %E bytes "
-                           "from a string of length %E")),
-                     call, fndecl, len, slen);
-       }
-      else if (tree_int_cst_equal (len, slen))
-       {
-         tree fndecl = gimple_call_fndecl (stmt);
-         gcall *call = as_a <gcall *> (stmt);
-
-         warning_at (loc, OPT_Wstringop_truncation,
-                     (tree_int_cst_equal (size_one_node, len)
-                      ? G_("%G%qD output truncated before terminating nul "
-                           "copying %E byte from a string of the same "
-                           "length")
-                      : G_("%G%qD output truncated before terminating nul "
-                           "copying %E bytes from a string of the same "
-                           "length")),
-                     call, fndecl, len);
-       }
-    }
+  /* Diagnose truncation that leaves the copy unterminated.  */
+  maybe_diag_stxncpy_trunc (*gsi, src, len);
 
   /* OK transform into builtin memcpy.  */
   tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
index d85d8a52dd60a7485beb13d6125d34ecab453b9c..e58ed9be1c6950f3fb84eb8c7b01beeb3a113620 100644 (file)
@@ -1,3 +1,9 @@
+2018-02-22  Martin Sebor  <msebor@redhat.com>
+
+       PR tree-optimization/84480
+       * c-c++-common/Wstringop-truncation.c: Adjust text of expected warnings.
+       * g++.dg/warn/Wstringop-truncation-1.C: New test.
+
 2018-02-22  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR target/84176
index dc8c618976e13cd3de8cc0a070077080d046e578..bd52091550262e3a49950707fec3c079d226067a 100644 (file)
@@ -188,7 +188,7 @@ void test_strncpy_ptr (char *d, const char* s, const char *t, int i)
   CPY (d, CHOOSE (s, t), 2);
 
   CPY (d, CHOOSE ("", "123"), 1);   /* { dg-warning ".strncpy\[^\n\r\]* output may be truncated copying 1 byte from a string of length 3" } */
-  CPY (d, CHOOSE ("1", "123"), 1);  /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 1" } */
+  CPY (d, CHOOSE ("1", "123"), 1);  /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying 1 byte from a string of the same length" } */
   CPY (d, CHOOSE ("12", "123"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 2" } */
   CPY (d, CHOOSE ("123", "12"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 2" } */
 
@@ -331,7 +331,7 @@ void test_strncpy_array (Dest *pd, int i, const char* s)
     /* This might be better written using memcpy() but it's safe so
        it probably shouldn't be diagnosed.  It currently triggers
        a warning because of bug 81704.  */
-    strncpy (dst7, "0123456", sizeof dst7);   /* { dg-bogus "truncated" "bug 81704" { xfail *-*-* } } */
+    strncpy (dst7, "0123456", sizeof dst7);   /* { dg-bogus "\\\[-Wstringop-truncation]" "bug 81704" { xfail *-*-* } } */
     dst7[sizeof dst7 - 1] = '\0';
     sink (dst7);
   }
@@ -350,7 +350,7 @@ void test_strncpy_array (Dest *pd, int i, const char* s)
   }
 
   {
-    strncpy (pd->a5, "01234", sizeof pd->a5);   /* { dg-bogus "truncated" "bug 81704" { xfail *-*-* } } */
+    strncpy (pd->a5, "01234", sizeof pd->a5);   /* { dg-bogus "\\\[-Wstringop-truncation]" "bug 81704" { xfail *-*-* } } */
     pd->a5[sizeof pd->a5 - 1] = '\0';
     sink (pd);
   }
diff --git a/gcc/testsuite/g++.dg/warn/Wstringop-truncation-1.C b/gcc/testsuite/g++.dg/warn/Wstringop-truncation-1.C
new file mode 100644 (file)
index 0000000..a502b78
--- /dev/null
@@ -0,0 +1,126 @@
+/* PR/tree-optimization/84480 - bogus -Wstringop-truncation despite
+   assignment with an inlined string literal
+   { dg-do compile }
+   { dg-options "-O2 -Wstringop-truncation" }  */
+
+#include <string.h>
+
+template <size_t N>
+class GoodString
+{
+public:
+  GoodString (const char *s, size_t slen = N)
+  {
+    if (slen > N)
+      slen = N;
+
+    strncpy (str, s, slen);
+
+    str[slen] = '\0';
+  }
+
+private:
+  char str[N + 1];
+};
+
+void sink (void*);
+
+void good_nowarn_size_m2 ()
+{
+  GoodString<3> str ("12");
+  sink (&str);
+}
+
+void good_nowarn_size_m1 ()
+{
+  GoodString<3> str ("123");    // { dg-bogus "\\\[-Wstringop-truncation]" }
+  sink (&str);
+}
+
+void good_nowarn_size_m1_var (const char* s)
+{
+  GoodString<3> str (s);        // { dg-bogus "\\\[-Wstringop-truncation]" }
+  sink (&str);
+}
+
+void call_good_nowarn_size_m1_var ()
+{
+  good_nowarn_size_m1_var ("456");
+}
+
+
+template <size_t N>
+class BadString1
+{
+public:
+  BadString1 (const char *s, size_t slen = N)
+  {
+    if (slen > N)
+      slen = N;
+
+    strncpy (str, s, slen);
+  }
+
+private:
+  char str[N + 1];
+};
+
+void bad1_nowarn_size_m2 ()
+{
+  BadString1<3> str ("12");
+  sink (&str);
+}
+
+
+template <size_t N>
+class BadString2
+{
+public:
+  BadString2 (const char *s, size_t slen = N)
+  {
+    if (slen > N)
+      slen = N;
+
+    strncpy (str, s, slen);     // { dg-warning "\\\[-Wstringop-truncation]" }
+  }
+
+private:
+  char str[N + 1];
+};
+
+void bad2_warn_size_m1 ()
+{
+  BadString2<3> str ("123");
+  sink (&str);
+}
+
+// { dg-message "inlined from .void bad2_warn_size_m1." "" { target *-*-* } 0 }
+
+template <size_t N>
+class BadString3
+{
+public:
+  BadString3 (const char *s, size_t slen = N)
+  {
+    if (slen > N)
+      slen = N;
+
+    strncpy (str, s, slen);     // { dg-warning "\\\[-Wstringop-truncation]" }
+  }
+
+private:
+  char str[N + 1];
+};
+
+void bad3_warn_size_m1_var (const char *s)
+{
+  BadString3<3> str (s);
+  sink (&str);
+}
+
+void call_bad3_warn_size_m1_var ()
+{
+  bad3_warn_size_m1_var ("456");
+}
+
+// { dg-message "inlined from .void call_bad3_warn_size_m1_var." "" { target *-*-* } 0 }
index 09ffa154439d02dfb607eccddc03e4c1d28a262d..71ed0ff1b4599ae7412f3aafa80197bddcc6c134 100644 (file)
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "domwalk.h"
 #include "tree-ssa-alias.h"
 #include "tree-ssa-propagate.h"
+#include "tree-ssa-strlen.h"
 #include "params.h"
 #include "ipa-chkp.h"
 #include "tree-hash-traits.h"
@@ -1780,11 +1781,12 @@ is_strlen_related_p (tree src, tree len)
   return false;
 }
 
-/* A helper of handle_builtin_stxncpy.  Check to see if the specified
-   bound is a) equal to the size of the destination DST and if so, b)
-   if it's immediately followed by DST[CNT - 1] = '\0'.  If a) holds
-   and b) does not, warn.  Otherwise, do nothing.  Return true if
-   diagnostic has been issued.
+/* Called by handle_builtin_stxncpy and by gimple_fold_builtin_strncpy
+   in gimple-fold.c.
+   Check to see if the specified bound is a) equal to the size of
+   the destination DST and if so, b) if it's immediately followed by
+   DST[CNT - 1] = '\0'.  If a) holds and b) does not, warn.  Otherwise,
+   do nothing.  Return true if diagnostic has been issued.
 
    The purpose is to diagnose calls to strncpy and stpncpy that do
    not nul-terminate the copy while allowing for the idiom where
@@ -1795,7 +1797,7 @@ is_strlen_related_p (tree src, tree len)
      a[sizeof a - 1] = '\0';
 */
 
-static bool
+bool
 maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
 {
   gimple *stmt = gsi_stmt (gsi);
@@ -1831,8 +1833,11 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
     return false;
 
   /* Negative value is the constant string length.  If it's less than
-     the lower bound there is no truncation.  */
-  int sidx = get_stridx (src);
+     the lower bound there is no truncation.  Avoid calling get_stridx()
+     when ssa_ver_to_stridx is empty.  That implies the caller isn't
+     running under the control of this pass and ssa_ver_to_stridx hasn't
+     been created yet.  */
+  int sidx = ssa_ver_to_stridx.length () ? get_stridx (src) : 0;
   if (sidx < 0 && wi::gtu_p (cntrange[0], ~sidx))
     return false;
 
@@ -1935,23 +1940,35 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
          lenrange[0] = wi::shwi (0, prec);
        }
 
-      if (wi::geu_p (lenrange[0], cntrange[1]))
+      gcall *call = as_a <gcall *> (stmt);
+
+      if (lenrange[0] == cntrange[1] && cntrange[0] == cntrange[1])
+       return warning_at (callloc, OPT_Wstringop_truncation,
+                          (integer_onep (cnt)
+                           ? G_("%G%qD output truncated before terminating "
+                                "nul copying %E byte from a string of the "
+                                "same length")
+                           : G_("%G%qD output truncated before terminating nul "
+                                "copying %E bytes from a string of the same "
+                                "length")),
+                          call, func, cnt);
+      else if (wi::geu_p (lenrange[0], cntrange[1]))
        {
          /* The shortest string is longer than the upper bound of
             the count so the truncation is certain.  */
          if (cntrange[0] == cntrange[1])
            return warning_at (callloc, OPT_Wstringop_truncation,
                               integer_onep (cnt)
-                              ? G_("%qD output truncated copying %E byte "
+                              ? G_("%G%qD output truncated copying %E byte "
                                    "from a string of length %wu")
-                              : G_("%qD output truncated copying %E bytes "
+                              : G_("%G%qD output truncated copying %E bytes "
                                    "from a string of length %wu"),
-                              func, cnt, lenrange[0].to_uhwi ());
+                              call, func, cnt, lenrange[0].to_uhwi ());
 
          return warning_at (callloc, OPT_Wstringop_truncation,
-                            "%qD output truncated copying between %wu "
+                            "%G%qD output truncated copying between %wu "
                             "and %wu bytes from a string of length %wu",
-                            func, cntrange[0].to_uhwi (),
+                            call, func, cntrange[0].to_uhwi (),
                             cntrange[1].to_uhwi (), lenrange[0].to_uhwi ());
        }
       else if (wi::geu_p (lenrange[1], cntrange[1]))
@@ -1961,16 +1978,16 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
          if (cntrange[0] == cntrange[1])
            return warning_at (callloc, OPT_Wstringop_truncation,
                               integer_onep (cnt)
-                              ? G_("%qD output may be truncated copying %E "
+                              ? G_("%G%qD output may be truncated copying %E "
                                    "byte from a string of length %wu")
-                              : G_("%qD output may be truncated copying %E "
+                              : G_("%G%qD output may be truncated copying %E "
                                    "bytes from a string of length %wu"),
-                              func, cnt, lenrange[1].to_uhwi ());
+                              call, func, cnt, lenrange[1].to_uhwi ());
 
          return warning_at (callloc, OPT_Wstringop_truncation,
-                            "%qD output may be truncated copying between %wu "
+                            "%G%qD output may be truncated copying between %wu "
                             "and %wu bytes from a string of length %wu",
-                            func, cntrange[0].to_uhwi (),
+                            call, func, cntrange[0].to_uhwi (),
                             cntrange[1].to_uhwi (), lenrange[1].to_uhwi ());
        }
 
@@ -1982,9 +1999,9 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
             the lower bound of the specified count but shorter than the
             upper bound the copy may (but need not) be truncated.  */
          return warning_at (callloc, OPT_Wstringop_truncation,
-                            "%qD output may be truncated copying between %wu "
-                            "and %wu bytes from a string of length %wu",
-                            func, cntrange[0].to_uhwi (),
+                            "%G%qD output may be truncated copying between "
+                            "%wu and %wu bytes from a string of length %wu",
+                            call, func, cntrange[0].to_uhwi (),
                             cntrange[1].to_uhwi (), lenrange[0].to_uhwi ());
        }
     }
@@ -2003,8 +2020,8 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
 
       if (cntrange[0] == cntrange[1])
        return warning_at (callloc, OPT_Wstringop_truncation,
-                          "%qD specified bound %E equals destination size",
-                          func, cnt);
+                          "%G%qD specified bound %E equals destination size",
+                          as_a <gcall *> (stmt), func, cnt);
     }
 
   return false;
@@ -2103,14 +2120,15 @@ handle_builtin_stxncpy (built_in_function, gimple_stmt_iterator *gsi)
   if (sisrc == silen
       && is_strlen_related_p (src, len)
       && warning_at (callloc, OPT_Wstringop_truncation,
-                    "%qD output truncated before terminating nul "
+                    "%G%qD output truncated before terminating nul "
                     "copying as many bytes from a string as its length",
-                    func))
+                    as_a <gcall *>(stmt), func))
     warned = true;
   else if (silen && is_strlen_related_p (src, silen->ptr))
     warned = warning_at (callloc, OPT_Wstringop_overflow_,
-                        "%qD specified bound depends on the length "
-                        "of the source argument", func);
+                        "%G%qD specified bound depends on the length "
+                        "of the source argument",
+                        as_a <gcall *>(stmt), func);
   if (warned)
     {
       location_t strlenloc = pss->second;
diff --git a/gcc/tree-ssa-strlen.h b/gcc/tree-ssa-strlen.h
new file mode 100644 (file)
index 0000000..1399a78
--- /dev/null
@@ -0,0 +1,26 @@
+/* Declarations of tree-ssa-strlen API.
+
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 3, or (at your option) any later
+   version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_TREE_SSA_STRLEN_H
+#define GCC_TREE_SSA_STRLEN_H
+
+extern bool maybe_diag_stxncpy_trunc (gimple_stmt_iterator, tree, tree);
+
+#endif   // GCC_TREE_SSA_STRLEN_H