+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
+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
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);
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);
--- /dev/null
+// 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;
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
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);