and 'massif format. The existing visualisers for these formats (e.g.
callgrind_annotate, kcachegrind, ms_print) can be used to visualise
and analyse these reports.
+ Memcheck can also produce leak reports in an xtree callgrind format.
For more details, read the user manual.
* ================== PLATFORM CHANGES =================
- Support for --xtree-memory and 'xtmemory [<filename>]>'.
+ - New command line options --xtree-leak=no|yes and --xtree-leak-file=<file>
+ to produce the end of execution leak report in a xtree callgrind format
+ file.
+
+ - New option 'xtleak' in the memcheck leak_check monitor command, to
+ produce the leak report in an xtree file.
+
* Massif:
- Support for --xtree-memory and 'xtmemory [<filename>]>'.
first line uniquely identifying the format ("# callgrind format").
Callgrind creates this line now (also the new xtree functionality).
+* File name template arguments (such as --log-file, --xtree-memory-file, ...)
+ have a new %n format letter that is replaced by a sequence number.
+
* ==================== FIXED BUGS ====================
The following bugs have been fixed or resolved. Note that "n-i-bz"
j += VG_(sprintf)(&out[j], "%d", pid);
i++;
}
+ else if ('n' == format[i]) {
+ // Print a seq nr.
+ static Int last_pid;
+ static Int seq_nr;
+ Int pid = VG_(getpid)();
+ if (last_pid != pid)
+ seq_nr = 0;
+ last_pid = pid;
+ seq_nr++;
+ ENSURE_THIS_MUCH_SPACE(10);
+ j += VG_(sprintf)(&out[j], "%d", seq_nr);
+ i++;
+ }
else if ('q' == format[i]) {
i++;
if ('{' == format[i]) {
= VG_(expand_file_name)("--xtree-memory-file",
(filename == NULL) ?
(fini ?
- VG_(clo_xtree_memory_file) : "xtmemory.kcg")
+ VG_(clo_xtree_memory_file)
+ : "xtmemory.kcg.%p.%n")
: filename);
/* fini is False => even if user kept --xtree-memory=none, we
</listitem>
<listitem>
- <para><varname>xtmemory [<filename> default xtmemory.kcg]</varname>
+ <para><varname>xtmemory [<filename> default xtmemory.kcg.%p.%n]</varname>
requests the tool to produce an xtree heap memory report.
See <xref linkend="manual-core.xtree"/> for
a detailed explanation about execution trees. </para>
all those processes will go into one file, possibly jumbled up, and
possibly incomplete.</para>
+ <para><option>%n</option> is replaced with a file sequence number
+ unique for this process.
+ This is useful for processes that produces several files
+ from the same filename template.</para>
+
+
<para><option>%q{FOO}</option> is replaced with the contents of the
environment variable <varname>FOO</varname>. If the
<option>{FOO}</option> part is malformed, it causes an abort. This
<para>An execution tree (xtree) is made of a set of stack traces, each
stack trace is associated with some resource consumptions or event
counts. Depending on the xtree, different event counts/resource
- consumptions can be recorded in the xtree.</para>
+ consumptions can be recorded in the xtree. Multiple tools can
+ produce memory use xtree. Memcheck can output the leak search results
+ in an xtree.</para>
<para> A typical usage for an xtree is to show a graphical or textual
representation of the heap usage of a program. The below figure is
check_memory [addressable|defined] <addr> [<len>]
check that <len> (or 1) bytes at <addr> have the given accessibility
and outputs a description of <addr>
- leak_check [full*|summary]
+ leak_check [full*|summary|xtleak]
[kinds kind1,kind2,...|reachable|possibleleak*|definiteleak]
[heuristics heur1,heur2,...]
[increased*|changed|any]
[unlimited*|limited <max_loss_records_output>]
* = defaults
+ xtleak produces an xtree full leak result in xtleak.kcg.%p.%n
where kind is one of:
definite indirect possible reachable all none
where heur is one of:
(with len 1, only shows "start pointers" pointing exactly to <addr>,
with len > 1, will also show "interior pointers")
xtmemory [<filename>]
- dump xtree memory profile in <filename> (default xtmemory.kcg)
+ dump xtree memory profile in <filename> (default xtmemory.kcg.%p.%n)
general valgrind monitor commands:
help [debug] : monitor command help. With debug: + debugging commands
v.wait [<ms>] : sleep <ms> (default 0) then continue
check_memory [addressable|defined] <addr> [<len>]
check that <len> (or 1) bytes at <addr> have the given accessibility
and outputs a description of <addr>
- leak_check [full*|summary]
+ leak_check [full*|summary|xtleak]
[kinds kind1,kind2,...|reachable|possibleleak*|definiteleak]
[heuristics heur1,heur2,...]
[increased*|changed|any]
[unlimited*|limited <max_loss_records_output>]
* = defaults
+ xtleak produces an xtree full leak result in xtleak.kcg.%p.%n
where kind is one of:
definite indirect possible reachable all none
where heur is one of:
(with len 1, only shows "start pointers" pointing exactly to <addr>,
with len > 1, will also show "interior pointers")
xtmemory [<filename>]
- dump xtree memory profile in <filename> (default xtmemory.kcg)
+ dump xtree memory profile in <filename> (default xtmemory.kcg.%p.%n)
monitor command request to kill this process
<para> Note that <option>--show-possibly-lost=no</option> has no effect
if <option>--show-reachable=yes</option> is specified.</para>
</varlistentry>
+
+ <varlistentry id="opt.xtree-leak" xreflabel="--xtree-leak">
+ <term>
+ <option><![CDATA[--xtree-leak=<no|yes> [no] ]]></option>
+ </term>
+ <listitem>
+ <para>If set to yes, the results for the leak search done at exit will be
+ output in a 'Callgrind Format' execution tree file. The produced file
+ will contain the following events:</para>
+ <itemizedlist>
+ <listitem><para><option>RB</option> : Reachable Bytes</para></listitem>
+ <listitem><para><option>PB</option> : Possibly lost Bytes</para></listitem>
+ <listitem><para><option>IB</option> : Indirectly lost Bytes</para></listitem>
+ <listitem><para><option>DB</option> : Definitely lost Bytes (direct plus indirect)</para></listitem>
+ <listitem><para><option>DiB</option> : Definitely indirectly lost Bytes (subset of DB)</para></listitem>
+ <listitem><para><option>RBk</option> : reachable Blocks</para></listitem>
+ <listitem><para><option>PBk</option> : Possibly lost Blocks</para></listitem>
+ <listitem><para><option>IBk</option> : Indirectly lost Blocks</para></listitem>
+ <listitem><para><option>DBk</option> : Definitely lost Blocks</para></listitem>
+ </itemizedlist>
+
+ <para>The increase or decrease for all events above will also be output in
+ the file to provide the delta (increase or decreaseĆ between 2
+ successive leak searches. For example, <option>iRB</option> is the
+ increase of the <option>RB</option> event, <option>dPBk</option> is the
+ decrease of <option>PBk</option> event. The values for the increase and
+ decrease events will be zero for the first leak search done.</para>
+
+ <para>See <xref linkend="manual-core.xtree"/> for a detailed explanation
+ about execution trees.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="opt.xtree-leak-file" xreflabel="--xtree-leak-file">
+ <term>
+ <option><![CDATA[--xtree-leak-file=<filename> [default:
+ xtleak.kcg.%p] ]]></option>
+ </term>
+ <listitem>
+ <para>Specifies that Valgrind should produce the xtree leak
+ report in the specified file. Any <option>%p</option>,
+ <option>%q</option> or <option>%n</option> sequences appearing in
+ the filename are expanded
+ in exactly the same way as they are for <option>--log-file</option>.
+ See the description of <xref linkend="opt.log-file"/>
+ for details. </para>
+ <para>See <xref linkend="manual-core.xtree"/>
+ for a detailed explanation about execution trees formats. </para>
+ </listitem>
+ </varlistentry>
<varlistentry id="opt.undef-value-errors" xreflabel="--undef-value-errors">
<term>
</listitem>
<listitem>
- <para><varname>leak_check [full*|summary]
+ <para><varname>leak_check [full*|summary|xtleak]
[kinds <set>|reachable|possibleleak*|definiteleak]
[heuristics heur1,heur2,...]
[increased*|changed|any]
performs a leak check. The <varname>*</varname> in the arguments
indicates the default values. </para>
- <para> If the <varname>[full*|summary]</varname> argument is
+ <para> If the <varname>[full*|summary|xtleak]</varname> 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
of leak records to output. If this maximum is reached, the leak
search outputs the records with the biggest number of bytes.
</para>
+ <para>The value <varname>xtleak</varname> also produces a full leak report,
+ but output it as an xtree in a file xtleak.kcg.%p.%n (see <xref linkend="opt.log-file"/>).
+ See <xref linkend="manual-core.xtree"/>
+ for a detailed explanation about execution trees formats.
+ See <xref linkend="opt.xtree-leak"/> for the description of the events
+ in a xtree leak file.
+ </para>
<para>The <varname>kinds</varname> argument controls what kind of blocks
are shown for a <varname>full</varname> leak search. The set of leak kinds
// least one interior-pointer along the way.
IndirectLeak =2, // Leaked, but reachable from another leaked block
// (be it Unreached or IndirectLeak).
- Unreached =3, // Not reached, ie. leaked.
+ Unreached =3 // Not reached, ie. leaked.
// (At best, only reachable from itself via a cycle.)
}
Reachedness;
LeakCheckDeltaMode deltamode;
UInt max_loss_records_output; // limit on the nr of loss records output.
Bool requested_by_monitor_command; // True when requested by gdb/vgdb.
+ const HChar* xt_filename; // if != NULL, produce an xtree leak file.
}
LeakCheckParams;
#include "pub_tool_signals.h" // Needed for mc_include.h
#include "pub_tool_libcsetjmp.h" // setjmp facilities
#include "pub_tool_tooliface.h" // Needed for mc_include.h
+#include "pub_tool_xarray.h"
+#include "pub_tool_xtree.h"
#include "mc_include.h"
&& RiS(lr->key.state,lcp->errors_for_leak_kinds);
}
+//
+// Types and functions for xtree leak report.
+//
+
+static XTree* leak_xt;
+
+/* Sizes and delta sizes for a loss record output in an xtree.
+ As the output format can only show positive values, we need values for
+ the increase and decrease cases. */
+typedef
+ struct _XT_BIBK {
+ ULong szB; // Current values
+ ULong indirect_szB;
+ ULong num_blocks;
+ } XT_BIBK; // Bytes, Indirect bytes, BlocKs
+
+typedef
+ enum {
+ XT_Value =0,
+ XT_Increase =1,
+ XT_Decrease =2
+ }
+ XT_VID; // Value or Increase or Decrease
+
+typedef
+ struct _XT_lr {
+ XT_BIBK vid[3]; // indexed by XT_VID
+ } XT_lr;
+
+typedef
+ struct _XT_Leak {
+ XT_lr xt_lr[4]; // indexed by Reachedness
+ } XT_Leak;
+
+static void MC_(XT_Leak_init)(void* xtl)
+{
+ VG_(memset) (xtl, 0, sizeof(XT_Leak));
+}
+static void MC_(XT_Leak_add) (void* to, const void* xtleak)
+{
+ XT_Leak* xto = to;
+ const XT_Leak* xtl = xtleak;
+
+ for (int r = Reachable; r <= Unreached; r++)
+ for (int d = 0; d < 3; d++) {
+ xto->xt_lr[r].vid[d].szB += xtl->xt_lr[r].vid[d].szB;
+ xto->xt_lr[r].vid[d].indirect_szB += xtl->xt_lr[r].vid[d].indirect_szB;
+ xto->xt_lr[r].vid[d].num_blocks += xtl->xt_lr[r].vid[d].num_blocks;
+ }
+}
+static void XT_insert_lr (LossRecord* lr)
+{
+ XT_Leak xtl;
+ Reachedness i = lr->key.state;
+
+ MC_(XT_Leak_init)(&xtl);
+
+ xtl.xt_lr[i].vid[XT_Value].szB = lr->szB;
+ xtl.xt_lr[i].vid[XT_Value].indirect_szB = lr->indirect_szB;
+ xtl.xt_lr[i].vid[XT_Value].num_blocks = lr->num_blocks;
+
+ if (lr->szB > lr->old_szB)
+ xtl.xt_lr[i].vid[XT_Increase].szB = lr->szB - lr->old_szB;
+ else
+ xtl.xt_lr[i].vid[XT_Decrease].szB = lr->old_szB - lr->szB;
+ if (lr->indirect_szB > lr->old_indirect_szB)
+ xtl.xt_lr[i].vid[XT_Increase].indirect_szB
+ = lr->indirect_szB - lr->old_indirect_szB;
+ else
+ xtl.xt_lr[i].vid[XT_Decrease].indirect_szB
+ = lr->old_indirect_szB - lr->indirect_szB;
+ if (lr->num_blocks > lr->old_num_blocks)
+ xtl.xt_lr[i].vid[XT_Increase].num_blocks
+ = lr->num_blocks - lr->old_num_blocks;
+ else
+ xtl.xt_lr[i].vid[XT_Decrease].num_blocks
+ = lr->old_num_blocks - lr->num_blocks;
+
+ VG_(XT_add_to_ec)(leak_xt, lr->key.allocated_at, &xtl);
+}
+
+static void MC_(XT_Leak_sub) (void* from, const void* xtleak)
+{
+ tl_assert(0); // Should not be called.
+}
+static const HChar* MC_(XT_Leak_img) (const void* xtleak)
+{
+ static XT_Leak zero;
+ static HChar buf[600];
+ UInt off = 0;
+
+ const XT_Leak* xtl = xtleak;
+
+ if (VG_(memcmp)(xtl, &zero, sizeof(XT_Leak)) != 0) {
+ for (UInt d = XT_Value; d <= XT_Decrease; d++) {
+ // print szB. We add indirect_szB to have the Unreachable showing
+ // the total bytes loss, including indirect loss. This is similar
+ // to the textual and xml reports.
+ for (UInt r = Reachable; r <= Unreached; r++)
+ off += VG_(sprintf) (buf + off, " %llu",
+ xtl->xt_lr[r].vid[d].szB
+ + xtl->xt_lr[r].vid[d].indirect_szB);
+ // print indirect_szB, only for reachedness having such values)
+ for (UInt r = Reachable; r <= Unreached; r++)
+ if (r == Unreached)
+ off += VG_(sprintf) (buf + off, " %llu",
+ xtl->xt_lr[r].vid[d].indirect_szB);
+ // print num_blocks
+ for (UInt r = Reachable; r <= Unreached; r++)
+ off += VG_(sprintf) (buf + off, " %llu",
+ xtl->xt_lr[r].vid[d].num_blocks);
+ }
+ return buf + 1; // + 1 to skip the useless first space
+ } else {
+ return NULL;
+ }
+}
+
+/* The short event name is made of 2 or 3 or 4 letters:
+ an optional delta indication: i = increase d = decrease
+ a loss kind: R = Reachable P = Possibly I = Indirectly D = Definitely
+ an optional i to indicate this loss record has indirectly lost bytes
+ B = Bytes or Bk = Blocks.
+ Note that indirectly lost bytes/blocks can thus be counted in 2
+ loss records: the loss records for their "own" allocation stack trace,
+ and the loss record of the 'main' Definitely or Possibly loss record
+ in the indirectly lost count for these loss records. */
+static const HChar* XT_Leak_events =
+ ////// XT_Value szB
+ "RB : Reachable Bytes" ","
+ "PB : Possibly lost Bytes" ","
+ "IB : Indirectly lost Bytes" ","
+ "DB : Definitely lost Bytes (direct plus indirect)" ","
+
+ ////// XT_Value indirect_szB
+ // no RiB
+ // no PiB
+ // no IiB
+ "DiB : Definitely indirectly lost Bytes (subset of DB)" ","
+
+ ////// XT_Value num_blocks
+ "RBk : reachable Blocks" ","
+ "PBk : Possibly lost Blocks" ","
+ "IBk : Indirectly lost Blocks" ","
+ "DBk : Definitely lost Blocks" ","
+
+ ////// XT_Increase szB
+ "iRB : increase Reachable Bytes" ","
+ "iPB : increase Possibly lost Bytes" ","
+ "iIB : increase Indirectly lost Bytes" ","
+ "iDB : increase Definitely lost Bytes" ","
+
+ ////// XT_Increase indirect_szB
+ // no iRiB
+ // no iPiB
+ // no iIiB
+ "iDiB : increase Definitely indirectly lost Bytes" ","
+
+ ////// XT_Increase num_blocks
+ "iRBk : increase reachable Blocks" ","
+ "iPBk : increase Possibly lost Blocks" ","
+ "iIBk : increase Indirectly lost Blocks" ","
+ "iDBk : increase Definitely lost Blocks" ","
+
+
+ ////// XT_Decrease szB
+ "dRB : decrease Reachable Bytes" ","
+ "dPB : decrease Possibly lost Bytes" ","
+ "dIB : decrease Indirectly lost Bytes" ","
+ "dDB : decrease Definitely lost Bytes" ","
+
+ ////// XT_Decrease indirect_szB
+ // no dRiB
+ // no dPiB
+ // no dIiB
+ "dDiB : decrease Definitely indirectly lost Bytes" ","
+
+ ////// XT_Decrease num_blocks
+ "dRBk : decrease reachable Blocks" ","
+ "dPBk : decrease Possibly lost Blocks" ","
+ "dIBk : decrease Indirectly lost Blocks" ","
+ "dDBk : decrease Definitely lost Blocks";
+
static void print_results(ThreadId tid, LeakCheckParams* lcp)
{
Int i, n_lossrecords, start_lr_output_scan;
}
}
+ if (lcp->xt_filename != NULL)
+ leak_xt = VG_(XT_create) (VG_(malloc),
+ "mc_leakcheck.leak_xt",
+ VG_(free),
+ sizeof(XT_Leak),
+ MC_(XT_Leak_init),
+ MC_(XT_Leak_add),
+ MC_(XT_Leak_sub),
+ VG_(XT_filter_maybe_below_main));
+
// Print the loss records (in size order) and collect summary stats.
for (i = start_lr_output_scan; i < n_lossrecords; i++) {
Bool count_as_error, print_record;
lr = lr_array[i];
get_printing_rules(lcp, lr, &count_as_error, &print_record);
is_suppressed =
- MC_(record_leak_error) ( tid, i+1, n_lossrecords, lr, print_record,
- count_as_error );
+ MC_(record_leak_error)
+ ( tid, i+1, n_lossrecords, lr,
+ lcp->xt_filename == NULL ? print_record : False,
+ count_as_error );
+ if (lcp->xt_filename != NULL && !is_suppressed && print_record)
+ XT_insert_lr (lr);
if (is_suppressed) {
MC_(blocks_suppressed) += lr->num_blocks;
}
}
+ if (lcp->xt_filename != NULL) {
+ VG_(XT_callgrind_print)(leak_xt,
+ lcp->xt_filename,
+ XT_Leak_events,
+ MC_(XT_Leak_img));
+ VG_(XT_delete)(leak_xt);
+ }
+
if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) {
HChar d_bytes[31];
HChar d_blocks[31];
| H2S( LchLength64)
| H2S( LchNewArray)
| H2S( LchMultipleInheritance);
+Bool MC_(clo_xtree_leak) = False;
+const HChar* MC_(clo_xtree_leak_file) = "xtleak.kcg.%p";
Bool MC_(clo_workaround_gcc296_bugs) = False;
Int MC_(clo_malloc_fill) = -1;
Int MC_(clo_free_fill) = -1;
else if VG_BOOL_CLO(arg, "--expensive-definedness-checks",
MC_(clo_expensive_definedness_checks)) {}
+ else if VG_BOOL_CLO(arg, "--xtree-leak",
+ MC_(clo_xtree_leak)) {}
+ else if VG_STR_CLO (arg, "--xtree-leak-file",
+ MC_(clo_xtree_leak_file)) {}
+
else
return VG_(replacement_malloc_process_cmd_line_option)(arg);
" same as --show-leak-kinds=definite,possible\n"
" --show-reachable=no --show-possibly-lost=no\n"
" same as --show-leak-kinds=definite\n"
+" --xtree-leak=no|yes output leak result in xtree format? [no]\n"
+" --xtree-leak-file=<file> xtree leak report file [xtleak.kcg.%%p.%%n]\n"
" --undef-value-errors=no|yes check for undefined value errors [yes]\n"
" --track-origins=no|yes show origins of undefined values? [no]\n"
" --partial-loads-ok=no|yes too hard to explain here; see manual [yes]\n"
" 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"
-" leak_check [full*|summary]\n"
+" leak_check [full*|summary|xtleak]\n"
" [kinds kind1,kind2,...|reachable|possibleleak*|definiteleak]\n"
" [heuristics heur1,heur2,...]\n"
" [increased*|changed|any]\n"
" [unlimited*|limited <max_loss_records_output>]\n"
" * = defaults\n"
+" xtleak produces an xtree full leak result in xtleak.kcg.%%p.%%n\n"
" where kind is one of:\n"
" definite indirect possible reachable all none\n"
" where heur is one of:\n"
" (with len 1, only shows \"start pointers\" pointing exactly to <addr>,\n"
" with len > 1, will also show \"interior pointers\")\n"
" xtmemory [<filename>]\n"
-" dump xtree memory profile in <filename> (default xtmemory.kcg)\n"
+" dump xtree memory profile in <filename> (default xtmemory.kcg.%%p.%%n)\n"
"\n");
}
case 2: { /* leak_check */
Int err = 0;
LeakCheckParams lcp;
+ HChar* xt_filename = NULL;
HChar* kw;
lcp.mode = LC_Full;
lcp.deltamode = LCD_Increased;
lcp.max_loss_records_output = 999999999;
lcp.requested_by_monitor_command = True;
+ lcp.xt_filename = NULL;
for (kw = VG_(strtok_r) (NULL, " ", &ssaveptr);
kw != NULL;
kw = VG_(strtok_r) (NULL, " ", &ssaveptr)) {
switch (VG_(keyword_id)
- ("full summary "
+ ("full summary xtleak "
"kinds reachable possibleleak definiteleak "
"heuristics "
"increased changed any "
lcp.mode = LC_Full; break;
case 1: /* summary */
lcp.mode = LC_Summary; break;
- case 2: { /* kinds */
+ case 2: /* xtleak */
+ lcp.mode = LC_Full;
+ xt_filename
+ = VG_(expand_file_name)("--xtleak-mc_main.c",
+ "xtleak.kcg.%p.%n");
+ lcp.xt_filename = xt_filename;
+ break;
+ case 3: { /* kinds */
wcmd = VG_(strtok_r) (NULL, " ", &ssaveptr);
if (wcmd == NULL
|| !VG_(parse_enum_set)(MC_(parse_leak_kinds_tokens),
}
break;
}
- case 3: /* reachable */
+ case 4: /* reachable */
lcp.show_leak_kinds = MC_(all_Reachedness)();
break;
- case 4: /* possibleleak */
+ case 5: /* possibleleak */
lcp.show_leak_kinds
= R2S(Possible) | R2S(IndirectLeak) | R2S(Unreached);
break;
- case 5: /* definiteleak */
+ case 6: /* definiteleak */
lcp.show_leak_kinds = R2S(Unreached);
break;
- case 6: { /* heuristics */
+ case 7: { /* heuristics */
wcmd = VG_(strtok_r) (NULL, " ", &ssaveptr);
if (wcmd == NULL
|| !VG_(parse_enum_set)(MC_(parse_leak_heuristics_tokens),
}
break;
}
- case 7: /* increased */
+ case 8: /* increased */
lcp.deltamode = LCD_Increased; break;
- case 8: /* changed */
+ case 9: /* changed */
lcp.deltamode = LCD_Changed; break;
- case 9: /* any */
+ case 10: /* any */
lcp.deltamode = LCD_Any; break;
- case 10: /* unlimited */
+ case 11: /* unlimited */
lcp.max_loss_records_output = 999999999; break;
- case 11: { /* limited */
+ case 12: { /* limited */
Int int_value;
const HChar* endptr;
}
if (!err)
MC_(detect_memory_leaks)(tid, &lcp);
+ if (xt_filename != NULL)
+ VG_(free)(xt_filename);
return True;
}
}
lcp.max_loss_records_output = 999999999;
lcp.requested_by_monitor_command = False;
+ lcp.xt_filename = NULL;
MC_(detect_memory_leaks)(tid, &lcp);
*ret = 0; /* return value is meaningless */
if (MC_(clo_leak_check) != LC_Off) {
LeakCheckParams lcp;
+ HChar* xt_filename = NULL;
lcp.mode = MC_(clo_leak_check);
lcp.show_leak_kinds = MC_(clo_show_leak_kinds);
lcp.heuristics = MC_(clo_leak_check_heuristics);
lcp.deltamode = LCD_Any;
lcp.max_loss_records_output = 999999999;
lcp.requested_by_monitor_command = False;
+ if (MC_(clo_xtree_leak)) {
+ xt_filename = VG_(expand_file_name)("--xtree-leak-file",
+ MC_(clo_xtree_leak_file));
+ lcp.xt_filename = xt_filename;
+ }
+ else
+ lcp.xt_filename = NULL;
MC_(detect_memory_leaks)(1/*bogus ThreadId*/, &lcp);
+ if (MC_(clo_xtree_leak))
+ VG_(free)(xt_filename);
} else {
if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
VG_(umsg)(