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 <ja...@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