When XML mode is selected messages from VALGRIND_PRINTF and friends

should go to the XML stream not stderr.  Fixes BZ 322807.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13516
This commit is contained in:
Florian Krohm 2013-08-27 15:17:53 +00:00
parent acbf92d975
commit 089f1ef803
9 changed files with 249 additions and 12 deletions

3
NEWS
View File

@ -443,6 +443,9 @@ FIXED r??
321960 pthread_create() then alloca() causing invalid stack write errors
FIXED 13467
322807 VALGRIND_PRINTF_BACKTRACE writes callstack to xml and text to stderr
FIXED 13516
322851 0bXXX binary literal syntax is not standard
FIXED 2736

View File

@ -1654,6 +1654,76 @@ static Bool os_client_request(ThreadId tid, UWord *args)
}
/* Write out a client message, possibly including a back trace. Return
the number of characters written. In case of XML output, the format
string as well as any arguments it requires will be XML'ified.
I.e. special characters such as the angle brackets will be translated
into proper escape sequences. */
static
Int print_client_message( ThreadId tid, const HChar *format,
va_list *vargsp, Bool include_backtrace)
{
Int count;
if (VG_(clo_xml)) {
/* Translate the format string as follows:
< --> &lt;
> --> &gt;
& --> &amp;
%s --> %pS
Yes, yes, it's simplified but in synch with
myvprintf_str_XML_simplistic and VG_(debugLog_vprintf).
*/
/* Allocate a buffer that is for sure large enough. */
HChar xml_format[VG_(strlen)(format) * 5 + 1];
const HChar *p;
HChar *q = xml_format;
for (p = format; *p; ++p) {
switch (*p) {
case '<': VG_(strcpy)(q, "&lt;"); q += 4; break;
case '>': VG_(strcpy)(q, "&gt;"); q += 4; break;
case '&': VG_(strcpy)(q, "&amp;"); q += 5; break;
case '%':
/* Careful: make sure %%s stays %%s */
*q++ = *p++;
if (*p == 's') {
*q++ = 'p';
*q++ = 'S';
} else {
*q++ = *p;
}
break;
default:
*q++ = *p;
break;
}
}
*q = '\0';
VG_(printf_xml)( "<clientmsg>\n" );
VG_(printf_xml)( " <tid>%d</tid>\n", tid );
VG_(printf_xml)( " <text>" );
count = VG_(vprintf_xml)( xml_format, *vargsp );
VG_(printf_xml)( " </text>\n" );
} else {
count = VG_(vmessage)( Vg_ClientMsg, format, *vargsp );
VG_(message_flush)();
}
if (include_backtrace)
VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
if (VG_(clo_xml))
VG_(printf_xml)( "</clientmsg>\n" );
return count;
}
/* Do a client request for the thread tid. After the request, tid may
or may not still be runnable; if not, the scheduler will have to
choose a new thread to run.
@ -1708,6 +1778,7 @@ void do_client_request ( ThreadId tid )
break;
case VG_USERREQ__PRINTF: {
const HChar* format = (HChar *)arg[1];
/* JRS 2010-Jan-28: this is DEPRECATED; use the
_VALIST_BY_REF version instead */
if (sizeof(va_list) != sizeof(UWord))
@ -1718,13 +1789,14 @@ void do_client_request ( ThreadId tid )
} u;
u.uw = (unsigned long)arg[2];
Int count =
VG_(vmessage)( Vg_ClientMsg, (HChar *)arg[1], u.vargs );
VG_(message_flush)();
print_client_message( tid, format, &u.vargs,
/* include_backtrace */ False );
SET_CLREQ_RETVAL( tid, count );
break;
}
case VG_USERREQ__PRINTF_BACKTRACE: {
const HChar* format = (HChar *)arg[1];
/* JRS 2010-Jan-28: this is DEPRECATED; use the
_VALIST_BY_REF version instead */
if (sizeof(va_list) != sizeof(UWord))
@ -1735,28 +1807,29 @@ void do_client_request ( ThreadId tid )
} u;
u.uw = (unsigned long)arg[2];
Int count =
VG_(vmessage)( Vg_ClientMsg, (HChar *)arg[1], u.vargs );
VG_(message_flush)();
VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
print_client_message( tid, format, &u.vargs,
/* include_backtrace */ True );
SET_CLREQ_RETVAL( tid, count );
break;
}
case VG_USERREQ__PRINTF_VALIST_BY_REF: {
const HChar* format = (HChar *)arg[1];
va_list* vargsp = (va_list*)arg[2];
Int count =
VG_(vmessage)( Vg_ClientMsg, (HChar *)arg[1], *vargsp );
VG_(message_flush)();
Int count =
print_client_message( tid, format, vargsp,
/* include_backtrace */ False );
SET_CLREQ_RETVAL( tid, count );
break;
}
case VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF: {
const HChar* format = (HChar *)arg[1];
va_list* vargsp = (va_list*)arg[2];
Int count =
VG_(vmessage)( Vg_ClientMsg, (HChar *)arg[1], *vargsp );
VG_(message_flush)();
VG_(get_and_pp_StackTrace)( tid, VG_(clo_backtrace_size) );
print_client_message( tid, format, vargsp,
/* include_backtrace */ True );
SET_CLREQ_RETVAL( tid, count );
break;
}

View File

@ -190,7 +190,7 @@ the following in sequence:
human-understandable. In current Valgrind versions it is the
elapsed wallclock time since process start.
* Zero or more of (either ERRORCOUNTS or TOOLSPECIFIC).
* Zero or more of (either ERRORCOUNTS, TOOLSPECIFIC, or CLIENTMSG).
* The following, indicating that the program has now finished, and
that the any final wrapup (eg, for Memcheck, leak checking) is happening.
@ -699,3 +699,36 @@ The possible values are:
One of various miscellaneous noteworthy conditions was observed
(eg, thread exited whilst holding locks, "impossible" behaviour
from the underlying threading library, etc)
====================================================================
CLIENTMSG
CLIENTMSG defines a message that was caused by one of the following
client requests:
- VALGRIND_PRINTF
- VALGRIND_PRINTF_BACKTRACE
Definition:
<clientmsg>
<tid>INT</tid>
<text>...</text>
</clientmsg>
OR
<clientmsg>
<tid>INT</tid>
<text>...</text>
STACK
</clientmsg>
* The <tid> tag indicates the Valgrind thread number.
* The <text> tag indicates the message as specified in the client request
(properly translated to XML).
* STACK is only present in case of VALGRIND_PRINTF_BACKTRACE. See above
for a definition of STACK.

View File

@ -74,6 +74,8 @@ EXTRA_DIST = \
buflen_check.stderr.exp-kfail \
bug287260.stderr.exp bug287260.vgtest \
calloc-overflow.stderr.exp calloc-overflow.vgtest\
client-msg.stderr.exp client-msg.vgtest \
client-msg-as-xml.stderr.exp client-msg-as-xml.vgtest \
clientperm.stderr.exp \
clientperm.stdout.exp clientperm.vgtest \
clireq_nofill.stderr.exp \
@ -273,6 +275,7 @@ check_PROGRAMS = \
buflen_check \
bug287260 \
calloc-overflow \
client-msg \
clientperm \
clireq_nofill \
clo_redzone \

View File

@ -0,0 +1,90 @@
<?xml version="1.0"?>
<valgrindoutput>
<protocolversion>4</protocolversion>
<protocoltool>memcheck</protocoltool>
<preamble>
<line>...</line>
<line>...</line>
<line>...</line>
<line>...</line>
</preamble>
<pid>...</pid>
<ppid>...</ppid>
<tool>memcheck</tool>
<args>
<vargv>...</vargv>
<argv>
<exe>./client-msg</exe>
</argv>
</args>
<status>
<state>RUNNING</state>
<time>...</time>
</status>
<clientmsg>
<tid>...</tid>
<text>hello &lt;&gt; &lt;&amp;&gt;%s world
</text>
<stack>
<frame>
<ip>0x........</ip>
<obj>...</obj>
<fn>VALGRIND_PRINTF_BACKTRACE</fn>
<dir>...</dir>
<file>valgrind.h</file>
<line>...</line>
</frame>
<frame>
<ip>0x........</ip>
<obj>...</obj>
<fn>baz</fn>
<dir>...</dir>
<file>client-msg.c</file>
<line>...</line>
</frame>
<frame>
<ip>0x........</ip>
<obj>...</obj>
<fn>bar</fn>
<dir>...</dir>
<file>client-msg.c</file>
<line>...</line>
</frame>
<frame>
<ip>0x........</ip>
<obj>...</obj>
<fn>foo</fn>
<dir>...</dir>
<file>client-msg.c</file>
<line>...</line>
</frame>
<frame>
<ip>0x........</ip>
<obj>...</obj>
<fn>main</fn>
<dir>...</dir>
<file>client-msg.c</file>
<line>...</line>
</frame>
</stack>
</clientmsg>
<status>
<state>FINISHED</state>
<time>...</time>
</status>
<errorcounts>
</errorcounts>
<suppcounts>...</suppcounts>
</valgrindoutput>

View File

@ -0,0 +1,3 @@
prog: client-msg
vgopts: --xml=yes --xml-fd=2 --log-file=/dev/null
stderr_filter: filter_xml

View File

@ -0,0 +1,24 @@
#include "valgrind.h"
void baz()
{
VALGRIND_PRINTF_BACKTRACE("hello <> %s%%s world\n","<&>");
}
void bar()
{
baz();
}
void foo()
{
bar();
}
int main()
{
foo();
return 0;
}

View File

@ -0,0 +1,6 @@
hello <> <&>%s world
...
by 0x........: baz (client-msg.c:5)
by 0x........: bar (client-msg.c:10)
by 0x........: foo (client-msg.c:15)
by 0x........: main (client-msg.c:20)

View File

@ -0,0 +1,2 @@
prog: client-msg
vgopts: -q