for 'use after free' errors or to decrease Valgrind memory and/or cpu usage
by recording less information for heap blocks.
+ - The list of used suppressions (shown when giving the -v option)
+ now shows for the leak suppressions how many blocks and bytes were
+ suppressed during the last leak search for each suppression.
+ The suppression count for a leak suppression shows the total nr
+ of loss records which were suppressed by this suppression.
+
* ==================== OTHER CHANGES ====================
- Option --merge-recursive-frames=<number> tells Valgrind to
'v.do expensive_sanity_check_general' that checks the sanity
of various Valgrind aspects, including the Valgrind heap.
+ - The list of used suppressions (shown when giving the -v option)
+ now gives the filename and linenr where the suppression is defined.
+
- remote debuginfo server + overhaul of debuginfo reading
- some fixes for OSX 10.8
" </pair>\n",
su->count, su->sname );
} else {
+ HChar xtra[256]; /* assumed big enough (is overrun-safe) */
+ Bool anyXtra;
// blank line before the first shown suppression, if any
if (!any_supp)
VG_(dmsg)("\n");
- VG_(dmsg)("used_suppression: %6d %s %s:%d\n", su->count, su->sname,
+ VG_(memset)(xtra, 0, sizeof(xtra));
+ anyXtra = VG_TDICT_CALL(tool_print_extra_suppression_use,
+ su, xtra, sizeof(xtra));
+ vg_assert(xtra[sizeof(xtra)-1] == 0);
+ VG_(dmsg)("used_suppression: %6d %s %s:%d%s%s\n", su->count, su->sname,
VG_(clo_suppressions)[su->clo_suppressions_i],
- su->sname_lineno);
+ su->sname_lineno,
+ anyXtra ? " " : "", xtra);
}
any_supp = True;
}
/* Conceptually, ip2fo contains an array of function names and an array of
object names, corresponding to the array of IP of err->where.
These names are just computed 'on demand' (so once maximum),
- then stored (efficiently, avoiding too many allocs) in ip2fo to be re-usable
- for the matching of the same IP with the next suppression pattern.
+ then stored (efficiently, avoiding too many allocs) in ip2fo to be
+ re-usable for the matching of the same IP with the next suppression
+ pattern.
VG_(generic_match) gets this 'IP to Fun or Obj name completer' as one
of its arguments. It will then pass it to the function
em_supplist_cmps++;
if (supp_matches_error(su, err)
&& supp_matches_callers(&ip2fo, su)) {
- /* got a match. Move this entry to the head of the list
+ /* got a match. */
+ /* Inform the tool that err is suppressed by su. */
+ (void)VG_TDICT_CALL(tool_update_extra_suppression_use, err, su);
+ /* Move this entry to the head of the list
in the hope of making future searches cheaper. */
if (su_prev) {
vg_assert(su_prev->next == su);
Bool (*read_extra) (Int, HChar**, SizeT*, Int*, Supp*),
Bool (*matches) (Error*, Supp*),
const HChar* (*name) (Error*),
- Bool (*get_xtra_si)(Error*,/*OUT*/HChar*,Int)
+ Bool (*get_xtra_si)(Error*,/*OUT*/HChar*,Int),
+ Bool (*print_xtra_su)(Supp*,/*OUT*/HChar*,Int),
+ void (*update_xtra_su)(Error*, Supp*)
)
{
VG_(needs).tool_errors = True;
VG_(tdict).tool_error_matches_suppression = matches;
VG_(tdict).tool_get_error_name = name;
VG_(tdict).tool_get_extra_suppression_info = get_xtra_si;
+ VG_(tdict).tool_print_extra_suppression_use = print_xtra_su;
+ VG_(tdict).tool_update_extra_suppression_use = update_xtra_su;
}
void VG_(needs_command_line_options)(
Bool (*tool_error_matches_suppression) (Error*, Supp*);
const HChar* (*tool_get_error_name) (Error*);
Bool (*tool_get_extra_suppression_info) (Error*,/*OUT*/HChar*,Int);
+ Bool (*tool_print_extra_suppression_use) (Supp*,/*OUT*/HChar*,Int);
+ void (*tool_update_extra_suppression_use) (Error*, Supp*);
// VG_(needs).superblock_discards
void (*tool_discard_superblock_info)(Addr64, VexGuestExtents);
specification of errors to suppress.</para>
<para>If you use the <option>-v</option> option, at the end of execution,
-Valgrind prints out one line for each used suppression, giving its name
-and the number of times it got used. Here's the suppressions used by a
-run of <computeroutput>valgrind --tool=memcheck ls -l</computeroutput>:</para>
+Valgrind prints out one line for each used suppression, giving the number of times
+it got used, its name and the filename and line number where the suppression is
+defined. Depending on the suppression kind, the filename and line number are optionally
+followed by additional information (such as the number of blocks and bytes suppressed
+by a memcheck leak suppression). Here's the suppressions used by a
+run of <computeroutput>valgrind -v --tool=memcheck ls -l</computeroutput>:</para>
<programlisting><![CDATA[
---27579-- supp: 1 socketcall.connect(serv_addr)/__libc_connect/__nscd_getgrgid_r
---27579-- supp: 1 socketcall.connect(serv_addr)/__libc_connect/__nscd_getpwuid_r
---27579-- supp: 6 strrchr/_dl_map_object_from_fd/_dl_map_object]]></programlisting>
+--1610-- used_suppression: 2 dl-hack3-cond-1 /usr/lib/valgrind/default.supp:1234
+--1610-- used_suppression: 2 glibc-2.5.x-on-SUSE-10.2-(PPC)-2a /usr/lib/valgrind/default.supp:1234
+]]></programlisting>
<para>Multiple suppressions files are allowed. By default, Valgrind
uses <filename>$PREFIX/lib/valgrind/default.supp</filename>. You can
return False;
}
+static
+Bool drd_print_extra_suppression_use(Supp* su,
+ /*OUT*/HChar* buf, Int nBuf)
+{
+ return False;
+}
+
+static
+void drd_update_extra_suppresion_use(Error* e, Supp* supp)
+{
+ return;
+}
+
/** Tell the Valgrind core about DRD's error handlers. */
void DRD_(register_error_handlers)(void)
{
drd_read_extra_suppression_info,
drd_error_matches_suppression,
drd_get_error_name,
- drd_get_extra_suppression_info);
+ drd_get_extra_suppression_info,
+ drd_print_extra_suppression_use,
+ drd_update_extra_suppresion_use);
}
}
}
+Bool pc_print_extra_suppression_use ( Supp* su,
+ /*OUT*/HChar* buf, Int nBuf )
+{
+ return False;
+}
+
+void pc_update_extra_suppression_use (Error* err, Supp* su)
+{
+ return;
+}
/*--------------------------------------------------------------------*/
/*--- end pc_common.c ---*/
const HChar* pc_get_error_name ( Error* err );
Bool pc_get_extra_suppression_info ( Error* err,
/*OUT*/HChar* buf, Int nBuf );
+Bool pc_print_extra_suppression_use ( Supp* su,
+ /*OUT*/HChar* buf, Int nBuf );
+void pc_update_extra_suppression_use (Error* err, Supp* su);
extern Bool h_clo_partial_loads_ok;
/* extern Bool h_clo_lossage_check; */
pc_read_extra_suppression_info,
pc_error_matches_suppression,
pc_get_error_name,
- pc_get_extra_suppression_info);
+ pc_get_extra_suppression_info,
+ pc_print_extra_suppression_use,
+ pc_update_extra_suppression_use);
VG_(needs_xml_output) ();
return False;
}
+Bool HG_(print_extra_suppression_use) ( Supp* su,
+ /*OUT*/HChar* buf, Int nBuf )
+{
+ /* Do nothing */
+ return False;
+}
+
+void HG_(update_extra_suppression_use) ( Error* err, Supp* su )
+{
+ /* Do nothing */
+ return;
+}
+
/*--------------------------------------------------------------------*/
/*--- end hg_errors.c ---*/
const HChar* HG_(get_error_name) ( Error* err );
Bool HG_(get_extra_suppression_info) ( Error* err,
/*OUT*/HChar* buf, Int nBuf );
+Bool HG_(print_extra_suppression_use) ( Supp* su,
+ /*OUT*/HChar* buf, Int nBuf );
+void HG_(update_extra_suppression_use) ( Error* err, Supp* su );
/* Functions for recording various kinds of errors. */
void HG_(record_error_Race) ( Thread* thr,
HG_(read_extra_suppression_info),
HG_(error_matches_suppression),
HG_(get_error_name),
- HG_(get_extra_suppression_info));
+ HG_(get_extra_suppression_info),
+ HG_(print_extra_suppression_use),
+ HG_(update_extra_suppression_use));
VG_(needs_xml_output) ();
// do nothing, and return False. This function is the inverse of
// VG_(tdict).tool_read_extra_suppression_info().
Bool (*print_extra_suppression_info)(Error* err,
- /*OUT*/HChar* buf, Int nBuf)
+ /*OUT*/HChar* buf, Int nBuf),
+
+ // This is similar to print_extra_suppression_info, but is used
+ // to print information such as additional statistical counters
+ // as part of the used suppression list produced by -v.
+ Bool (*print_extra_suppression_use)(Supp* su,
+ /*OUT*/HChar* buf, Int nBuf),
+
+ // Called by error mgr once it has been established that err
+ // is suppressed by su. update_extra_suppression_use typically
+ // can be used to update suppression extra information such as
+ // some statistical counters that will be printed by
+ // print_extra_suppression_use.
+ void (*update_extra_suppression_use)(Error* err, Supp* su)
);
/* Is information kept by the tool about specific instructions or
<computeroutput><set></computeroutput> is specified similarly
to the option <option>--show-leak-kinds</option>.
If this optional extra line is not present, the suppression entry will match
-all leak kinds.
-</para>
+all leak kinds. </para>
<para>The other memcheck error kinds do not have extra lines.</para>
+<para>
+If you give the <option>-v</option> option, Valgrind will print
+the list of used suppressions at the end of the execution.
+For a leak suppression, this output gives the number of different
+loss records that matches the suppression, the number of bytes
+and blocks suppressed by the suppressions.
+In case several leak searches are done, the number of bytes and blocks
+are reset to 0 before a new leak search. Note that the number of different
+loss records is not reset to 0.
+<para>In the example below, in the last leak search, 7 blocks and 96 bytes have
+been suppressed by the <option>some_leak_suppression</option>
+suppression. </para>
+<programlisting><![CDATA[
+--21041-- used_suppression: 10 some_other_leak_suppression s.supp:14 suppressed: 12,400 bytes in 1 blocks
+--21041-- used_suppression: 39 some_leak_suppression s.supp:2 suppressed: 96 bytes in 7 blocks
+]]></programlisting>
+</para>
+
<para>The first line of the calling context: for <varname>ValueN</varname>
and <varname>AddrN</varname> errors, it is either the name of the function
in which the error occurred, or, failing that, the full path of the
struct _MC_LeakSuppExtra {
UInt match_leak_kinds;
+
+ /* Maintains nr of blocks and bytes suppressed with this suppression
+ during the leak search identified by leak_search_gen.
+ blocks_suppressed and bytes_suppressed are reset to 0 when
+ used the first time during a leak search. */
+ SizeT blocks_suppressed;
+ SizeT bytes_suppressed;
+ UInt leak_search_gen;
};
Bool MC_(read_extra_suppression_info) ( Int fd, HChar** bufpp,
MC_LeakSuppExtra* lse;
lse = VG_(malloc)("mc.resi.2", sizeof(MC_LeakSuppExtra));
lse->match_leak_kinds = RallS;
+ lse->blocks_suppressed = 0;
+ lse->bytes_suppressed = 0;
+ lse->leak_search_gen = 0;
VG_(set_supp_extra)(su, lse); // By default, all kinds will match.
eof = VG_(get_line) ( fd, bufpp, nBufp, lineno );
if (eof) return True; // old LeakSupp style, no match-leak-kinds line.
case LeakSupp:
if (ekind == Err_Leak) {
MC_LeakSuppExtra* lse = (MC_LeakSuppExtra*) VG_(get_supp_extra)(su);
+ if (lse->leak_search_gen != MC_(leak_search_gen)) {
+ // First time we see this suppression during this leak search.
+ // => reset the counters to 0.
+ lse->blocks_suppressed = 0;
+ lse->bytes_suppressed = 0;
+ lse->leak_search_gen = MC_(leak_search_gen);
+ }
return RiS(extra->Err.Leak.lr->key.state, lse->match_leak_kinds);
} else
return False;
}
}
+Bool MC_(print_extra_suppression_use) ( Supp *su,
+ /*OUT*/HChar *buf, Int nBuf )
+{
+ if (VG_(get_supp_kind)(su) == LeakSupp) {
+ MC_LeakSuppExtra *lse = (MC_LeakSuppExtra*) VG_(get_supp_extra) (su);
+
+ if (lse->leak_search_gen == MC_(leak_search_gen)
+ && lse->blocks_suppressed > 0) {
+ VG_(snprintf) (buf, nBuf-1,
+ "suppressed: %'lu bytes in %'lu blocks",
+ lse->bytes_suppressed,
+ lse->blocks_suppressed);
+ return True;
+ } else
+ return False;
+ } else
+ return False;
+}
+
+void MC_(update_extra_suppression_use) ( Error* err, Supp* su)
+{
+ if (VG_(get_supp_kind)(su) == LeakSupp) {
+ MC_LeakSuppExtra *lse = (MC_LeakSuppExtra*) VG_(get_supp_extra) (su);
+ MC_Error* extra = VG_(get_error_extra)(err);
+
+ tl_assert (lse->leak_search_gen = MC_(leak_search_gen));
+ lse->blocks_suppressed += extra->Err.Leak.lr->num_blocks;
+ lse->bytes_suppressed
+ += extra->Err.Leak.lr->szB + extra->Err.Leak.lr->indirect_szB;
+ }
+}
/*--------------------------------------------------------------------*/
/*--- end mc_errors.c ---*/
void MC_(detect_memory_leaks) ( ThreadId tid, LeakCheckParams * lcp);
+// Each time a leak search is done, the leak search generation
+// MC_(leak_search_gen) is incremented.
+extern UInt MC_(leak_search_gen);
+
// maintains the lcp.deltamode given in the last call to detect_memory_leaks
extern LeakCheckDeltaMode MC_(detect_memory_leaks_last_delta_mode);
Bool MC_(get_extra_suppression_info) ( Error* err,
/*OUT*/HChar* buf, Int nBuf );
+Bool MC_(print_extra_suppression_use) ( Supp* su,
+ /*OUT*/HChar* buf, Int nBuf );
+void MC_(update_extra_suppression_use) ( Error* err, Supp* su );
const HChar* MC_(get_error_name) ( Error* err );
// The below avoids replicating the delta_mode in each LossRecord.
LeakCheckDeltaMode MC_(detect_memory_leaks_last_delta_mode);
+// Each leak search run increments the below generation counter.
+// A used suppression during a leak search will contain this
+// generation number.
+UInt MC_(leak_search_gen);
// Records chunks that are currently being processed. Each element in the
// stack is an index into lc_chunks and lc_extras. Its size is
// before checking for (smaller) page skipping.
tl_assert((SM_SIZE % VKI_PAGE_SIZE) == 0);
-
+ MC_(leak_search_gen)++;
MC_(detect_memory_leaks_last_delta_mode) = lcp->deltamode;
detect_memory_leaks_last_heuristics = lcp->heuristics;
MC_(read_extra_suppression_info),
MC_(error_matches_suppression),
MC_(get_error_name),
- MC_(get_extra_suppression_info));
+ MC_(get_extra_suppression_info),
+ MC_(print_extra_suppression_use),
+ MC_(update_extra_suppression_use));
VG_(needs_libc_freeres) ();
VG_(needs_command_line_options)(mc_process_cmd_line_options,
mc_print_usage,