aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/gimple-fold.c8
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-truncation-4.c63
-rw-r--r--gcc/tree-ssa-strlen.c84
5 files changed, 127 insertions, 40 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 07db821..5334c36 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,12 @@
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.
2018-06-25 Michael Meissner <meissner@linux.ibm.com>
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index a01bce7..b025935 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -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))
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f2d9caf..4606474 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..f394863
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-truncation-4.c
@@ -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]" } */
+}
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 92545b9..2da82a8 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -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))
{