Unlike strcat and strcpy, it is valid for strncat and strncpy
to result in modifying the source string by overwriting its
terminating nul.  The attached patch removes an assumption
to the contrary introduced with the -Wstringop-truncation
enhancement.

Martin
PR tree-optimization/83075 - Invalid strncpy optimization

gcc/ChangeLog:

	PR tree-optimization/83075
	* tree-ssa-strlen.c (handle_builtin_stxncpy): Avoid assuming
	strncat/strncpy don't change length of source string.

gcc/testsuite/ChangeLog:

	PR tree-optimization/83075
	* gcc.dg/tree-ssa/strncat.c: New test.
	* gcc.dg/tree-ssa/strncpy-2.c: Same.

Index: gcc/testsuite/gcc.dg/tree-ssa/strncat.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/strncat.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/tree-ssa/strncat.c	(working copy)
@@ -0,0 +1,22 @@
+/* PR tree-optimization/83075 - Invalid strncpy optimization
+   { dg-do compile }
+   { dg-options "-O2 -Wno-stringop-overflow -fdump-tree-optimized" } */
+
+void test_overlapping_strncpy (void)
+{
+  char a[8] = "";
+
+  __builtin_strcpy (a, "123");
+
+  unsigned n0 = __builtin_strlen (a);
+
+  __builtin_strncat (a + 3, a, n0);
+
+  unsigned n1 = __builtin_strlen (a);
+
+  if (n1 == n0)
+    __builtin_abort ();
+}
+
+/* Verify the call to abort hasn't been eliminated.
+   { dg-final { scan-tree-dump-times "abort" 1 "optimized" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/strncpy-2.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/strncpy-2.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/tree-ssa/strncpy-2.c	(working copy)
@@ -0,0 +1,22 @@
+/* PR tree-optimization/83075 - Invalid strncpy optimization
+   { dg-do compile }
+   { dg-options "-O2 -Wno-stringop-overflow -fdump-tree-optimized" } */
+
+void test_overlapping_strncpy (void)
+{
+  char a[8] = "";
+
+  __builtin_strcpy (a, "123");
+
+  unsigned n0 = __builtin_strlen (a);
+
+  __builtin_strncpy (a + 3, a, n0);
+
+  unsigned n1 = __builtin_strlen (a);
+
+  if (n1 == n0)
+    __builtin_abort ();
+}
+
+/* Verify the call to abort hasn't been eliminated.
+   { dg-final { scan-tree-dump-times "abort" 1 "optimized" } } */
Index: gcc/tree-ssa-strlen.c
===================================================================
--- gcc/tree-ssa-strlen.c	(revision 254961)
+++ gcc/tree-ssa-strlen.c	(working copy)
@@ -1931,10 +1931,9 @@ handle_builtin_stxncpy (built_in_function, gimple_
   int sidx = get_stridx (src);
   strinfo *sisrc = sidx > 0 ? get_strinfo (sidx) : NULL;
 
-  /* Strncpy() et al. cannot modify the source string.  Prevent the rest
-     of the pass from invalidating the strinfo data.  */
-  if (sisrc)
-    sisrc->dont_invalidate = true;
+  /* Strncat() and strncpy() can modify the source string by specifying
+     as a destination SRC + strlen(SRC) and a bound <= strlen(SRC) so
+     SISRC->DONT_INVALIDATE must be left clear.  */
 
   /* Retrieve the strinfo data for the string S that LEN was computed
      from as some function F of strlen (S) (i.e., LEN need not be equal

Reply via email to