summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormsebor <msebor@138bc75d-0d04-0410-961f-82ee72b054a4>2018-03-07 19:30:31 +0000
committermsebor <msebor@138bc75d-0d04-0410-961f-82ee72b054a4>2018-03-07 19:30:31 +0000
commitdc4a43f21b0aa4eb16cf1a2958edfff6de8d020a (patch)
tree06a0c23188ccd0d051f0d12c261d793b03baaa68
parent720d31166435c7d4446bc6323301914cd52fcdab (diff)
downloadgcc-dc4a43f21b0aa4eb16cf1a2958edfff6de8d020a.tar.gz
PR tree-optimization/84468 - bogus -Wstringop-truncation despite assignment after conditional strncpy
gcc/ChangeLog: PR tree-optimization/84468 * tree-ssa-strlen.c (maybe_diag_stxncpy_trunc): Consider successor basic block when looking for nul assignment. gcc/testsuite/ChangeLog: PR tree-optimization/84468 * g++.dg/warn/Wstringop-truncation-2.C: New test. * gcc.dg/Wstringop-truncation.c: New test. * gcc.dg/Wstringop-truncation-2.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@258339 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/g++.dg/warn/Wstringop-truncation-1.C4
-rw-r--r--gcc/testsuite/g++.dg/warn/Wstringop-truncation-2.C164
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-truncation-2.c126
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-truncation.c131
-rw-r--r--gcc/tree-ssa-strlen.c27
7 files changed, 462 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 00b79a553c9..1e988ed7199 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2018-03-07 Martin Sebor <msebor@redhat.com>
+
+ PR tree-optimization/84468
+ * tree-ssa-strlen.c (maybe_diag_stxncpy_trunc): Consider successor
+ basic block when looking for nul assignment.
+
2018-03-07 Eric Botcazou <ebotcazou@adacore.com>
PR target/84277
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 2bf1abbd5b6..8e273c6bf6c 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2018-03-07 Martin Sebor <msebor@redhat.com>
+
+ PR tree-optimization/84468
+ * g++.dg/warn/Wstringop-truncation-2.C: New test.
+ * gcc.dg/Wstringop-truncation.c: New test.
+ * gcc.dg/Wstringop-truncation-2.c: New test.
+
2018-03-07 Jakub Jelinek <jakub@redhat.com>
PR fortran/84565
diff --git a/gcc/testsuite/g++.dg/warn/Wstringop-truncation-1.C b/gcc/testsuite/g++.dg/warn/Wstringop-truncation-1.C
index a502b78b711..83066019772 100644
--- a/gcc/testsuite/g++.dg/warn/Wstringop-truncation-1.C
+++ b/gcc/testsuite/g++.dg/warn/Wstringop-truncation-1.C
@@ -37,7 +37,7 @@ void good_nowarn_size_m1 ()
sink (&str);
}
-void good_nowarn_size_m1_var (const char* s)
+static void good_nowarn_size_m1_var (const char* s)
{
GoodString<3> str (s); // { dg-bogus "\\\[-Wstringop-truncation]" }
sink (&str);
@@ -112,7 +112,7 @@ private:
char str[N + 1];
};
-void bad3_warn_size_m1_var (const char *s)
+static void bad3_warn_size_m1_var (const char *s)
{
BadString3<3> str (s);
sink (&str);
diff --git a/gcc/testsuite/g++.dg/warn/Wstringop-truncation-2.C b/gcc/testsuite/g++.dg/warn/Wstringop-truncation-2.C
new file mode 100644
index 00000000000..ebbd44307d9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wstringop-truncation-2.C
@@ -0,0 +1,164 @@
+// PR tree-optimization/84468 - bogus -Wstringop-truncation despite
+// assignment after conditional strncpy
+// Compile with -g to verify the warning deals properly with debug
+// statements.
+// { dg-do compile }
+// { dg-options "-O2 -Wstringop-truncation -g" }
+
+extern "C" char* strncpy (char*, const char*, __SIZE_TYPE__);
+
+char d[3];
+
+void g ();
+
+void fnowarn1 (const char *s)
+{
+ // Update dummy but never actually use it so it's eliminated
+ // but causes debugging statements to be emitted for each
+ // modification.
+ int dummy = 0;
+
+ try
+ {
+ g ();
+ strncpy (d, s, sizeof d); // { dg-bogus "\\\[-Wstringop-truncation]" }
+ ++dummy;
+ }
+ catch (...)
+ {
+ ++dummy;
+ d[0] = 0;
+ }
+
+ ++dummy;
+ d[sizeof d - 1] = 0;
+}
+
+void fnowarn2 (const char *s)
+{
+ int dummy = 0;
+
+ try
+ {
+ g ();
+ strncpy (d, s, sizeof d);
+ ++dummy;
+ }
+ catch (...)
+ {
+ ++dummy;
+ return;
+ }
+
+ ++dummy;
+ d[sizeof d - 1] = 0;
+}
+
+void fnowarn3 (const char *s)
+{
+ int dummy = 0;
+
+ try
+ {
+ g ();
+ strncpy (d, s, sizeof d);
+ ++dummy;
+ try
+ {
+ ++dummy;
+ d[sizeof d - 1] = 0;
+ g ();
+ }
+ catch (...)
+ {
+ ++dummy;
+ }
+ }
+ catch (...)
+ {
+ ++dummy;
+ return;
+ }
+
+ ++dummy;
+ d[sizeof d - 1] = 0;
+}
+
+void fnowarn4 (const char *s)
+{
+ int dummy = 0;
+
+ try
+ {
+ g ();
+ }
+ catch (...)
+ {
+ strncpy (d, s, sizeof d); // { dg-bogus "\\\[-Wstringop-truncation]" "bug 84468" { xfail *-*-*} }
+ ++dummy;
+ }
+
+ ++dummy;
+ d[sizeof d - 1] = 0;
+}
+
+void fwarn1 (const char *s)
+{
+ int dummy = 0;
+
+ try
+ {
+ ++dummy;
+ g ();
+ ++dummy;
+ strncpy (d, s, sizeof d); // { dg-warning "\\\[-Wstringop-truncation]" }
+ ++dummy;
+ }
+ catch (...)
+ {
+ ++dummy;
+ }
+
+ ++dummy;
+}
+
+void fwarn2 (const char *s)
+{
+ int dummy = 0;
+
+ try
+ {
+ ++dummy;
+ strncpy (d, s, sizeof d); // { dg-warning "\\\[-Wstringop-truncation]" }
+ ++dummy;
+ g ();
+ ++dummy;
+ }
+ catch (...)
+ {
+ ++dummy;
+ }
+
+ ++dummy;
+}
+
+void fwarn3 (const char *s)
+{
+ int dummy = 0;
+
+ try
+ {
+ ++dummy;
+ g ();
+ ++dummy;
+ strncpy (d, s, sizeof d); // { dg-warning "\\\[-Wstringop-truncation]" }
+ ++dummy;
+ }
+ catch (...)
+ {
+ ++dummy;
+ d[0] = 0;
+ }
+
+ ++dummy;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-truncation-2.c b/gcc/testsuite/gcc.dg/Wstringop-truncation-2.c
new file mode 100644
index 00000000000..707a511d92e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-truncation-2.c
@@ -0,0 +1,126 @@
+/* PR tree-optimization/84468 - bogus -Wstringop-truncation despite
+ assignment after conditional strncpy
+ { dg-do compile }
+ { dg-options "-O2 -Wstringop-truncation -g" } */
+
+extern char* strncpy (char*, const char*, __SIZE_TYPE__);
+
+char a[4];
+
+void f1 (char *s)
+{
+ int i = 0;
+
+ if (s[0] == '0')
+ {
+ i += 1;
+ strncpy (a, s, sizeof a); /* { dg-bogus "\\\[-Wstringop-truncation]" } */
+ }
+ else
+ i += 2;
+
+ a[sizeof a - 1] = 0;
+}
+
+void f2 (char *s)
+{
+ int i = 0;
+
+ if (s[0] == '0')
+ {
+ i += 1;
+ if (s[1] == '1')
+ {
+ i += 2;
+ strncpy (a, s, sizeof a); /* { dg-bogus "\\\[-Wstringop-truncation]" } */
+ }
+ else
+ i += 3;
+ }
+ else
+ i += 4;
+
+ a[sizeof a - 1] = 0;
+}
+
+void f3 (char *s)
+{
+ int i = 0;
+
+ if (s[0] == '0')
+ {
+ i += 1;
+ if (s[1] == '1')
+ {
+ i += 2;
+ if (s[2] == '2')
+ strncpy (a, s, sizeof a); /* { dg-bogus "\\\[-Wstringop-truncation]" } */
+ else
+ i += 3;
+ }
+ else
+ i += 4;
+ }
+ else
+ i += 5;
+
+ a[sizeof a - 1] = 0;
+}
+
+void f4 (char *s)
+{
+ int i = 0;
+
+ if (s[0] == '0')
+ {
+ i += 1;
+ if (s[1] == '1')
+ {
+ i += 2;
+ if (s[2] == '2')
+ {
+ i += 3;
+ if (s[3] == '3')
+ strncpy (a, s, sizeof a); /* { dg-bogus "\\\[-Wstringop-truncation]" } */
+ else
+ i += 4;
+ }
+ else
+ i += 5;
+ }
+ else
+ i += 6;
+ }
+ else
+ i += 7;
+
+ a[sizeof a - 1] = 0;
+}
+
+void f4_warn (char *s)
+{
+ int i = 0;
+
+ if (s[0] == '0')
+ {
+ i += 1;
+ if (s[1] == '1')
+ {
+ i += 2;
+ if (s[2] == '2')
+ {
+ i += 3;
+ if (s[3] == '3')
+ strncpy (a, s, sizeof a); /* { dg-warning "\\\[-Wstringop-truncation]" } */
+ else
+ i += 4;
+ }
+ else
+ i += 5;
+ }
+ else
+ i += 6;
+ }
+ else
+ i += 7;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-truncation.c b/gcc/testsuite/gcc.dg/Wstringop-truncation.c
new file mode 100644
index 00000000000..b5372967790
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-truncation.c
@@ -0,0 +1,131 @@
+/* PR tree-optimization/84468 - Inconsistent -Wstringop-truncation warnings
+ with -O2
+ { dg-do compile }
+ { dg-options "-O2 -Wstringop-truncation -ftrack-macro-expansion=0 -g" } */
+
+#define strncpy __builtin_strncpy
+
+struct A
+{
+ char a[4];
+};
+
+void no_pred_succ_lit (struct A *p)
+{
+ /* The following is folded early on, before the strncpy statement
+ has a basic block. Verify that the case is handled gracefully
+ (i.e., there's no assumption that the statement does have
+ a basic block). */
+ strncpy (p->a, "1234", sizeof p->a - 1); /* { dg-warning "\\\[-Wstringop-truncation" } */
+}
+
+/* Verify a strncpy call in a basic block with no predecessor or
+ successor. */
+void no_pred_succ (struct A *p, const struct A *q)
+{
+ strncpy (p->a, q->a, sizeof p->a - 1); /* { dg-warning "\\\[-Wstringop-truncation" } */
+}
+
+
+/* Verify a strncpy call in a basic block with no successor. */
+void no_succ (struct A *p, const struct A *q)
+{
+ if (q->a)
+ strncpy (p->a, q->a, sizeof p->a - 1); /* { dg-warning "\\\[-Wstringop-truncation" } */
+}
+
+/* Verify a strncpy call in a basic block with nul assignment in
+ a successor block. */
+void succ (struct A *p, const struct A *q)
+{
+ /* Verify that the assignment suppresses the warning for the conditional
+ strcnpy call. The conditional should be folded to true since the
+ address of an array can never be null (see bug 84470). */
+ if (q->a)
+ strncpy (p->a, q->a, sizeof p->a - 1); /* { dg-bogus "\\\[-Wstringop-truncation" } */
+
+ p->a[sizeof p->a - 1] = 0;
+}
+
+
+void succ_2 (struct A *p, const struct A *q, int i)
+{
+ /* Same as above but with a conditional that cannot be eliminated. */
+ if (i < 0)
+ strncpy (p->a, q->a, sizeof p->a - 1); /* { dg-bogus "\\\[-Wstringop-truncation" } */
+
+ p->a[sizeof p->a - 1] = 0;
+}
+
+
+/* Verify a strncpy call in a basic block with nul assignment in
+ the next successor block. */
+int next_succ (struct A *p, const struct A *q, int i, int j)
+{
+ /* Same as above but with a nested conditionals with else clauses. */
+ if (i < 0)
+ {
+ if (j < 0)
+ strncpy (p->a, q->a, sizeof p->a - 1); /* { dg-bogus "\\\[-Wstringop-truncation" } */
+ }
+ else
+ __builtin_strcpy (p->a, q->a);
+
+ p->a[sizeof p->a - 1] = 0;
+ return 0;
+}
+
+
+int next_succ_1 (struct A *p, const struct A *q, int i, int j)
+{
+ /* Same as above but with a nested conditionals with else clauses. */
+ if (i < 0)
+ {
+ if (j < 0)
+ strncpy (p->a, q->a, sizeof p->a - 1); /* { dg-bogus "\\\[-Wstringop-truncation" } */
+ else
+ strncpy (p->a, q->a, sizeof p->a - 2); /* { dg-bogus "\\\[-Wstringop-truncation" } */
+ }
+
+ p->a[sizeof p->a - 2] = 0;
+ return 1;
+}
+
+
+int next_succ_2 (struct A *p, const struct A *q, int i, int j)
+{
+ /* Same as above but with a nested conditionals with else clauses. */
+ if (i < 0)
+ {
+ if (j < 0)
+ strncpy (p->a, q->a, sizeof p->a - 1); /* { dg-bogus "\\\[-Wstringop-truncation" } */
+ else
+ strncpy (p->a, q->a, sizeof p->a - 2); /* { dg-bogus "\\\[-Wstringop-truncation" } */
+ }
+ else
+ __builtin_strcpy (p->a, q->a);
+
+ p->a[sizeof p->a - 2] = 0;
+ return 2;
+}
+
+
+void cond_succ_warn (struct A *p, const struct A *q, int i)
+{
+ /* Verify that a conditional assignment doesn't suppress the warning. */
+ strncpy (p->a, q->a, sizeof p->a - 1); /* { dg-warning "\\\[-Wstringop-truncation" } */
+
+ if (i < 0)
+ p->a[sizeof p->a - 1] = 0;
+}
+
+void cond_succ_nowarn (struct A *p, const struct A *q)
+{
+ /* Verify that distinct but provably equivalent conditionals are
+ recognized and don't trigger the warning. */
+ if (p != q)
+ strncpy (p->a, q->a, sizeof p->a - 1);
+
+ if (p->a != q->a)
+ p->a[sizeof p->a - 1] = 0;
+}
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 1266f399373..72f6a17cd32 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -1856,8 +1856,33 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
avoid the truncation warning. */
gsi_next_nondebug (&gsi);
gimple *next_stmt = gsi_stmt (gsi);
+ if (!next_stmt)
+ {
+ /* When there is no statement in the same basic block check
+ the immediate successor block. */
+ if (basic_block bb = gimple_bb (stmt))
+ {
+ if (single_succ_p (bb))
+ {
+ /* For simplicity, ignore blocks with multiple outgoing
+ edges for now and only consider successor blocks along
+ normal edges. */
+ edge e = EDGE_SUCC (bb, 0);
+ if (!(e->flags & EDGE_ABNORMAL))
+ {
+ gsi = gsi_start_bb (e->dest);
+ next_stmt = gsi_stmt (gsi);
+ if (next_stmt && is_gimple_debug (next_stmt))
+ {
+ gsi_next_nondebug (&gsi);
+ next_stmt = gsi_stmt (gsi);
+ }
+ }
+ }
+ }
+ }
- if (!gsi_end_p (gsi) && is_gimple_assign (next_stmt))
+ if (next_stmt && is_gimple_assign (next_stmt))
{
tree lhs = gimple_assign_lhs (next_stmt);
tree_code code = TREE_CODE (lhs);