PR tree-optimization/85700 - Spurious -Wstringop-truncation warning with strncat
authorMartin Sebor <msebor@redhat.com>
Mon, 25 Jun 2018 20:33:28 +0000 (20:33 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Mon, 25 Jun 2018 20:33:28 +0000 (14:33 -0600)
gcc/ChangeLog:

PR tree-optimization/85700
* gimple-fold.c (gimple_fold_builtin_strncat): Adjust comment.
* tree-ssa-strlen.c (is_strlen_related_p): Handle integer subtraction.
(maybe_diag_stxncpy_trunc): Distinguish strncat from strncpy.

gcc/testsuite/ChangeLog:

PR tree-optimization/85700
* gcc.dg/Wstringop-truncation-4.c: New test.

From-SVN: r262110

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

index 07db821bf571b65fa55e31c0700a896a33f48de1..5334c36708d55b35ce2a8148a165499107f5a39c 100644 (file)
@@ -1,3 +1,10 @@
+2018-06-25  Martin Sebor  <msebor@redhat.com>
+
+       PR tree-optimization/85700
+       * gimple-fold.c (gimple_fold_builtin_strncat): Adjust comment.
+       * tree-ssa-strlen.c (is_strlen_related_p): Handle integer subtraction.
+       (maybe_diag_stxncpy_trunc): Distinguish strncat from strncpy.
+
 2018-06-25  Martin Sebor  <msebor@redhat.com>
 
        * doc/extend.texi (Zero-length arrays): Update and clarify.
index a01bce7ab0805d68c5ed70ff230509aaeacf336e..b02593596bfb66a9dd9272c8459c4a5c7aa9e883 100644 (file)
@@ -2051,10 +2051,12 @@ gimple_fold_builtin_strncat (gimple_stmt_iterator *gsi)
   if (!nowarn && cmpsrc == 0)
     {
       tree fndecl = gimple_call_fndecl (stmt);
-
-      /* To avoid certain truncation the specified bound should also
-        not be equal to (or less than) the length of the source.  */
       location_t loc = gimple_location (stmt);
+
+      /* To avoid possible overflow the specified bound should also
+        not be equal to the length of the source, even when the size
+        of the destination is unknown (it's not an uncommon mistake
+        to specify as the bound to strncpy the length of the source).  */
       if (warning_at (loc, OPT_Wstringop_overflow_,
                      "%G%qD specified bound %E equals source length",
                      stmt, fndecl, len))
index f2d9caffc0e3bd4521307a687dcd6471ff637012..46064749e3fadf0ea4d8730716e2b1e70d6a1f6b 100644 (file)
@@ -1,3 +1,8 @@
+2018-06-25  Martin Sebor  <msebor@redhat.com>
+
+       PR tree-optimization/85700
+       * gcc.dg/Wstringop-truncation-4.c: New test.
+
 2018-06-25  Fritz Reese  <fritzoreese@gmail.com>
 
        PR fortran/82972
diff --git a/gcc/testsuite/gcc.dg/Wstringop-truncation-4.c b/gcc/testsuite/gcc.dg/Wstringop-truncation-4.c
new file mode 100644 (file)
index 0000000..f394863
--- /dev/null
@@ -0,0 +1,63 @@
+/* PR tree-optimization/85700 - Spurious -Wstringop-truncation warning
+   with strncat
+   { dg-do compile }
+   { dg-options "-O2 -Wno-stringop-overflow -Wstringop-truncation -ftrack-macro-expansion=0" } */
+
+#define NOIPA __attribute__ ((noipa))
+#define strncat __builtin_strncat
+#define strlen __builtin_strlen
+
+extern char a4[4], b4[4], ax[];
+
+NOIPA void cat_a4_s1_1 (void)
+{
+  /* There is no truncation here but since the bound of 1 equals
+     the length of the source string it's likely a mistake that
+     could cause overflow so it's diagnosed by -Wstringop-overflow */
+  strncat (a4, "1", 1);
+}
+
+NOIPA void cat_a4_s1_2 (void)
+{
+  strncat (a4, "1", 2);
+}
+
+NOIPA void cat_a4_s1_3 (void)
+{
+  strncat (a4, "1", 3);
+}
+
+NOIPA void cat_a4_s1_4 (void)
+{
+  /* There is no truncation here but since the bound of 1 equals
+     the length of the source string it's likely a mistake that
+     could cause overflow so it's diagnosed by -Wstringop-overflow */
+  strncat (a4, "1", 4);
+}
+
+NOIPA void cat_a4_s1_5 (void)
+{
+  /* A bound in excess of the destination size is diagnosed by
+     -Wstringop-overflow.  */
+  strncat (a4, "1", 5);
+}
+
+NOIPA void cat_a4_s1_dlen (void)
+{
+  strncat (a4, "1", sizeof a4 - strlen (a4) - 1);
+}
+
+NOIPA void cat_a4_s2_dlen (void)
+{
+  strncat (a4, "12", sizeof a4 - strlen (a4) - 1);  /* { dg-bogus "\\\[-Wstringop-truncation]" } */
+}
+
+NOIPA void cat_a4_b4_dlen (void)
+{
+  strncat (a4, b4, sizeof a4 - strlen (a4) - 1);  /* { dg-bogus "\\\[-Wstringop-truncation]" } */
+}
+
+NOIPA void cat_ax_b4_dlen (void)
+{
+  strncat (ax, b4, 32 - strlen (ax) - 1);  /* { dg-bogus "\\\[-Wstringop-truncation]" } */
+}
index 92545b9ce4d03af5d3fbe296b38b587048476291..2da82a878e3e6b2b21a26f7121b46cc6a8d3866f 100644 (file)
@@ -2014,6 +2014,12 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
 
       gcall *call = as_a <gcall *> (stmt);
 
+      /* Set to true for strncat whose bound is derived from the length
+        of the destination (the expected usage pattern).  */
+      bool cat_dstlen_bounded = false;
+      if (DECL_FUNCTION_CODE (func) == BUILT_IN_STRNCAT)
+       cat_dstlen_bounded = is_strlen_related_p (dst, cnt);
+
       if (lenrange[0] == cntrange[1] && cntrange[0] == cntrange[1])
        return warning_n (callloc, OPT_Wstringop_truncation,
                          cntrange[0].to_uhwi (),
@@ -2024,46 +2030,50 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
                          "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_n (callloc, OPT_Wstringop_truncation,
-                             cntrange[0].to_uhwi (),
-                             "%G%qD output truncated copying %E byte "
-                             "from a string of length %wu",
-                             "%G%qD output truncated copying %E bytes "
-                             "from a string of length %wu",
-                             call, func, cnt, lenrange[0].to_uhwi ());
-
-         return warning_at (callloc, OPT_Wstringop_truncation,
-                            "%G%qD output 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 ());
-       }
-      else if (wi::geu_p (lenrange[1], cntrange[1]))
+      else if (!cat_dstlen_bounded)
        {
-         /* The longest string is longer than the upper bound of
-            the count so the truncation is possible.  */
-         if (cntrange[0] == cntrange[1])
-           return warning_n (callloc, OPT_Wstringop_truncation,
-                             cntrange[0].to_uhwi (),
-                             "%G%qD output may be truncated copying %E "
-                             "byte from a string of length %wu",
-                             "%G%qD output may be truncated copying %E "
-                             "bytes from a string of length %wu",
-                             call, func, cnt, lenrange[1].to_uhwi ());
-
-         return warning_at (callloc, OPT_Wstringop_truncation,
-                            "%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[1].to_uhwi ());
+         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_n (callloc, OPT_Wstringop_truncation,
+                                 cntrange[0].to_uhwi (),
+                                 "%G%qD output truncated copying %E byte "
+                                 "from a string of length %wu",
+                                 "%G%qD output truncated copying %E bytes "
+                                 "from a string of length %wu",
+                                 call, func, cnt, lenrange[0].to_uhwi ());
+
+             return warning_at (callloc, OPT_Wstringop_truncation,
+                                "%G%qD output 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 ());
+           }
+         else if (wi::geu_p (lenrange[1], cntrange[1]))
+           {
+             /* The longest string is longer than the upper bound of
+                the count so the truncation is possible.  */
+             if (cntrange[0] == cntrange[1])
+               return warning_n (callloc, OPT_Wstringop_truncation,
+                                 cntrange[0].to_uhwi (),
+                                 "%G%qD output may be truncated copying %E "
+                                 "byte from a string of length %wu",
+                                 "%G%qD output may be truncated copying %E "
+                                 "bytes from a string of length %wu",
+                                 call, func, cnt, lenrange[1].to_uhwi ());
+
+             return warning_at (callloc, OPT_Wstringop_truncation,
+                                "%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[1].to_uhwi ());
+           }
        }
 
-      if (cntrange[0] != cntrange[1]
+      if (!cat_dstlen_bounded
+         && cntrange[0] != cntrange[1]
          && wi::leu_p (cntrange[0], lenrange[0])
          && wi::leu_p (cntrange[1], lenrange[0] + 1))
        {