This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug c++/81586] valgrind error in output_buffer_append_r with -Wall
- From: "msebor at gcc dot gnu.org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Thu, 27 Jul 2017 21:42:46 +0000
- Subject: [Bug c++/81586] valgrind error in output_buffer_append_r with -Wall
- Auto-submitted: auto-generated
- References: <bug-81586-4@http.gcc.gnu.org/bugzilla/>
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81586
--- Comment #3 from Martin Sebor <msebor at gcc dot gnu.org> ---
I don't see a problem with the code in maybe_warn. It does this:
/* Buffer for the directive in the host character set (used when
the source character set is different). */
char hostdir[32];
...
return fmtwarn (dirloc, pargrange, NULL,
info.warnopt (), fmtstr, dir.len,
target_to_host (hostdir, sizeof hostdir, dir.beg),
res.min, navail);
The call being made has fmtstr = "%<%.*s%> directive output truncated writing
%wu bytes into a region of size %wu", dir.len = 73, and hostdir =
"af_get_next_segv end of file..." (with strlen (hostdir) == 31). With that,
while the "%.*s" directive in fmtstr says to read at most 73 bytes from
hostdir, since hostdir is only 31 characters long, the directive should read
exactly that many and no more than that.
I think the bug is actually in pp_format where the "%.*s" directive is handled:
case '.':
{
int n;
const char *s;
/* We handle '%.Ns' and '%.*s' or '%M$.*N$s'
(where M == N + 1). The format string should be verified
already from the first phase. */
p++;
if (ISDIGIT (*p))
{
char *end;
n = strtoul (p, &end, 10);
p = end;
gcc_assert (*p == 's');
}
else
{
gcc_assert (*p == '*');
p++;
gcc_assert (*p == 's');
n = va_arg (*text->args_ptr, int);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Here n is extracted from the variable argument list (the corresponding argument
is dir.len).
/* This consumes a second entry in the formatters array. */
gcc_assert (formatters[argno] == formatters[argno+1]);
argno++;
}
s = va_arg (*text->args_ptr, const char *);
pp_append_text (pp, s, s + n);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Here s points to hostdir and n is 73, but strlen(s) is just 31. This code
doesn't handle the precision correctly. The precision is the maximum number of
non-nul characters to print. The fix is to set n to be no greater than
strlen(s):
if (strlen (s) < n)
n = strlen (s);
pp_append_text (pp, s, s + n);