Added a new parameter to the memcheck 'leak_check' GDB monitor command
to let the user specify a max nr of loss records to output : on huge
applications, interactive display of a lot of records in gdb can
take a lot of time.
* mc_include.h :
- added UInt max_loss_records_output; to LeakCheckParams structure
- avoid passing LeakCheckParams by struct copy.
* modified test gdbserver_tests/mcleak to test the new parameter
* mc_main.c : parse or set max_loss_records_output in leak_check cmd
handling and calls.
* mc-manual.xml : document new leak_check parameter
* mc_leakcheck.c :
- extract printing rules logic in its own function
- in print_results, if there is a limit in LeakCheckParam,
compute from where the printing of loss records has to start
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@12329 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/memcheck/mc_leakcheck.c b/memcheck/mc_leakcheck.c
index 944ef27..1f8cd65 100644
--- a/memcheck/mc_leakcheck.c
+++ b/memcheck/mc_leakcheck.c
@@ -781,9 +781,64 @@
return 0;
}
-static void print_results(ThreadId tid, LeakCheckParams lcp)
+
+static void get_printing_rules(LeakCheckParams* lcp,
+ LossRecord* lr,
+ Bool* count_as_error,
+ Bool* print_record)
{
- Int i, n_lossrecords;
+ // Rules for printing:
+ // - We don't show suppressed loss records ever (and that's controlled
+ // within the error manager).
+ // - We show non-suppressed loss records that are not "reachable" if
+ // --leak-check=yes.
+ // - We show all non-suppressed loss records if --leak-check=yes and
+ // --show-reachable=yes.
+ //
+ // Nb: here "reachable" means Reachable *or* IndirectLeak; note that
+ // this is different to "still reachable" used elsewhere because it
+ // includes indirectly lost blocks!
+
+ Bool delta_considered;
+
+ switch (lcp->deltamode) {
+ case LCD_Any:
+ delta_considered = lr->num_blocks > 0;
+ break;
+ case LCD_Increased:
+ delta_considered
+ = lr->szB > lr->old_szB
+ || lr->indirect_szB > lr->old_indirect_szB
+ || lr->num_blocks > lr->old_num_blocks;
+ break;
+ case LCD_Changed:
+ delta_considered = lr->szB != lr->old_szB
+ || lr->indirect_szB != lr->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 ||
+ ( lcp->show_possibly_lost &&
+ Possible == lr->key.state ) );
+ // 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 = lcp->mode == LC_Full && delta_considered &&
+ ( Unreached == lr->key.state ||
+ Possible == lr->key.state );
+}
+
+static void print_results(ThreadId tid, LeakCheckParams* lcp)
+{
+ Int i, n_lossrecords, start_lr_output_scan;
LossRecord** lr_array;
LossRecord* lr;
Bool is_suppressed;
@@ -864,55 +919,37 @@
MC_(blocks_reachable) = MC_(bytes_reachable) = 0;
MC_(blocks_suppressed) = MC_(bytes_suppressed) = 0;
- // Print the loss records (in size order) and collect summary stats.
- for (i = 0; i < n_lossrecords; i++) {
- 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).
- // - We show non-suppressed loss records that are not "reachable" if
- // --leak-check=yes.
- // - We show all non-suppressed loss records if --leak-check=yes and
- // --show-reachable=yes.
- //
- // Nb: here "reachable" means Reachable *or* IndirectLeak; note that
- // this is different to "still reachable" used elsewhere because it
- // includes indirectly lost blocks!
- //
- lr = lr_array[i];
- 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);
+ // If there is a maximum nr of loss records we can output, then first
+ // compute from where the output scan has to start.
+ // By default, start from the first loss record. Compute a higher
+ // value if there is a maximum to respect. We need to print the last
+ // records, as the one with the biggest sizes are more interesting.
+ start_lr_output_scan = 0;
+ if (lcp->mode == LC_Full && lcp->max_loss_records_output < n_lossrecords) {
+ Int nr_printable_records = 0;
+ for (i = n_lossrecords - 1; i >= 0 && start_lr_output_scan == 0; i--) {
+ Bool count_as_error, print_record;
+ lr = lr_array[i];
+ get_printing_rules (lcp, lr, &count_as_error, &print_record);
+ // Do not use get_printing_rules results for is_suppressed, as we
+ // only want to check if the record would be suppressed.
+ is_suppressed =
+ MC_(record_leak_error) ( tid, i+1, n_lossrecords, lr,
+ False /* print_record */,
+ False /* count_as_error */);
+ if (print_record && !is_suppressed) {
+ nr_printable_records++;
+ if (nr_printable_records == lcp->max_loss_records_output)
+ start_lr_output_scan = i;
+ }
}
+ }
- print_record = lcp.mode == LC_Full && delta_considered &&
- ( lcp.show_reachable ||
- Unreached == lr->key.state ||
- ( lcp.show_possibly_lost &&
- Possible == lr->key.state ) );
- // 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 = lcp.mode == LC_Full && delta_considered &&
- ( Unreached == lr->key.state ||
- Possible == lr->key.state );
+ // 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 );
@@ -968,44 +1005,44 @@
VG_(umsg)("LEAK SUMMARY:\n");
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_(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));
+ 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_(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) );
+ 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_(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) );
+ 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_(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) );
+ 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_(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_(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) {
- if (lcp.requested_by_monitor_command)
+ if (lcp->requested_by_monitor_command)
VG_(umsg)("To see details of leaked memory, give 'full' arg to leak_check\n");
else
VG_(umsg)("Rerun with --leak-check=full to see details "
"of leaked memory\n");
}
- if (lcp.mode == LC_Full &&
- MC_(blocks_reachable) > 0 && !lcp.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");
- if (lcp.requested_by_monitor_command)
+ if (lcp->requested_by_monitor_command)
VG_(umsg)("To see them, add 'reachable any' args to leak_check\n");
else
VG_(umsg)("To see them, rerun with: --leak-check=full "
@@ -1019,13 +1056,13 @@
/*--- Top-level entry point. ---*/
/*------------------------------------------------------------*/
-void MC_(detect_memory_leaks) ( ThreadId tid, LeakCheckParams lcp)
+void MC_(detect_memory_leaks) ( ThreadId tid, LeakCheckParams* lcp)
{
Int i, j;
- tl_assert(lcp.mode != LC_Off);
+ tl_assert(lcp->mode != LC_Off);
- MC_(detect_memory_leaks_last_delta_mode) = lcp.deltamode;
+ 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);