mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-03 10:05:29 +00:00
Memcheck:
* add delta leak checking functionality * some editing of related manual sections (Philippe Waroquiers, philippe.waroquiers@skynet.be). Bug 214909 comment 105. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11838
This commit is contained in:
parent
64940ed44a
commit
5c1e65aa42
@ -495,12 +495,12 @@ of the Valgrind core monitor commands.
|
||||
|
||||
<para>Each tool can also provide tool-specific monitor commands.
|
||||
An example of a tool specific monitor command is the Memcheck monitor
|
||||
command <computeroutput>mc.leak_check any full
|
||||
reachable</computeroutput>. This requests a full reporting of the
|
||||
command <computeroutput>mc.leak_check full
|
||||
reachable any</computeroutput>. This requests a full reporting of the
|
||||
allocated memory blocks. To have this leak check executed, use the GDB
|
||||
command:
|
||||
<screen><![CDATA[
|
||||
(gdb) monitor mc.leak_check any full reachable
|
||||
(gdb) monitor mc.leak_check full reachable any
|
||||
]]></screen>
|
||||
</para>
|
||||
|
||||
@ -511,7 +511,7 @@ monitor command. If it is not recognised as such, it is assumed to
|
||||
be tool-specific and is handed to the tool for execution. For example:
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
(gdb) monitor mc.leak_check any full reachable
|
||||
(gdb) monitor mc.leak_check full reachable any
|
||||
==2418== 100 bytes in 1 blocks are still reachable in loss record 1 of 1
|
||||
==2418== at 0x4006E9E: malloc (vg_replace_malloc.c:236)
|
||||
==2418== by 0x804884F: main (prog.c:88)
|
||||
@ -532,12 +532,12 @@ abbreviation is unambiguous. For example, the above
|
||||
<computeroutput>mc.leak_check</computeroutput>
|
||||
command can also be typed as:
|
||||
<screen><![CDATA[
|
||||
(gdb) mo mc.l a f r
|
||||
(gdb) mo mc.l f r a
|
||||
]]></screen>
|
||||
|
||||
The letters <computeroutput>mo</computeroutput> are recognised by GDB as being
|
||||
an abbreviation for <computeroutput>monitor</computeroutput>. So GDB sends the
|
||||
string <computeroutput>mc.l a f r</computeroutput> to the Valgrind
|
||||
string <computeroutput>mc.l f r a</computeroutput> to the Valgrind
|
||||
gdbserver. The letters provided in this string are unambiguous for the
|
||||
Valgrind gdbserver. This therefore gives the same output as the
|
||||
unabbreviated command and arguments. If the provided abbreviation is
|
||||
@ -556,7 +556,7 @@ lines, when given in a shell, will cause the same leak search to be executed
|
||||
by the process 3145:
|
||||
<screen><![CDATA[
|
||||
vgdb --pid=3145 mc.leak_check any full reachable
|
||||
vgdb --pid=3145 mc.l a f r
|
||||
vgdb --pid=3145 mc.l f r a
|
||||
]]></screen></para>
|
||||
|
||||
<para>Note that the Valgrind gdbserver automatically continues the
|
||||
|
||||
@ -21,11 +21,11 @@ memcheck monitor commands:
|
||||
mc.check_memory [addressable|defined] <addr> [<len>]
|
||||
check that <len> (or 1) bytes at <addr> have the given accessibility
|
||||
and outputs a description of <addr>
|
||||
mc.leak_check [full*|summary]
|
||||
[reachable|leakpossible*|definiteleak]
|
||||
mc.leak_check [full*|summary] [reachable|leakpossible*|definiteleak]
|
||||
[increased*|changed|any]
|
||||
* = defaults
|
||||
Examples: mc.leak_check
|
||||
mc.leak_check any summary
|
||||
mc.leak_check summary any
|
||||
|
||||
general valgrind monitor commands:
|
||||
help [debug] : monitor command help. With debug: + debugging commands
|
||||
@ -57,10 +57,10 @@ memcheck monitor commands:
|
||||
mc.check_memory [addressable|defined] <addr> [<len>]
|
||||
check that <len> (or 1) bytes at <addr> have the given accessibility
|
||||
and outputs a description of <addr>
|
||||
mc.leak_check [full*|summary]
|
||||
[reachable|leakpossible*|definiteleak]
|
||||
mc.leak_check [full*|summary] [reachable|leakpossible*|definiteleak]
|
||||
[increased*|changed|any]
|
||||
* = defaults
|
||||
Examples: mc.leak_check
|
||||
mc.leak_check any summary
|
||||
mc.leak_check summary any
|
||||
|
||||
monitor command request to kill this process
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
(action at startup) vgdb me ...
|
||||
|
||||
|
||||
expecting details 10 bytes reachable
|
||||
10 bytes in 1 blocks are still reachable in loss record ... of ...
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
|
||||
@ -13,13 +13,13 @@ continue
|
||||
#
|
||||
# fprintf(stderr, "expecting details 10 bytes reachable\n"); fflush(stderr); breakme();
|
||||
up
|
||||
monitor mc.leak_check any reachable full
|
||||
monitor mc.leak_check full reachable any
|
||||
continue
|
||||
# VALGRIND_DO_LEAK_CHECK;
|
||||
#
|
||||
# fprintf(stderr, "expecting to have NO details\n"); fflush(stderr);
|
||||
up
|
||||
monitor mc.leak_check increased reachable full
|
||||
monitor mc.leak_check full reachable increased
|
||||
continue
|
||||
# VALGRIND_DO_ADDED_LEAK_CHECK;
|
||||
#
|
||||
@ -27,7 +27,7 @@ continue
|
||||
# b21 = malloc (21);
|
||||
# fprintf(stderr, "expecting details +10 bytes lost, +21 bytes reachable\n"); fflush(stderr); breakme();
|
||||
up
|
||||
monitor mc.leak_check increased reachable full
|
||||
monitor mc.leak_check full reachable increased
|
||||
continue
|
||||
# VALGRIND_DO_ADDED_LEAK_CHECK;
|
||||
#
|
||||
@ -35,41 +35,41 @@ continue
|
||||
# b32_33[i] = malloc (32+i);
|
||||
# fprintf(stderr, "expecting details +65 bytes reachable\n"); fflush(stderr); breakme();
|
||||
up
|
||||
monitor mc.leak_check increased reachable full
|
||||
monitor mc.leak_check full reachable increased
|
||||
continue
|
||||
# VALGRIND_DO_ADDED_LEAK_CHECK;
|
||||
#
|
||||
# fprintf(stderr, "expecting to have NO details\n"); fflush(stderr); breakme();
|
||||
up
|
||||
monitor mc.leak_check increased reachable full
|
||||
monitor mc.leak_check full reachable increased
|
||||
continue
|
||||
# VALGRIND_DO_ADDED_LEAK_CHECK;
|
||||
#
|
||||
# b10++;
|
||||
# fprintf(stderr, "expecting details +10 bytes reachable\n"); fflush(stderr); breakme();
|
||||
up
|
||||
monitor mc.leak_check increased reachable full
|
||||
monitor mc.leak_check full reachable increased
|
||||
continue
|
||||
# VALGRIND_DO_ADDED_LEAK_CHECK;
|
||||
#
|
||||
# b10--;
|
||||
# fprintf(stderr, "expecting details -10 bytes reachable, +10 bytes lost\n"); fflush(stderr); breakme();
|
||||
up
|
||||
monitor mc.leak_check changed reachable full
|
||||
monitor mc.leak_check full reachable changed
|
||||
continue
|
||||
# VALGRIND_DO_CHANGED_LEAK_CHECK;
|
||||
#
|
||||
# b10++;
|
||||
# fprintf(stderr, "expecting details -10 bytes lost, +10 bytes reachable\n"); fflush(stderr); breakme();
|
||||
up
|
||||
monitor mc.leak_check changed reachable full
|
||||
monitor mc.leak_check full reachable changed
|
||||
continue
|
||||
# VALGRIND_DO_CHANGED_LEAK_CHECK;
|
||||
#
|
||||
# b32_33[0]--;
|
||||
# fprintf(stderr, "expecting details 32 (+32) bytes lost, 33 (-32) bytes reachable\n"); fflush(stderr); breakme();
|
||||
up
|
||||
monitor mc.leak_check changed reachable full
|
||||
monitor mc.leak_check full reachable changed
|
||||
continue
|
||||
# VALGRIND_DO_CHANGED_LEAK_CHECK;
|
||||
#
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
Remote debugging using | ./vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-mcleak
|
||||
0x........ in _start () from ...start file...
|
||||
Breakpoint 1 at 0x........: file leak-delta.c, line 9.
|
||||
Continuing.
|
||||
Breakpoint 1, breakme () at leak-delta.c:9
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
# test the memcheck leak functionality.
|
||||
prog: ../memcheck/tests/leak-delta
|
||||
vgopts: --tool=memcheck --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-mcleak -q --leak-check=yes --show-reachable=yes --leak-resolution=high
|
||||
# temorarily disabled, waiting for leak-delta test program (next patch)
|
||||
prereq: test -e gdb -a -x ../memcheck/tests/leak-delta
|
||||
prereq: test -e gdb
|
||||
stdout_filter: filter_memcheck_monitor
|
||||
stderr_filter: filter_memcheck_monitor
|
||||
progB: gdb
|
||||
|
||||
@ -1272,23 +1272,27 @@ is:</para>
|
||||
|
||||
<sect1 id="mc-manual.monitor-commands" xreflabel="Memcheck Monitor Commands">
|
||||
<title>Memcheck Monitor Commands</title>
|
||||
<para>The Memcheck tool provides monitor commands handled by the Valgrind
|
||||
gdbserver (see <xref linkend="manual-core-adv.gdbserver-commandhandling"/>).
|
||||
<para>The Memcheck tool provides monitor commands handled by Valgrind's
|
||||
built-in gdbserver (see <xref linkend="manual-core-adv.gdbserver-commandhandling"/>).
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><varname>mc.get_vbits <addr> [<len>]</varname>
|
||||
outputs the validity bits for the range of <len> (default 1)
|
||||
bytes at <addr>. The validity of each byte of the range is
|
||||
given using two hexadecimal digits. These hexadecimal digits are
|
||||
encoding the validity of each bit of the corresponding byte, using
|
||||
0 if the bit is valid and 1 if the bit is invalid. In the
|
||||
following example, 'string10' is an array of 10 characters in
|
||||
which one byte on two is undefined. If a byte is not addressable,
|
||||
its validity bits are replaced by __. In the below example, the byte
|
||||
corresponding to string10[5]
|
||||
is not addressable.</para>
|
||||
shows the definedness (V) bits for <len> (default 1) bytes
|
||||
starting at <addr>. The definedness of each byte in the
|
||||
range is given using two hexadecimal digits. These hexadecimal
|
||||
digits encode the validity of each bit of the corresponding byte,
|
||||
using 0 if the bit is defined and 1 if the bit is undefined.
|
||||
If a byte is not addressable, its validity bits are replaced
|
||||
by <varname>__</varname> (a double underscore).
|
||||
</para>
|
||||
<para>
|
||||
In the following example, <varname>string10</varname> is an array
|
||||
of 10 characters, in which the even numbered bytes are
|
||||
undefined. In the below example, the byte corresponding
|
||||
to <varname>string10[5]</varname> is not addressable.
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
(gdb) p &string10
|
||||
$4 = (char (*)[10]) 0x8049e28
|
||||
@ -1299,14 +1303,22 @@ ff00ff00 ff__ff00 ff00
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><varname>mc.make_memory [noaccess|undefined|defined|ifaddressabledefined] <addr> [<len>]</varname>
|
||||
marks the range of <len> (default 1) bytes at <addr>
|
||||
with the given accessibility. Marking with 'noaccess' changes the
|
||||
(A) bits of the range to be not addressable. Marking with
|
||||
'undefined' or 'defined' are changing the definedness of the
|
||||
range. 'ifaddressabledefined' marks the range as defined but only
|
||||
if the range is addressable. In the following example, the first
|
||||
byte of the 'string10' is marked as defined.
|
||||
<para><varname>mc.make_memory
|
||||
[noaccess|undefined|defined|ifaddressabledefined] <addr>
|
||||
[<len>]</varname> marks the range of <len> (default 1)
|
||||
bytes at <addr> as having the given status. Parameter
|
||||
<varname>noaccess</varname> marks the range as non-accessible, so
|
||||
Memcheck will report an error on any access to it.
|
||||
<varname>undefined</varname> or <varname>defined</varname> mark
|
||||
the area as accessible, but Memcheck regards the bytes in it
|
||||
respectively as having undefined or defined values.
|
||||
<varname>ifaddressabledefined</varname> marks as defined, bytes in
|
||||
the range which are already addressible, but makes no change to
|
||||
the status of bytes in the range which are not addressible.</para>
|
||||
|
||||
<para>
|
||||
In the following example, the first byte of the
|
||||
<varname>string10</varname> is marked as defined:
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
(gdb) monitor mc.make_memory defined 0x8049e28 1
|
||||
@ -1319,10 +1331,11 @@ ff00ff00 ff__ff00 ff00
|
||||
<listitem>
|
||||
<para><varname>mc.check_memory [addressable|defined] <addr>
|
||||
[<len>]</varname> checks that the range of <len>
|
||||
(default 1) bytes at <addr> has the given accessibility. It
|
||||
then outputs a description of <addr>. In the below case, a
|
||||
detailed description is given as the option --read-var-info=yes
|
||||
was used to start Valgrind.
|
||||
(default 1) bytes at <addr> has the specified accessibility. It
|
||||
then outputs a description of <addr>. In the following example, a
|
||||
detailed description is given available because
|
||||
the option <option>--read-var-info=yes</option>
|
||||
was given Valgrind at startup:
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
(gdb) monitor mc.check_memory defined 0x8049e28 1
|
||||
@ -1334,58 +1347,93 @@ Address 0x8049E28 len 1 defined
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><varname>mc.leak_check
|
||||
[full*|summary] [reachable|leakpossible*|definiteleak]</varname>
|
||||
starts a leak checking. The * in the arguments above indicates the
|
||||
default value. </para>
|
||||
<para><varname>mc.leak_check [full*|summary]
|
||||
[reachable|leakpossible*|definiteleak]
|
||||
[increased*|changed|any]
|
||||
</varname>
|
||||
performs a leak check. The <varname>*</varname> in the arguments
|
||||
indicates the default value. </para>
|
||||
|
||||
<para> If the first argument is 'summary', only a summary of
|
||||
the leak search is given.
|
||||
<para> If the first argument is <varname>summary</varname>, only a
|
||||
summary of the leak search is given; otherwise a full leak report
|
||||
is produced. A full leak report gives detailed information for
|
||||
each leak: the stack trace where the leaked blocks were allocated,
|
||||
the number of blocks leaked and their total size. When a full
|
||||
report is requested, the next two arguments further specify what
|
||||
kind of leaks to report. A leak's details are shown if they match
|
||||
both the second and third argument.
|
||||
</para>
|
||||
|
||||
<para>The second argument controls which entries are output
|
||||
for a 'full' leak search. The value 'definiteleak' indicates to
|
||||
output only the definitely leaked blocks. The value 'leakpossible'
|
||||
will output in addition the possibly leaked blocks. The value
|
||||
'reachable' will output all blocks (reachable, possibly leaked,
|
||||
definitely leaked).
|
||||
<para>The second argument controls what kind of blocks are shown for
|
||||
a <varname>full</varname> leak search. The
|
||||
value <varname>definiteleak</varname> specifies that only
|
||||
definitely leaked blocks should be shown. The
|
||||
value <varname>leakpossible</varname> will also show possibly
|
||||
leaked blocks (those for which only an interior pointer was
|
||||
found). The value
|
||||
<varname>reachable</varname> will show all block categories
|
||||
(reachable, possibly leaked, definitely leaked).
|
||||
</para>
|
||||
<para>The below is an example of using the mc.leak_check monitor
|
||||
command on the leak-cases Memcheck regression tests.</para>
|
||||
|
||||
<para>The third argument controls what kinds of changes are shown
|
||||
for a <varname>full</varname> leak search. The
|
||||
value <varname>increased</varname> specifies that only block
|
||||
allocation stacks with an increased number of leaked bytes or
|
||||
blocks since the previous leak check should be shown. The
|
||||
value <varname>changed</varname> specifies that allocation stacks
|
||||
with any change since the previous leak check should be shown.
|
||||
The value <varname>any</varname> specifies that all leak entries
|
||||
should be shown, regardless of any increase or decrease. When
|
||||
If <varname>increased</varname> or <varname>changed</varname> are
|
||||
specified, the leak report entries will show the delta relative to
|
||||
the previous leak report.
|
||||
</para>
|
||||
|
||||
<para>The following example shows usage of the
|
||||
<varname>mc.leak_check monitor</varname> command on
|
||||
the <varname>memcheck/tests/leak-cases.c</varname> regression
|
||||
test. The first command outputs one entry having an increase in
|
||||
the leaked bytes. The second command is the same as the first
|
||||
command, but uses the abbreviated forms accepted by GDB and the
|
||||
Valgrind gdbserver. It only outputs the summary information, as
|
||||
there was no increase since the previous leak search.</para>
|
||||
<programlisting><![CDATA[
|
||||
(gdb) monitor mc.leak_check full leakpossible
|
||||
==14729== 16 bytes in 1 blocks are possibly lost in loss record 13 of 16
|
||||
(gdb) monitor mc.leak_check full leakpossible increased
|
||||
==14729== 16 (+16) bytes in 1 (+1) blocks are possibly lost in loss record 13 of 16
|
||||
==14729== at 0x4006E9E: malloc (vg_replace_malloc.c:236)
|
||||
==14729== by 0x80484D5: mk (leak-cases.c:52)
|
||||
==14729== by 0x804855F: f (leak-cases.c:81)
|
||||
==14729== by 0x80488F5: main (leak-cases.c:107)
|
||||
==14729==
|
||||
==14729== LEAK SUMMARY:
|
||||
==14729== definitely lost: 32 bytes in 2 blocks
|
||||
==14729== indirectly lost: 16 bytes in 1 blocks
|
||||
==14729== possibly lost: 32 bytes in 2 blocks
|
||||
==14729== still reachable: 96 bytes in 6 blocks
|
||||
==14729== suppressed: 0 bytes in 0 blocks
|
||||
==14729== definitely lost: 32 (+0) bytes in 2 (+0) blocks
|
||||
==14729== indirectly lost: 16 (+0) bytes in 1 (+0) blocks
|
||||
==14729== possibly lost: 32 (+16) bytes in 2 (+1) blocks
|
||||
==14729== still reachable: 96 (+16) bytes in 6 (+1) blocks
|
||||
==14729== suppressed: 0 (+0) bytes in 0 (+0) blocks
|
||||
==14729== Reachable blocks (those to which a pointer was found) are not shown.
|
||||
==14729== To see them, rerun with: --leak-check=full --show-reachable=yes
|
||||
==14729== o see them, add 'reachable any' args to mc.leak_check
|
||||
==14729==
|
||||
(gdb) mo mc.l
|
||||
==14729== LEAK SUMMARY:
|
||||
==14729== definitely lost: 32 bytes in 2 blocks
|
||||
==14729== indirectly lost: 16 bytes in 1 blocks
|
||||
==14729== possibly lost: 32 bytes in 2 blocks
|
||||
==14729== still reachable: 96 bytes in 6 blocks
|
||||
==14729== suppressed: 0 bytes in 0 blocks
|
||||
==14729== definitely lost: 32 (+0) bytes in 2 (+0) blocks
|
||||
==14729== indirectly lost: 16 (+0) bytes in 1 (+0) blocks
|
||||
==14729== possibly lost: 32 (+0) bytes in 2 (+0) blocks
|
||||
==14729== still reachable: 96 (+0) bytes in 6 (+0) blocks
|
||||
==14729== suppressed: 0 (+0) bytes in 0 (+0) blocks
|
||||
==14729== Reachable blocks (those to which a pointer was found) are not shown.
|
||||
==14729== To see them, rerun with: --leak-check=full --show-reachable=yes
|
||||
==14729== To see them, add 'reachable any' args to mc.leak_check
|
||||
==14729==
|
||||
(gdb)
|
||||
]]></programlisting>
|
||||
<para>Note that when using the Valgrind gdbserver, it is not
|
||||
needed to rerun with --leak-check=full --show-reachable=yes to see
|
||||
the reachable blocks. You can obtain the same information without
|
||||
rerunning by using the gdb command 'monitor mc.leak_check full
|
||||
reachable' (or, using abbreviation: 'mo mc.l f r').
|
||||
<para>Note that when using Valgrind's gdbserver, it is not
|
||||
necessary to rerun
|
||||
with <option>--leak-check=full</option>
|
||||
<option>--show-reachable=yes</option> to see the reachable
|
||||
blocks. You can obtain the same information without rerunning by
|
||||
using the GDB command <computeroutput>monitor mc.leak_check full
|
||||
reachable any</computeroutput> (or, using
|
||||
abbreviation: <computeroutput>mo mc.l f r a</computeroutput>).
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
@ -1442,6 +1490,22 @@ arguments.</para>
|
||||
places in the program's execution. It has no return value.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><varname>VALGRIND_DO_ADDED_LEAK_CHECK</varname>: same as
|
||||
<varname> VALGRIND_DO_LEAK_CHECK</varname> but only shows the
|
||||
entries for which there was an increase in leaked bytes or leaked
|
||||
number of blocks since the previous leak search. It has no return
|
||||
value.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><varname>VALGRIND_DO_CHANGED_LEAK_CHECK</varname>: same as
|
||||
<varname>VALGRIND_DO_LEAK_CHECK</varname> but only shows the
|
||||
entries for which there was an increase or decrease in leaked
|
||||
bytes or leaked number of blocks since the previous leak search. It
|
||||
has no return value.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><varname>VALGRIND_DO_QUICK_LEAK_CHECK</varname>: like
|
||||
<varname>VALGRIND_DO_LEAK_CHECK</varname>, except it produces only a leak
|
||||
|
||||
@ -432,6 +432,20 @@ static void mc_pp_origin ( ExeContext* ec, UInt okind )
|
||||
}
|
||||
}
|
||||
|
||||
char * MC_(snprintf_delta) (char * buf, Int size,
|
||||
SizeT current_val, SizeT old_val,
|
||||
LeakCheckDeltaMode delta_mode)
|
||||
{
|
||||
if (delta_mode == LCD_Any)
|
||||
buf[0] = '\0';
|
||||
else if (current_val >= old_val)
|
||||
VG_(snprintf) (buf, size, " (+%'lu)", current_val - old_val);
|
||||
else
|
||||
VG_(snprintf) (buf, size, " (-%'lu)", old_val - current_val);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void MC_(pp_Error) ( Error* err )
|
||||
{
|
||||
const Bool xml = VG_(clo_xml); /* a shorthand */
|
||||
@ -702,15 +716,41 @@ void MC_(pp_Error) ( Error* err )
|
||||
UInt n_this_record = extra->Err.Leak.n_this_record;
|
||||
UInt n_total_records = extra->Err.Leak.n_total_records;
|
||||
LossRecord* lr = extra->Err.Leak.lr;
|
||||
// char arrays to produce the indication of increase/decrease in case
|
||||
// of delta_mode != LC_Any
|
||||
char d_bytes[20];
|
||||
char d_direct_bytes[20];
|
||||
char d_indirect_bytes[20];
|
||||
char d_num_blocks[20];
|
||||
|
||||
MC_(snprintf_delta) (d_bytes, 20,
|
||||
lr->szB + lr->indirect_szB,
|
||||
lr->old_szB + lr->old_indirect_szB,
|
||||
MC_(detect_memory_leaks_last_delta_mode));
|
||||
MC_(snprintf_delta) (d_direct_bytes, 20,
|
||||
lr->szB,
|
||||
lr->old_szB,
|
||||
MC_(detect_memory_leaks_last_delta_mode));
|
||||
MC_(snprintf_delta) (d_indirect_bytes, 20,
|
||||
lr->indirect_szB,
|
||||
lr->old_indirect_szB,
|
||||
MC_(detect_memory_leaks_last_delta_mode));
|
||||
MC_(snprintf_delta) (d_num_blocks, 20,
|
||||
(SizeT) lr->num_blocks,
|
||||
(SizeT) lr->old_num_blocks,
|
||||
MC_(detect_memory_leaks_last_delta_mode));
|
||||
|
||||
if (xml) {
|
||||
emit(" <kind>%s</kind>\n", xml_leak_kind(lr->key.state));
|
||||
if (lr->indirect_szB > 0) {
|
||||
emit( " <xwhat>\n" );
|
||||
emit( " <text>%'lu (%'lu direct, %'lu indirect) bytes "
|
||||
"in %'u blocks"
|
||||
emit( " <text>%'lu%s (%'lu%s direct, %'lu%s indirect) bytes "
|
||||
"in %'u%s blocks"
|
||||
" are %s in loss record %'u of %'u</text>\n",
|
||||
lr->szB + lr->indirect_szB, lr->szB, lr->indirect_szB,
|
||||
lr->num_blocks,
|
||||
lr->szB + lr->indirect_szB, d_bytes,
|
||||
lr->szB, d_direct_bytes,
|
||||
lr->indirect_szB, d_indirect_bytes,
|
||||
lr->num_blocks, d_num_blocks,
|
||||
str_leak_lossmode(lr->key.state),
|
||||
n_this_record, n_total_records );
|
||||
// Nb: don't put commas in these XML numbers
|
||||
@ -720,9 +760,10 @@ void MC_(pp_Error) ( Error* err )
|
||||
emit( " </xwhat>\n" );
|
||||
} else {
|
||||
emit( " <xwhat>\n" );
|
||||
emit( " <text>%'lu bytes in %'u blocks"
|
||||
emit( " <text>%'lu%s bytes in %'u%s blocks"
|
||||
" are %s in loss record %'u of %'u</text>\n",
|
||||
lr->szB, lr->num_blocks,
|
||||
lr->szB, d_direct_bytes,
|
||||
lr->num_blocks, d_num_blocks,
|
||||
str_leak_lossmode(lr->key.state),
|
||||
n_this_record, n_total_records );
|
||||
emit( " <leakedbytes>%ld</leakedbytes>\n", lr->szB);
|
||||
@ -733,16 +774,21 @@ void MC_(pp_Error) ( Error* err )
|
||||
} else { /* ! if (xml) */
|
||||
if (lr->indirect_szB > 0) {
|
||||
emit(
|
||||
"%'lu (%'lu direct, %'lu indirect) bytes in %'u blocks"
|
||||
"%'lu%s (%'lu%s direct, %'lu%s indirect) bytes in %'u%s blocks"
|
||||
" are %s in loss record %'u of %'u\n",
|
||||
lr->szB + lr->indirect_szB, lr->szB, lr->indirect_szB,
|
||||
lr->num_blocks, str_leak_lossmode(lr->key.state),
|
||||
lr->szB + lr->indirect_szB, d_bytes,
|
||||
lr->szB, d_direct_bytes,
|
||||
lr->indirect_szB, d_indirect_bytes,
|
||||
lr->num_blocks, d_num_blocks,
|
||||
str_leak_lossmode(lr->key.state),
|
||||
n_this_record, n_total_records
|
||||
);
|
||||
} else {
|
||||
emit(
|
||||
"%'lu bytes in %'u blocks are %s in loss record %'u of %'u\n",
|
||||
lr->szB, lr->num_blocks, str_leak_lossmode(lr->key.state),
|
||||
"%'lu%s bytes in %'u%s blocks are %s in loss record %'u of %'u\n",
|
||||
lr->szB, d_direct_bytes,
|
||||
lr->num_blocks, d_num_blocks,
|
||||
str_leak_lossmode(lr->key.state),
|
||||
n_this_record, n_total_records
|
||||
);
|
||||
}
|
||||
|
||||
@ -270,6 +270,15 @@ typedef
|
||||
}
|
||||
LeakCheckMode;
|
||||
|
||||
typedef
|
||||
enum {
|
||||
LCD_Any, // output all loss records, whatever the delta
|
||||
LCD_Increased, // output loss records with an increase in size or blocks
|
||||
LCD_Changed, // output loss records with an increase or
|
||||
//decrease in size or blocks
|
||||
}
|
||||
LeakCheckDeltaMode;
|
||||
|
||||
/* When a LossRecord is put into an OSet, these elements represent the key. */
|
||||
typedef
|
||||
struct _LossRecordKey {
|
||||
@ -287,10 +296,33 @@ typedef
|
||||
SizeT szB; // Sum of all MC_Chunk.szB values.
|
||||
SizeT indirect_szB; // Sum of all LC_Extra.indirect_szB values.
|
||||
UInt num_blocks; // Number of blocks represented by the record.
|
||||
SizeT old_szB; // old_* values are the values found during the
|
||||
SizeT old_indirect_szB; // previous leak search. old_* values are used to
|
||||
UInt old_num_blocks; // output only the changed/new loss records
|
||||
}
|
||||
LossRecord;
|
||||
|
||||
void MC_(detect_memory_leaks) ( ThreadId tid, LeakCheckMode mode );
|
||||
typedef
|
||||
struct _LeakCheckParams {
|
||||
LeakCheckMode mode;
|
||||
Bool show_reachable;
|
||||
Bool show_possibly_lost;
|
||||
LeakCheckDeltaMode deltamode;
|
||||
Bool requested_by_monitor_command; // True when requested by gdb/vgdb.
|
||||
}
|
||||
LeakCheckParams;
|
||||
|
||||
void MC_(detect_memory_leaks) ( ThreadId tid, LeakCheckParams lcp);
|
||||
|
||||
// maintains the lcp.deltamode given in the last call to detect_memory_leaks
|
||||
extern LeakCheckDeltaMode MC_(detect_memory_leaks_last_delta_mode);
|
||||
|
||||
// if delta_mode == LC_Any, prints in buf an empty string
|
||||
// otherwise prints a delta in the layout " (+%'lu)" or " (-%'lu)"
|
||||
extern char * MC_(snprintf_delta) (char * buf, Int size,
|
||||
SizeT current_val, SizeT old_val,
|
||||
LeakCheckDeltaMode delta_mode);
|
||||
|
||||
|
||||
Bool MC_(is_valid_aligned_word) ( Addr a );
|
||||
Bool MC_(is_within_valid_secondary) ( Addr a );
|
||||
|
||||
@ -434,6 +434,16 @@ typedef
|
||||
static MC_Chunk** lc_chunks;
|
||||
// How many chunks we're dealing with.
|
||||
static Int lc_n_chunks;
|
||||
// chunks will be converted and merged in loss record, maintained in lr_table
|
||||
// lr_table elements are kept from one leak_search to another to implement
|
||||
// the "print new/changed leaks" client request
|
||||
static OSet* lr_table;
|
||||
|
||||
// DeltaMode used the last time we called detect_memory_leaks.
|
||||
// The recorded leak errors must be output using a logic based on this delta_mode.
|
||||
// The below avoids replicating the delta_mode in each LossRecord.
|
||||
LeakCheckDeltaMode MC_(detect_memory_leaks_last_delta_mode);
|
||||
|
||||
|
||||
// This has the same number of entries as lc_chunks, and each entry
|
||||
// in lc_chunks corresponds with the entry here (ie. lc_chunks[i] and
|
||||
@ -770,20 +780,35 @@ static Int cmp_LossRecords(void* va, void* vb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_results(ThreadId tid, Bool is_full_check)
|
||||
static void print_results(ThreadId tid, LeakCheckParams lcp)
|
||||
{
|
||||
Int i, n_lossrecords;
|
||||
OSet* lr_table;
|
||||
LossRecord** lr_array;
|
||||
LossRecord* lr;
|
||||
Bool is_suppressed;
|
||||
SizeT old_bytes_leaked = MC_(bytes_leaked); /* to report delta in summary */
|
||||
SizeT old_bytes_indirect = MC_(bytes_indirect);
|
||||
SizeT old_bytes_dubious = MC_(bytes_dubious);
|
||||
SizeT old_bytes_reachable = MC_(bytes_reachable);
|
||||
SizeT old_bytes_suppressed = MC_(bytes_suppressed);
|
||||
SizeT old_blocks_leaked = MC_(blocks_leaked);
|
||||
SizeT old_blocks_indirect = MC_(blocks_indirect);
|
||||
SizeT old_blocks_dubious = MC_(blocks_dubious);
|
||||
SizeT old_blocks_reachable = MC_(blocks_reachable);
|
||||
SizeT old_blocks_suppressed = MC_(blocks_suppressed);
|
||||
|
||||
if (lr_table == NULL)
|
||||
// Create the lr_table, which holds the loss records.
|
||||
// If the lr_table already exists, it means it contains
|
||||
// loss_records from the previous leak search. The old_*
|
||||
// values in these records are used to implement the
|
||||
// leak check delta mode
|
||||
lr_table =
|
||||
VG_(OSetGen_Create)(offsetof(LossRecord, key),
|
||||
cmp_LossRecordKey_LossRecord,
|
||||
VG_(malloc), "mc.pr.1",
|
||||
VG_(free));
|
||||
|
||||
// Create the lr_table, which holds the loss records.
|
||||
lr_table =
|
||||
VG_(OSetGen_Create)(offsetof(LossRecord, key),
|
||||
cmp_LossRecordKey_LossRecord,
|
||||
VG_(malloc), "mc.pr.1",
|
||||
VG_(free));
|
||||
|
||||
// Convert the chunks into loss records, merging them where appropriate.
|
||||
for (i = 0; i < lc_n_chunks; i++) {
|
||||
@ -810,6 +835,9 @@ static void print_results(ThreadId tid, Bool is_full_check)
|
||||
lr->szB = ch->szB;
|
||||
lr->indirect_szB = ex->indirect_szB;
|
||||
lr->num_blocks = 1;
|
||||
lr->old_szB = 0;
|
||||
lr->old_indirect_szB = 0;
|
||||
lr->old_num_blocks = 0;
|
||||
VG_(OSetGen_Insert)(lr_table, lr);
|
||||
}
|
||||
}
|
||||
@ -837,7 +865,7 @@ static void print_results(ThreadId tid, Bool is_full_check)
|
||||
|
||||
// Print the loss records (in size order) and collect summary stats.
|
||||
for (i = 0; i < n_lossrecords; i++) {
|
||||
Bool count_as_error, print_record;
|
||||
Bool count_as_error, print_record, delta_considered;
|
||||
// Rules for printing:
|
||||
// - We don't show suppressed loss records ever (and that's controlled
|
||||
// within the error manager).
|
||||
@ -851,18 +879,37 @@ static void print_results(ThreadId tid, Bool is_full_check)
|
||||
// includes indirectly lost blocks!
|
||||
//
|
||||
lr = lr_array[i];
|
||||
print_record = is_full_check &&
|
||||
( MC_(clo_show_reachable) ||
|
||||
switch (lcp.deltamode) {
|
||||
case LCD_Any:
|
||||
delta_considered = lr->num_blocks > 0;
|
||||
break;
|
||||
case LCD_Increased:
|
||||
delta_considered
|
||||
= lr_array[i]->szB > lr_array[i]->old_szB
|
||||
|| lr_array[i]->indirect_szB > lr_array[i]->old_indirect_szB
|
||||
|| lr->num_blocks > lr->old_num_blocks;
|
||||
break;
|
||||
case LCD_Changed:
|
||||
delta_considered = lr_array[i]->szB != lr_array[i]->old_szB
|
||||
|| lr_array[i]->indirect_szB != lr_array[i]->old_indirect_szB
|
||||
|| lr->num_blocks != lr->old_num_blocks;
|
||||
break;
|
||||
default:
|
||||
tl_assert(0);
|
||||
}
|
||||
|
||||
print_record = lcp.mode == LC_Full && delta_considered &&
|
||||
( lcp.show_reachable ||
|
||||
Unreached == lr->key.state ||
|
||||
( MC_(clo_show_possibly_lost) &&
|
||||
( lcp.show_possibly_lost &&
|
||||
Possible == lr->key.state ) );
|
||||
// We don't count a leaks as errors with --leak-check=summary.
|
||||
// We don't count a leaks as errors with lcp.mode==LC_Summary.
|
||||
// Otherwise you can get high error counts with few or no error
|
||||
// messages, which can be confusing. Also, you could argue that
|
||||
// indirect leaks should be counted as errors, but it seems better to
|
||||
// make the counting criteria similar to the printing criteria. So we
|
||||
// don't count them.
|
||||
count_as_error = is_full_check &&
|
||||
count_as_error = lcp.mode == LC_Full && delta_considered &&
|
||||
( Unreached == lr->key.state ||
|
||||
Possible == lr->key.state );
|
||||
is_suppressed =
|
||||
@ -894,31 +941,74 @@ static void print_results(ThreadId tid, Bool is_full_check)
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < n_lossrecords; i++)
|
||||
{
|
||||
if (lr->num_blocks == 0)
|
||||
// remove from lr_table the old loss_records with 0 bytes found
|
||||
VG_(OSetGen_Remove) (lr_table, &lr_array[i]->key);
|
||||
else
|
||||
{
|
||||
// move the leak sizes to old_* and zero the current sizes
|
||||
// for next leak search
|
||||
lr_array[i]->old_szB = lr_array[i]->szB;
|
||||
lr_array[i]->old_indirect_szB = lr_array[i]->indirect_szB;
|
||||
lr_array[i]->old_num_blocks = lr_array[i]->num_blocks;
|
||||
lr_array[i]->szB = 0;
|
||||
lr_array[i]->indirect_szB = 0;
|
||||
lr_array[i]->num_blocks = 0;
|
||||
}
|
||||
}
|
||||
VG_(free)(lr_array);
|
||||
|
||||
if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) {
|
||||
char d_bytes[20];
|
||||
char d_blocks[20];
|
||||
|
||||
VG_(umsg)("LEAK SUMMARY:\n");
|
||||
VG_(umsg)(" definitely lost: %'lu bytes in %'lu blocks\n",
|
||||
MC_(bytes_leaked), MC_(blocks_leaked) );
|
||||
VG_(umsg)(" indirectly lost: %'lu bytes in %'lu blocks\n",
|
||||
MC_(bytes_indirect), MC_(blocks_indirect) );
|
||||
VG_(umsg)(" possibly lost: %'lu bytes in %'lu blocks\n",
|
||||
MC_(bytes_dubious), MC_(blocks_dubious) );
|
||||
VG_(umsg)(" still reachable: %'lu bytes in %'lu blocks\n",
|
||||
MC_(bytes_reachable), MC_(blocks_reachable) );
|
||||
VG_(umsg)(" suppressed: %'lu bytes in %'lu blocks\n",
|
||||
MC_(bytes_suppressed), MC_(blocks_suppressed) );
|
||||
if (!is_full_check &&
|
||||
VG_(umsg)(" definitely lost: %'lu%s bytes in %'lu%s blocks\n",
|
||||
MC_(bytes_leaked),
|
||||
MC_(snprintf_delta) (d_bytes, 20, MC_(bytes_leaked), old_bytes_leaked, lcp.deltamode),
|
||||
MC_(blocks_leaked),
|
||||
MC_(snprintf_delta) (d_blocks, 20, MC_(blocks_leaked), old_blocks_leaked, lcp.deltamode));
|
||||
VG_(umsg)(" indirectly lost: %'lu%s bytes in %'lu%s blocks\n",
|
||||
MC_(bytes_indirect),
|
||||
MC_(snprintf_delta) (d_bytes, 20, MC_(bytes_indirect), old_bytes_indirect, lcp.deltamode),
|
||||
MC_(blocks_indirect),
|
||||
MC_(snprintf_delta) (d_blocks, 20, MC_(blocks_indirect), old_blocks_indirect, lcp.deltamode) );
|
||||
VG_(umsg)(" possibly lost: %'lu%s bytes in %'lu%s blocks\n",
|
||||
MC_(bytes_dubious),
|
||||
MC_(snprintf_delta) (d_bytes, 20, MC_(bytes_dubious), old_bytes_dubious, lcp.deltamode),
|
||||
MC_(blocks_dubious),
|
||||
MC_(snprintf_delta) (d_blocks, 20, MC_(blocks_dubious), old_blocks_dubious, lcp.deltamode) );
|
||||
VG_(umsg)(" still reachable: %'lu%s bytes in %'lu%s blocks\n",
|
||||
MC_(bytes_reachable),
|
||||
MC_(snprintf_delta) (d_bytes, 20, MC_(bytes_reachable), old_bytes_reachable, lcp.deltamode),
|
||||
MC_(blocks_reachable),
|
||||
MC_(snprintf_delta) (d_blocks, 20, MC_(blocks_reachable), old_blocks_reachable, lcp.deltamode) );
|
||||
VG_(umsg)(" suppressed: %'lu%s bytes in %'lu%s blocks\n",
|
||||
MC_(bytes_suppressed),
|
||||
MC_(snprintf_delta) (d_bytes, 20, MC_(bytes_suppressed), old_bytes_suppressed, lcp.deltamode),
|
||||
MC_(blocks_suppressed),
|
||||
MC_(snprintf_delta) (d_blocks, 20, MC_(blocks_suppressed), old_blocks_suppressed, lcp.deltamode) );
|
||||
if (lcp.mode != LC_Full &&
|
||||
(MC_(blocks_leaked) + MC_(blocks_indirect) +
|
||||
MC_(blocks_dubious) + MC_(blocks_reachable)) > 0) {
|
||||
VG_(umsg)("Rerun with --leak-check=full to see details "
|
||||
"of leaked memory\n");
|
||||
if (lcp.requested_by_monitor_command)
|
||||
VG_(umsg)("To see details of leaked memory, give 'full' arg to mc.leak_check\n");
|
||||
else
|
||||
VG_(umsg)("Rerun with --leak-check=full to see details "
|
||||
"of leaked memory\n");
|
||||
}
|
||||
if (is_full_check &&
|
||||
MC_(blocks_reachable) > 0 && !MC_(clo_show_reachable))
|
||||
if (lcp.mode == LC_Full &&
|
||||
MC_(blocks_reachable) > 0 && !lcp.show_reachable)
|
||||
{
|
||||
VG_(umsg)("Reachable blocks (those to which a pointer "
|
||||
"was found) are not shown.\n");
|
||||
VG_(umsg)("To see them, rerun with: --leak-check=full "
|
||||
"--show-reachable=yes\n");
|
||||
if (lcp.requested_by_monitor_command)
|
||||
VG_(umsg)("To see them, add 'reachable any' args to mc.leak_check\n");
|
||||
else
|
||||
VG_(umsg)("To see them, rerun with: --leak-check=full "
|
||||
"--show-reachable=yes\n");
|
||||
}
|
||||
VG_(umsg)("\n");
|
||||
}
|
||||
@ -928,16 +1018,26 @@ static void print_results(ThreadId tid, Bool is_full_check)
|
||||
/*--- Top-level entry point. ---*/
|
||||
/*------------------------------------------------------------*/
|
||||
|
||||
void MC_(detect_memory_leaks) ( ThreadId tid, LeakCheckMode mode )
|
||||
void MC_(detect_memory_leaks) ( ThreadId tid, LeakCheckParams lcp)
|
||||
{
|
||||
Int i, j;
|
||||
|
||||
tl_assert(mode != LC_Off);
|
||||
tl_assert(lcp.mode != LC_Off);
|
||||
|
||||
MC_(detect_memory_leaks_last_delta_mode) = lcp.deltamode;
|
||||
|
||||
// Get the chunks, stop if there were none.
|
||||
lc_chunks = find_active_chunks(&lc_n_chunks);
|
||||
if (lc_n_chunks == 0) {
|
||||
tl_assert(lc_chunks == NULL);
|
||||
if (lr_table != NULL) {
|
||||
// forget the previous recorded LossRecords as next leak search will in any case
|
||||
// just create new leaks.
|
||||
// Maybe it would be better to rather call print_result ?
|
||||
// (at least when leak decrease are requested)
|
||||
// This will then output all LossRecords with a size decreasing to 0
|
||||
VG_(OSetGen_Destroy) (lr_table);
|
||||
}
|
||||
if (VG_(clo_verbosity) >= 1 && !VG_(clo_xml)) {
|
||||
VG_(umsg)("All heap blocks were freed -- no leaks are possible\n");
|
||||
VG_(umsg)("\n");
|
||||
@ -1124,7 +1224,7 @@ void MC_(detect_memory_leaks) ( ThreadId tid, LeakCheckMode mode )
|
||||
}
|
||||
}
|
||||
|
||||
print_results( tid, ( mode == LC_Full ? True : False ) );
|
||||
print_results( tid, lcp);
|
||||
|
||||
VG_(free) ( lc_chunks );
|
||||
VG_(free) ( lc_extras );
|
||||
|
||||
@ -4945,11 +4945,11 @@ static void print_monitor_help ( void )
|
||||
" mc.check_memory [addressable|defined] <addr> [<len>]\n"
|
||||
" check that <len> (or 1) bytes at <addr> have the given accessibility\n"
|
||||
" and outputs a description of <addr>\n"
|
||||
" mc.leak_check [full*|summary]\n"
|
||||
" [reachable|leakpossible*|definiteleak]\n"
|
||||
" mc.leak_check [full*|summary] [reachable|leakpossible*|definiteleak]\n"
|
||||
" [increased*|changed|any]\n"
|
||||
" * = defaults\n"
|
||||
" Examples: mc.leak_check\n"
|
||||
" mc.leak_check any summary\n"
|
||||
" mc.leak_check summary any\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
@ -5013,40 +5013,50 @@ static Bool handle_gdb_monitor_command (ThreadId tid, Char *req)
|
||||
}
|
||||
case 2: { /* mc.leak_check */
|
||||
Int err = 0;
|
||||
Bool save_clo_show_reachable = MC_(clo_show_reachable);
|
||||
Bool save_clo_show_possibly_lost = MC_(clo_show_possibly_lost);
|
||||
LeakCheckParams lcp;
|
||||
Char* kw;
|
||||
|
||||
LeakCheckMode mode;
|
||||
|
||||
MC_(clo_show_reachable) = False;
|
||||
mode = LC_Full;
|
||||
lcp.mode = LC_Full;
|
||||
lcp.show_reachable = False;
|
||||
lcp.show_possibly_lost = True;
|
||||
lcp.deltamode = LCD_Increased;
|
||||
lcp.requested_by_monitor_command = True;
|
||||
|
||||
for (kw = VG_(strtok_r) (NULL, " ", &ssaveptr);
|
||||
kw != NULL;
|
||||
kw = VG_(strtok_r) (NULL, " ", &ssaveptr)) {
|
||||
switch (VG_(keyword_id)
|
||||
("full summary "
|
||||
"reachable leakpossible definiteleak",
|
||||
"reachable leakpossible definiteleak "
|
||||
"increased changed any",
|
||||
kw, kwd_report_all)) {
|
||||
case -2: err++; break;
|
||||
case -1: err++; break;
|
||||
case 0: mode = LC_Full; break;
|
||||
case 1: mode = LC_Summary; break;
|
||||
case 2: MC_(clo_show_reachable) = True;
|
||||
MC_(clo_show_possibly_lost) = True; break;
|
||||
case 3: MC_(clo_show_reachable) = False;
|
||||
MC_(clo_show_possibly_lost) = True; break;
|
||||
case 4: MC_(clo_show_reachable) = False;
|
||||
MC_(clo_show_possibly_lost) = False; break;
|
||||
default: tl_assert (0);
|
||||
case 0: /* full */
|
||||
lcp.mode = LC_Full; break;
|
||||
case 1: /* summary */
|
||||
lcp.mode = LC_Summary; break;
|
||||
case 2: /* reachable */
|
||||
lcp.show_reachable = True;
|
||||
lcp.show_possibly_lost = True; break;
|
||||
case 3: /* leakpossible */
|
||||
lcp.show_reachable = False;
|
||||
lcp.show_possibly_lost = True; break;
|
||||
case 4: /* definiteleak */
|
||||
lcp.show_reachable = False;
|
||||
lcp.show_possibly_lost = False; break;
|
||||
case 5: /* increased */
|
||||
lcp.deltamode = LCD_Increased; break;
|
||||
case 6: /* changed */
|
||||
lcp.deltamode = LCD_Changed; break;
|
||||
case 7: /* any */
|
||||
lcp.deltamode = LCD_Any; break;
|
||||
default:
|
||||
tl_assert (0);
|
||||
}
|
||||
}
|
||||
if (!err)
|
||||
MC_(detect_memory_leaks)(tid, mode);
|
||||
|
||||
MC_(clo_show_reachable) = save_clo_show_reachable;
|
||||
MC_(clo_show_possibly_lost) = save_clo_show_possibly_lost;
|
||||
MC_(detect_memory_leaks)(tid, lcp);
|
||||
return True;
|
||||
}
|
||||
|
||||
@ -5189,10 +5199,40 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
|
||||
break;
|
||||
}
|
||||
|
||||
case VG_USERREQ__DO_LEAK_CHECK:
|
||||
MC_(detect_memory_leaks)(tid, arg[1] ? LC_Summary : LC_Full);
|
||||
case VG_USERREQ__DO_LEAK_CHECK: {
|
||||
LeakCheckParams lcp;
|
||||
|
||||
if (arg[1] == 0)
|
||||
lcp.mode = LC_Full;
|
||||
else if (arg[1] == 1)
|
||||
lcp.mode = LC_Summary;
|
||||
else {
|
||||
VG_(message)(Vg_UserMsg,
|
||||
"Warning: unknown memcheck leak search mode\n");
|
||||
lcp.mode = LC_Full;
|
||||
}
|
||||
|
||||
lcp.show_reachable = MC_(clo_show_reachable);
|
||||
lcp.show_possibly_lost = MC_(clo_show_possibly_lost);
|
||||
|
||||
if (arg[2] == 0)
|
||||
lcp.deltamode = LCD_Any;
|
||||
else if (arg[2] == 1)
|
||||
lcp.deltamode = LCD_Increased;
|
||||
else if (arg[2] == 2)
|
||||
lcp.deltamode = LCD_Changed;
|
||||
else {
|
||||
VG_(message)
|
||||
(Vg_UserMsg,
|
||||
"Warning: unknown memcheck leak search deltamode\n");
|
||||
lcp.deltamode = LCD_Any;
|
||||
}
|
||||
lcp.requested_by_monitor_command = False;
|
||||
|
||||
MC_(detect_memory_leaks)(tid, lcp);
|
||||
*ret = 0; /* return value is meaningless */
|
||||
break;
|
||||
}
|
||||
|
||||
case VG_USERREQ__MAKE_MEM_NOACCESS:
|
||||
MC_(make_mem_noaccess) ( arg[1], arg[2] );
|
||||
@ -5854,7 +5894,13 @@ static void mc_fini ( Int exitcode )
|
||||
MC_(print_malloc_stats)();
|
||||
|
||||
if (MC_(clo_leak_check) != LC_Off) {
|
||||
MC_(detect_memory_leaks)(1/*bogus ThreadId*/, MC_(clo_leak_check));
|
||||
LeakCheckParams lcp;
|
||||
lcp.mode = MC_(clo_leak_check);
|
||||
lcp.show_reachable = MC_(clo_show_reachable);
|
||||
lcp.show_possibly_lost = MC_(clo_show_possibly_lost);
|
||||
lcp.deltamode = LCD_Any;
|
||||
lcp.requested_by_monitor_command = False;
|
||||
MC_(detect_memory_leaks)(1/*bogus ThreadId*/, lcp);
|
||||
} else {
|
||||
if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
|
||||
VG_(umsg)(
|
||||
|
||||
@ -188,6 +188,26 @@ typedef
|
||||
VG_USERREQ__DO_LEAK_CHECK, \
|
||||
0, 0, 0, 0, 0)
|
||||
|
||||
/* Same as VALGRIND_DO_LEAK_CHECK but only showing the entries for
|
||||
which there was an increase in leaked bytes or leaked nr of blocks
|
||||
since the previous leak search. */
|
||||
#define VALGRIND_DO_ADDED_LEAK_CHECK \
|
||||
{unsigned long _qzz_res; \
|
||||
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
|
||||
VG_USERREQ__DO_LEAK_CHECK, \
|
||||
0, 1, 0, 0, 0); \
|
||||
}
|
||||
|
||||
/* Same as VALGRIND_DO_ADDED_LEAK_CHECK but showing entries with
|
||||
increased or decreased leaked bytes/blocks since previous leak
|
||||
search. */
|
||||
#define VALGRIND_DO_CHANGED_LEAK_CHECK \
|
||||
{unsigned long _qzz_res; \
|
||||
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
|
||||
VG_USERREQ__DO_LEAK_CHECK, \
|
||||
0, 2, 0, 0, 0); \
|
||||
}
|
||||
|
||||
/* Do a summary memory leak check (like --leak-check=summary) mid-execution. */
|
||||
#define VALGRIND_DO_QUICK_LEAK_CHECK \
|
||||
VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
|
||||
|
||||
@ -88,6 +88,7 @@ EXTRA_DIST = \
|
||||
leak-cases-possible.vgtest leak-cases-possible.stderr.exp \
|
||||
leak-cases-summary.vgtest leak-cases-summary.stderr.exp \
|
||||
leak-cycle.vgtest leak-cycle.stderr.exp \
|
||||
leak-delta.vgtest leak-delta.stderr.exp \
|
||||
leak-pool-0.vgtest leak-pool-0.stderr.exp \
|
||||
leak-pool-1.vgtest leak-pool-1.stderr.exp \
|
||||
leak-pool-2.vgtest leak-pool-2.stderr.exp \
|
||||
@ -219,6 +220,7 @@ check_PROGRAMS = \
|
||||
leak-0 \
|
||||
leak-cases \
|
||||
leak-cycle \
|
||||
leak-delta \
|
||||
leak-pool \
|
||||
leak-tree \
|
||||
long_namespace_xml \
|
||||
|
||||
68
memcheck/tests/leak-delta.c
Normal file
68
memcheck/tests/leak-delta.c
Normal file
@ -0,0 +1,68 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "../memcheck.h"
|
||||
#include "leak.h"
|
||||
|
||||
char *b10;
|
||||
char *b21;
|
||||
char *b32_33[2];
|
||||
static void breakme() {};
|
||||
void f(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
b10 = malloc (10);
|
||||
|
||||
fprintf(stderr, "expecting details 10 bytes reachable\n"); fflush(stderr); breakme();
|
||||
VALGRIND_DO_LEAK_CHECK;
|
||||
|
||||
fprintf(stderr, "expecting to have NO details\n"); fflush(stderr); breakme();
|
||||
VALGRIND_DO_ADDED_LEAK_CHECK;
|
||||
|
||||
b10--; // lose b10
|
||||
b21 = malloc (21);
|
||||
fprintf(stderr, "expecting details +10 bytes lost, +21 bytes reachable\n"); fflush(stderr); breakme();
|
||||
VALGRIND_DO_ADDED_LEAK_CHECK;
|
||||
|
||||
for (i = 0; i < 2; i ++)
|
||||
b32_33[i] = malloc (32+i);
|
||||
fprintf(stderr, "expecting details +65 bytes reachable\n"); fflush(stderr); breakme();
|
||||
VALGRIND_DO_ADDED_LEAK_CHECK;
|
||||
|
||||
fprintf(stderr, "expecting to have NO details\n"); fflush(stderr); breakme();
|
||||
VALGRIND_DO_ADDED_LEAK_CHECK;
|
||||
|
||||
b10++;
|
||||
fprintf(stderr, "expecting details +10 bytes reachable\n"); fflush(stderr); breakme();
|
||||
VALGRIND_DO_ADDED_LEAK_CHECK;
|
||||
|
||||
b10--;
|
||||
fprintf(stderr, "expecting details -10 bytes reachable, +10 bytes lost\n"); fflush(stderr); breakme();
|
||||
VALGRIND_DO_CHANGED_LEAK_CHECK;
|
||||
|
||||
b10++;
|
||||
fprintf(stderr, "expecting details -10 bytes lost, +10 bytes reachable\n"); fflush(stderr); breakme();
|
||||
VALGRIND_DO_CHANGED_LEAK_CHECK;
|
||||
|
||||
b32_33[0]--;
|
||||
fprintf(stderr, "expecting details 32 (+32) bytes lost, 33 (-32) bytes reachable\n"); fflush(stderr); breakme();
|
||||
VALGRIND_DO_CHANGED_LEAK_CHECK;
|
||||
|
||||
fprintf(stderr, "finished\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
DECLARE_LEAK_COUNTERS;
|
||||
|
||||
GET_INITIAL_LEAK_COUNTS;
|
||||
|
||||
f(); // see leak-cases.c
|
||||
|
||||
|
||||
GET_FINAL_LEAK_COUNTS;
|
||||
|
||||
PRINT_LEAK_COUNTS(stderr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
89
memcheck/tests/leak-delta.stderr.exp
Normal file
89
memcheck/tests/leak-delta.stderr.exp
Normal file
@ -0,0 +1,89 @@
|
||||
expecting details 10 bytes reachable
|
||||
10 bytes in 1 blocks are still reachable in loss record ... of ...
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: f (leak-delta.c:14)
|
||||
by 0x........: main (leak-delta.c:60)
|
||||
|
||||
expecting to have NO details
|
||||
expecting details +10 bytes lost, +21 bytes reachable
|
||||
10 (+10) bytes in 1 (+1) blocks are definitely lost in loss record ... of ...
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: f (leak-delta.c:14)
|
||||
by 0x........: main (leak-delta.c:60)
|
||||
|
||||
21 (+21) bytes in 1 (+1) blocks are still reachable in loss record ... of ...
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: f (leak-delta.c:23)
|
||||
by 0x........: main (leak-delta.c:60)
|
||||
|
||||
expecting details +65 bytes reachable
|
||||
65 (+65) bytes in 2 (+2) blocks are still reachable in loss record ... of ...
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: f (leak-delta.c:28)
|
||||
by 0x........: main (leak-delta.c:60)
|
||||
|
||||
expecting to have NO details
|
||||
expecting details +10 bytes reachable
|
||||
10 (+10) bytes in 1 (+1) blocks are still reachable in loss record ... of ...
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: f (leak-delta.c:14)
|
||||
by 0x........: main (leak-delta.c:60)
|
||||
|
||||
expecting details -10 bytes reachable, +10 bytes lost
|
||||
0 (-10) bytes in 0 (-1) blocks are still reachable in loss record ... of ...
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: f (leak-delta.c:14)
|
||||
by 0x........: main (leak-delta.c:60)
|
||||
|
||||
10 (+10) bytes in 1 (+1) blocks are definitely lost in loss record ... of ...
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: f (leak-delta.c:14)
|
||||
by 0x........: main (leak-delta.c:60)
|
||||
|
||||
expecting details -10 bytes lost, +10 bytes reachable
|
||||
0 (-10) bytes in 0 (-1) blocks are definitely lost in loss record ... of ...
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: f (leak-delta.c:14)
|
||||
by 0x........: main (leak-delta.c:60)
|
||||
|
||||
10 (+10) bytes in 1 (+1) blocks are still reachable in loss record ... of ...
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: f (leak-delta.c:14)
|
||||
by 0x........: main (leak-delta.c:60)
|
||||
|
||||
expecting details 32 (+32) bytes lost, 33 (-32) bytes reachable
|
||||
32 (+32) bytes in 1 (+1) blocks are definitely lost in loss record ... of ...
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: f (leak-delta.c:28)
|
||||
by 0x........: main (leak-delta.c:60)
|
||||
|
||||
33 (-32) bytes in 1 (-1) blocks are still reachable in loss record ... of ...
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: f (leak-delta.c:28)
|
||||
by 0x........: main (leak-delta.c:60)
|
||||
|
||||
finished
|
||||
leaked: 32 bytes in 1 blocks
|
||||
dubious: 0 bytes in 0 blocks
|
||||
reachable: 64 bytes in 3 blocks
|
||||
suppressed: 0 bytes in 0 blocks
|
||||
10 bytes in 1 blocks are still reachable in loss record ... of ...
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: f (leak-delta.c:14)
|
||||
by 0x........: main (leak-delta.c:60)
|
||||
|
||||
21 bytes in 1 blocks are still reachable in loss record ... of ...
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: f (leak-delta.c:23)
|
||||
by 0x........: main (leak-delta.c:60)
|
||||
|
||||
32 bytes in 1 blocks are definitely lost in loss record ... of ...
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: f (leak-delta.c:28)
|
||||
by 0x........: main (leak-delta.c:60)
|
||||
|
||||
33 bytes in 1 blocks are still reachable in loss record ... of ...
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: f (leak-delta.c:28)
|
||||
by 0x........: main (leak-delta.c:60)
|
||||
|
||||
2
memcheck/tests/leak-delta.vgtest
Normal file
2
memcheck/tests/leak-delta.vgtest
Normal file
@ -0,0 +1,2 @@
|
||||
prog: leak-delta
|
||||
vgopts: -q --leak-check=yes --show-reachable=yes --leak-resolution=high
|
||||
Loading…
x
Reference in New Issue
Block a user