[PATCH] Fix up target_to_host fn in gimple-ssa-sprintf.c (PR c++/90010)

Jakub Jelinek jakub@redhat.com
Tue Apr 9 21:48:00 GMT 2019


Hi!

As the following testcase shows, target_to_host handled
targstr with strlen shorter than hostsz - 4 right (though with wasteful
clearing of the rest of the buffer when only one '\0' termination is enough)
and similarly also strlen hostsz and more right (making last 4 characters
in the buffer "..."), but anything in between resulted in random byte(s)
at the end of the string (strncpy with hostsz - 4 length didn't zero
terminate and because strlen (targstr) >= hostsz was false, nothing was
appended).  When some target to host charset adjustment was needed, it
appended that "..." even to strings that actually didn't need it.

The following patch doesn't use "..." if targstr fits (including the zero
termination), otherwise makes sure last 4 bytes in the buffer are "...".
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2019-04-09  Jakub Jelinek  <jakub@redhat.com>

	PR c++/90010
	* gimple-ssa-sprintf.c (target_to_host): Fix handling of targstr
	with strlen in between hostsz-3 and hostsz-1 inclusive when no
	translation is needed, and when translation is needed, only append
	... if the string length is hostsz or more bytes long.  Avoid using
	strncpy or strcat.

	* gcc.dg/pr90010.c: New test.

--- gcc/gimple-ssa-sprintf.c.jj	2019-04-09 12:25:41.000000000 +0200
+++ gcc/gimple-ssa-sprintf.c	2019-04-09 14:01:04.875445413 +0200
@@ -383,9 +383,14 @@ target_to_host (char *hostr, size_t host
      overlong strings just like the translated strings are.  */
   if (target_to_host_charmap['\0'] == 1)
     {
-      strncpy (hostr, targstr, hostsz - 4);
-      if (strlen (targstr) >= hostsz)
-	strcpy (hostr + hostsz - 4, "...");
+      size_t len = strlen (targstr);
+      if (len >= hostsz)
+	{
+	  memcpy (hostr, targstr, hostsz - 4);
+	  strcpy (hostr + hostsz - 4, "...");
+	}
+      else
+	memcpy (hostr, targstr, len + 1);
       return hostr;
     }
 
@@ -399,10 +404,9 @@ target_to_host (char *hostr, size_t host
       if (!*targstr)
 	break;
 
-      if (size_t (ph - hostr) == hostsz - 4)
+      if (size_t (ph - hostr) == hostsz)
 	{
-	  *ph = '\0';
-	  strcat (ph, "...");
+	  strcpy (ph - 4, "...");
 	  break;
 	}
     }
--- gcc/testsuite/gcc.dg/pr90010.c.jj	2019-04-09 14:22:14.795791124 +0200
+++ gcc/testsuite/gcc.dg/pr90010.c	2019-04-09 14:26:10.274961523 +0200
@@ -0,0 +1,27 @@
+/* PR c++/90010 */
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+
+char b[4096] = "abc";
+void bar (char *);
+
+void
+foo ()
+{
+  char d[4096];
+  __builtin_snprintf (d, sizeof d, "%sfoobarbazquxquuxquuzthudfred", b);	/* { dg-warning "'foobarbazquxquuxquuzthudfred' directive output may be truncated writing 28 bytes into a region of size between 1 and 4096" } */
+  /* { dg-message "'__builtin_snprintf' output between 29 and 4124 bytes into a destination of size 4096" "" { target *-*-* } .-1 } */
+  bar (d);
+  __builtin_snprintf (d, sizeof d, "%sfoobarbazquxquuxquuzcorgefred", b);	/* { dg-warning "'foobarbazquxquuxquuzcorgefred' directive output may be truncated writing 29 bytes into a region of size between 1 and 4096" } */
+  /* { dg-message "'__builtin_snprintf' output between 30 and 4125 bytes into a destination of size 4096" "" { target *-*-* } .-1 } */
+  bar (d);
+  __builtin_snprintf (d, sizeof d, "%sfoobarbazquxquuxquuzcorgewaldo", b);	/* { dg-warning "'foobarbazquxquuxquuzcorgewaldo' directive output may be truncated writing 30 bytes into a region of size between 1 and 4096" } */
+  /* { dg-message "'__builtin_snprintf' output between 31 and 4126 bytes into a destination of size 4096" "" { target *-*-* } .-1 } */
+  bar (d);
+  __builtin_snprintf (d, sizeof d, "%sfoobarbazquxquuxquuzcorgegarply", b);	/* { dg-warning "'foobarbazquxquuxquuzcorgegarply' directive output may be truncated writing 31 bytes into a region of size between 1 and 4096" } */
+  /* { dg-message "'__builtin_snprintf' output between 32 and 4127 bytes into a destination of size 4096" "" { target *-*-* } .-1 } */
+  bar (d);
+  __builtin_snprintf (d, sizeof d, "%sfoobarfredquxquuxquuzcorgegarply", b);	/* { dg-warning "'foobarfredquxquuxquuzcorgega\.\.\.' directive output may be truncated writing 32 bytes into a region of size between 1 and 4096" } */
+  /* { dg-message "'__builtin_snprintf' output between 33 and 4128 bytes into a destination of size 4096" "" { target *-*-* } .-1 } */
+  bar (d);
+}

	Jakub



More information about the Gcc-patches mailing list