|
From: Adam S. <sim...@ne...> - 2006-01-25 00:29:35
|
Below is a patch that I've found extremely handy. It modifies
valgrind in the following two ways:
- When memory leaks are detected, the addresses of the first 3
leaked blocks in each loss record are printed.
- If "--db-attach=yes" is specified, valgrind prompts to attach the
db after each loss record is printed.
For instance, I use this in a network server that reads messages from
a socket. All of the messages are allocated in the same place when
they are read, but they are processed differently based on their
contents. With this enhancement, I can examine the contents of leaked
messages to figure out which part of the code should have been
responsible for processing and freeing them.
I've been using this modification for quite a while now. I was a
little concerned at first about attaching the db to a process that has
already exited, but everything seems to work fine. I noticed that
with valgrind 3.1.0 there is actually a backtrace now when the db
attaches. (I used to use valgrind 2.2 and 1.9.6 with this patch, and
there was no backtrace--gdb would just report "???".)
--
Adam Simpkins
sim...@ne...
diff -Naur valgrind-3.1.0/memcheck/mac_leakcheck.c valgrind-3.1.0.db-on-leak/memcheck/mac_leakcheck.c
--- valgrind-3.1.0/memcheck/mac_leakcheck.c 2005-11-25 04:36:02.000000000 -0800
+++ valgrind-3.1.0.db-on-leak/memcheck/mac_leakcheck.c 2006-01-24 13:17:51.000000000 -0800
@@ -126,6 +126,9 @@
}
Reachedness;
+/* The maximum number of lost addresses we store */
+enum { NUM_LOST_ADDRESSES = 3 };
+
/* An entry in the mark stack */
typedef
struct {
@@ -147,6 +150,8 @@
SizeT total_bytes;
SizeT indirect_bytes;
UInt num_blocks;
+ /* The addresses of the first few lost blocks */
+ Addr addresses[NUM_LOST_ADDRESSES];
}
LossRecord;
@@ -272,6 +277,7 @@
LeakExtra* extra = (LeakExtra*)vextra;
LossRecord* l = extra->lossRecord;
const Char *loss = str_lossmode(l->loss_mode);
+ unsigned int n;
if (VG_(clo_xml)) {
VG_(message)(Vg_UserMsg, " <kind>%t</kind>", xml_kind(l->loss_mode));
@@ -312,6 +318,12 @@
l->num_blocks);
}
}
+ for (n = 0; n < NUM_LOST_ADDRESSES; ++n) {
+ if (n >= l->num_blocks)
+ break;
+ VG_(message)(Vg_UserMsg, " Block %d of %d: 0x%x",
+ n + 1, l->num_blocks, l->addresses[n]);
+ }
VG_(pp_ExeContext)(l->allocated_at);
}
@@ -561,6 +573,8 @@
p->num_blocks ++;
p->total_bytes += lc_shadows[i]->size;
p->indirect_bytes += lc_markstack[i].indirect;
+ if (p->num_blocks - 1 < NUM_LOST_ADDRESSES)
+ p->addresses[p->num_blocks - 1] = lc_shadows[i]->data;
} else {
n_lossrecords ++;
p = VG_(malloc)(sizeof(LossRecord));
@@ -569,6 +583,7 @@
p->total_bytes = lc_shadows[i]->size;
p->indirect_bytes = lc_markstack[i].indirect;
p->num_blocks = 1;
+ p->addresses[0] = lc_shadows[i]->data;
p->next = errlist;
errlist = p;
}
@@ -577,6 +592,7 @@
/* Print out the commoned-up blocks and collect summary stats. */
for (i = 0; i < n_lossrecords; i++) {
Bool print_record;
+ Bool allow_db_attach;
LossRecord* p_min = NULL;
SizeT n_min = ~(0x0L);
for (p = errlist; p != NULL; p = p->next) {
@@ -596,6 +612,8 @@
print_record = ( MAC_(clo_show_reachable) ||
Unreached == p_min->loss_mode ||
Interior == p_min->loss_mode );
+ /* Allow attaching the debugger if we print the error */
+ allow_db_attach = print_record;
// Nb: because VG_(unique_error) does all the error processing
// immediately, and doesn't save the error, leakExtra can be
@@ -607,7 +625,7 @@
VG_(unique_error) ( tid, LeakErr, /*Addr*/0, /*s*/NULL,
/*extra*/&leak_extra,
/*where*/p_min->allocated_at, print_record,
- /*allow_GDB_attach*/False, /*count_error*/False );
+ allow_db_attach, /*count_error*/False );
if (is_suppressed) {
blocks_suppressed += p_min->num_blocks;
|