summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormsebor <msebor@138bc75d-0d04-0410-961f-82ee72b054a4>2018-02-22 17:35:29 +0000
committermsebor <msebor@138bc75d-0d04-0410-961f-82ee72b054a4>2018-02-22 17:35:29 +0000
commitbcb285a0b5a8765d45cf828a175a5d053e2a1e2a (patch)
tree6ddd58eb12d9e64c3ae7a6ca7afaab4501d2b47d
parent95b8f16f0c0ceef491a2b776533935877829fe0d (diff)
downloadgcc-bcb285a0b5a8765d45cf828a175a5d053e2a1e2a.tar.gz
PR tree-optimization/84480 - bogus -Wstringop-truncation despite assignment with an inlined string literal
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@257910 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/gimple-fold.c34
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/c-c++-common/Wstringop-truncation.c6
-rw-r--r--gcc/testsuite/g++.dg/warn/Wstringop-truncation-1.C126
-rw-r--r--gcc/tree-ssa-strlen.c74
-rw-r--r--gcc/tree-ssa-strlen.h26
7 files changed, 220 insertions, 62 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1868bb6d83f..9e737edec02 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 0b7553160b5..8257873dd20 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -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);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d85d8a52dd6..e58ed9be1c6 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/c-c++-common/Wstringop-truncation.c b/gcc/testsuite/c-c++-common/Wstringop-truncation.c
index dc8c618976e..bd520915502 100644
--- a/gcc/testsuite/c-c++-common/Wstringop-truncation.c
+++ b/gcc/testsuite/c-c++-common/Wstringop-truncation.c
@@ -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
index 00000000000..a502b78b711
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wstringop-truncation-1.C
@@ -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 }
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 09ffa154439..71ed0ff1b45 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -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
index 00000000000..1399a7819eb
--- /dev/null
+++ b/gcc/tree-ssa-strlen.h
@@ -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