blob: e7ed39339de85cf31853af55855c1599a9df385f [file] [log] [blame]
njn43c799e2003-04-08 00:08:52 +00001
2/*--------------------------------------------------------------------*/
3/*--- The leak checker, shared between Memcheck and Addrcheck. ---*/
4/*--- mac_leakcheck.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
nethercote137bc552003-11-14 17:47:54 +00008 This file is part of MemCheck, a heavyweight Valgrind tool for
9 detecting memory errors, and AddrCheck, a lightweight Valgrind tool
njn43c799e2003-04-08 00:08:52 +000010 for detecting memory errors.
11
njn53612422005-03-12 16:22:54 +000012 Copyright (C) 2000-2005 Julian Seward
njn43c799e2003-04-08 00:08:52 +000013 jseward@acm.org
14
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation; either version 2 of the
18 License, or (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 02111-1307, USA.
29
30 The GNU General Public License is contained in the file COPYING.
31*/
32
sewardjb5f6f512005-03-10 23:59:00 +000033#include <setjmp.h>
njn43c799e2003-04-08 00:08:52 +000034#include "mac_shared.h"
njn97405b22005-06-02 03:39:33 +000035#include "pub_tool_libcbase.h"
njn43c799e2003-04-08 00:08:52 +000036
37/* Define to debug the memory-leak-detector. */
sewardjb5f6f512005-03-10 23:59:00 +000038#define VG_DEBUG_LEAKCHECK 0
39#define VG_DEBUG_CLIQUE 0
40
njn43c799e2003-04-08 00:08:52 +000041/*------------------------------------------------------------*/
42/*--- Low-level address-space scanning, for the leak ---*/
43/*--- detector. ---*/
44/*------------------------------------------------------------*/
45
46static
47jmp_buf memscan_jmpbuf;
48
49
50static
njn695c16e2005-03-27 03:40:28 +000051void scan_all_valid_memory_catcher ( Int sigNo, Addr addr )
njn43c799e2003-04-08 00:08:52 +000052{
sewardjb5f6f512005-03-10 23:59:00 +000053 if (0)
54 VG_(printf)("OUCH! sig=%d addr=%p\n", sigNo, addr);
55 if (sigNo == VKI_SIGSEGV || sigNo == VKI_SIGBUS)
56 __builtin_longjmp(memscan_jmpbuf, 1);
njn43c799e2003-04-08 00:08:52 +000057}
58
59/*------------------------------------------------------------*/
60/*--- Detecting leaked (unreachable) malloc'd blocks. ---*/
61/*------------------------------------------------------------*/
62
63/* A block is either
64 -- Proper-ly reached; a pointer to its start has been found
65 -- Interior-ly reached; only an interior pointer to it has been found
66 -- Unreached; so far, no pointers to any part of it have been found.
sewardjb5f6f512005-03-10 23:59:00 +000067 -- IndirectLeak; leaked, but referred to by another leaked block
njn43c799e2003-04-08 00:08:52 +000068*/
sewardjb5f6f512005-03-10 23:59:00 +000069typedef enum {
70 Unreached,
71 IndirectLeak,
72 Interior,
73 Proper
74 } Reachedness;
75
76/* An entry in the mark stack */
77typedef struct {
78 Int next:30; /* Index of next in mark stack */
79 UInt state:2; /* Reachedness */
80 SizeT indirect; /* if Unreached, how much is unreachable from here */
81} MarkStack;
njn43c799e2003-04-08 00:08:52 +000082
83/* A block record, used for generating err msgs. */
84typedef
85 struct _LossRecord {
86 struct _LossRecord* next;
87 /* Where these lost blocks were allocated. */
88 ExeContext* allocated_at;
89 /* Their reachability. */
90 Reachedness loss_mode;
91 /* Number of blocks and total # bytes involved. */
92 UInt total_bytes;
sewardjb5f6f512005-03-10 23:59:00 +000093 UInt indirect_bytes;
njn43c799e2003-04-08 00:08:52 +000094 UInt num_blocks;
95 }
96 LossRecord;
97
njn02977032005-05-17 04:00:11 +000098/* The 'extra' struct for leak errors. */
99typedef struct {
100 UInt n_this_record;
101 UInt n_total_records;
102 LossRecord* lossRecord;
103} LeakExtra;
njn43c799e2003-04-08 00:08:52 +0000104
105/* Find the i such that ptr points at or inside the block described by
106 shadows[i]. Return -1 if none found. This assumes that shadows[]
107 has been sorted on the ->data field. */
108
sewardjb5f6f512005-03-10 23:59:00 +0000109#if VG_DEBUG_LEAKCHECK
njn43c799e2003-04-08 00:08:52 +0000110/* Used to sanity-check the fast binary-search mechanism. */
111static
njn3e884182003-04-15 13:03:23 +0000112Int find_shadow_for_OLD ( Addr ptr,
113 MAC_Chunk** shadows,
114 Int n_shadows )
njn43c799e2003-04-08 00:08:52 +0000115
116{
117 Int i;
118 Addr a_lo, a_hi;
119 PROF_EVENT(70);
120 for (i = 0; i < n_shadows; i++) {
121 PROF_EVENT(71);
122 a_lo = shadows[i]->data;
sewardjb5f6f512005-03-10 23:59:00 +0000123 a_hi = ((Addr)shadows[i]->data) + shadows[i]->size;
njn43c799e2003-04-08 00:08:52 +0000124 if (a_lo <= ptr && ptr <= a_hi)
125 return i;
126 }
127 return -1;
128}
129#endif
130
131
132static
njn3e884182003-04-15 13:03:23 +0000133Int find_shadow_for ( Addr ptr,
134 MAC_Chunk** shadows,
135 Int n_shadows )
njn43c799e2003-04-08 00:08:52 +0000136{
137 Addr a_mid_lo, a_mid_hi;
138 Int lo, mid, hi, retVal;
139 /* VG_(printf)("find shadow for %p = ", ptr); */
140 retVal = -1;
141 lo = 0;
142 hi = n_shadows-1;
143 while (True) {
njn3e884182003-04-15 13:03:23 +0000144 /* invariant: current unsearched space is from lo to hi, inclusive. */
njn43c799e2003-04-08 00:08:52 +0000145 if (lo > hi) break; /* not found */
146
147 mid = (lo + hi) / 2;
njn3e884182003-04-15 13:03:23 +0000148 a_mid_lo = shadows[mid]->data;
sewardjb5f6f512005-03-10 23:59:00 +0000149 a_mid_hi = shadows[mid]->data + shadows[mid]->size;
njn43c799e2003-04-08 00:08:52 +0000150
151 if (ptr < a_mid_lo) {
152 hi = mid-1;
153 continue;
154 }
155 if (ptr > a_mid_hi) {
156 lo = mid+1;
157 continue;
158 }
sewardj76754cf2005-03-14 00:14:04 +0000159 tl_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
njn43c799e2003-04-08 00:08:52 +0000160 retVal = mid;
161 break;
162 }
163
sewardjb5f6f512005-03-10 23:59:00 +0000164# if VG_DEBUG_LEAKCHECK
sewardj76754cf2005-03-14 00:14:04 +0000165 tl_assert(retVal == find_shadow_for_OLD ( ptr, shadows, n_shadows ));
njn43c799e2003-04-08 00:08:52 +0000166# endif
167 /* VG_(printf)("%d\n", retVal); */
168 return retVal;
169}
170
171/* Globals, for the following callback used by VG_(detect_memory_leaks). */
njn3e884182003-04-15 13:03:23 +0000172static MAC_Chunk** lc_shadows;
173static Int lc_n_shadows;
sewardjb5f6f512005-03-10 23:59:00 +0000174static MarkStack* lc_markstack;
175static Int lc_markstack_top;
njn3e884182003-04-15 13:03:23 +0000176static Addr lc_min_mallocd_addr;
177static Addr lc_max_mallocd_addr;
sewardjb5f6f512005-03-10 23:59:00 +0000178static SizeT lc_scanned;
njn43c799e2003-04-08 00:08:52 +0000179
sewardj05fe85e2005-04-27 22:46:36 +0000180static Bool (*lc_is_within_valid_secondary) (Addr addr);
181static Bool (*lc_is_valid_aligned_word) (Addr addr);
sewardjb5f6f512005-03-10 23:59:00 +0000182
sewardj71bc3cb2005-05-19 00:25:45 +0000183static const HChar* str_lossmode ( Reachedness lossmode )
njn43c799e2003-04-08 00:08:52 +0000184{
sewardj71bc3cb2005-05-19 00:25:45 +0000185 const HChar *loss = "?";
186 switch (lossmode) {
187 case Unreached: loss = "definitely lost"; break;
188 case IndirectLeak: loss = "indirectly lost"; break;
189 case Interior: loss = "possibly lost"; break;
190 case Proper: loss = "still reachable"; break;
njn43c799e2003-04-08 00:08:52 +0000191 }
sewardjb5f6f512005-03-10 23:59:00 +0000192 return loss;
njn43c799e2003-04-08 00:08:52 +0000193}
194
sewardj71bc3cb2005-05-19 00:25:45 +0000195static const HChar* xml_kind ( Reachedness lossmode )
196{
197 const HChar *loss = "?";
198 switch (lossmode) {
199 case Unreached: loss = "Leak_DefinitelyLost"; break;
200 case IndirectLeak: loss = "Leak_IndirectlyLost"; break;
201 case Interior: loss = "Leak_PossiblyLost"; break;
202 case Proper: loss = "Leak_StillReachable"; break;
203 }
204 return loss;
205}
206
207
njn43c799e2003-04-08 00:08:52 +0000208/* Used for printing leak errors, avoids exposing the LossRecord type (which
209 comes in as void*, requiring a cast. */
njn02977032005-05-17 04:00:11 +0000210void MAC_(pp_LeakError)(void* vextra)
njn43c799e2003-04-08 00:08:52 +0000211{
sewardj71bc3cb2005-05-19 00:25:45 +0000212 HChar* xpre = VG_(clo_xml) ? " <what>" : "";
213 HChar* xpost = VG_(clo_xml) ? "</what>" : "";
214
njn02977032005-05-17 04:00:11 +0000215 LeakExtra* extra = (LeakExtra*)vextra;
216 LossRecord* l = extra->lossRecord;
217 const Char *loss = str_lossmode(l->loss_mode);
njn43c799e2003-04-08 00:08:52 +0000218
sewardj71bc3cb2005-05-19 00:25:45 +0000219 if (VG_(clo_xml)) {
220 VG_(message)(Vg_UserMsg, " <kind>%s</kind>", xml_kind(l->loss_mode));
221 } else {
222 VG_(message)(Vg_UserMsg, "");
223 }
224
sewardjb5f6f512005-03-10 23:59:00 +0000225 if (l->indirect_bytes) {
226 VG_(message)(Vg_UserMsg,
sewardj71bc3cb2005-05-19 00:25:45 +0000227 "%s%d (%d direct, %d indirect) bytes in %d blocks"
228 " are %s in loss record %d of %d%s",
229 xpre,
230 l->total_bytes + l->indirect_bytes,
231 l->total_bytes, l->indirect_bytes, l->num_blocks,
232 loss, extra->n_this_record, extra->n_total_records,
233 xpost
234 );
235 if (VG_(clo_xml)) {
236 VG_(message)(Vg_UserMsg, " <leakedbytes>%d</leakedbytes>",
237 l->total_bytes + l->indirect_bytes);
238 VG_(message)(Vg_UserMsg, " <leakedblocks>%d</leakedblocks>",
239 l->num_blocks);
240 }
sewardjb5f6f512005-03-10 23:59:00 +0000241 } else {
sewardj71bc3cb2005-05-19 00:25:45 +0000242 VG_(message)(
243 Vg_UserMsg,
244 "%s%d bytes in %d blocks are %s in loss record %d of %d%s",
245 xpre,
246 l->total_bytes, l->num_blocks,
247 loss, extra->n_this_record, extra->n_total_records,
248 xpost
249 );
250 if (VG_(clo_xml)) {
251 VG_(message)(Vg_UserMsg, " <leakedbytes>%d</leakedbytes>",
252 l->total_bytes);
253 VG_(message)(Vg_UserMsg, " <leakedblocks>%d</leakedblocks>",
254 l->num_blocks);
255 }
sewardjb5f6f512005-03-10 23:59:00 +0000256 }
njn43c799e2003-04-08 00:08:52 +0000257 VG_(pp_ExeContext)(l->allocated_at);
258}
259
njne8b5c052003-07-22 22:03:58 +0000260Int MAC_(bytes_leaked) = 0;
sewardjb5f6f512005-03-10 23:59:00 +0000261Int MAC_(bytes_indirect) = 0;
njne8b5c052003-07-22 22:03:58 +0000262Int MAC_(bytes_dubious) = 0;
263Int MAC_(bytes_reachable) = 0;
264Int MAC_(bytes_suppressed) = 0;
njn47363ab2003-04-21 13:24:40 +0000265
njn06072ec2003-09-30 15:35:13 +0000266static Int lc_compar(void* n1, void* n2)
267{
268 MAC_Chunk* mc1 = *(MAC_Chunk**)n1;
269 MAC_Chunk* mc2 = *(MAC_Chunk**)n2;
270 return (mc1->data < mc2->data ? -1 : 1);
271}
272
sewardjb5f6f512005-03-10 23:59:00 +0000273/* If ptr is pointing to a heap-allocated block which hasn't been seen
274 before, push it onto the mark stack. Clique is the index of the
275 clique leader; -1 if none. */
276static void _lc_markstack_push(Addr ptr, Int clique)
277{
278 Int sh_no;
279
280 if (!VG_(is_client_addr)(ptr)) /* quick filter */
281 return;
282
283 sh_no = find_shadow_for(ptr, lc_shadows, lc_n_shadows);
284
285 if (VG_DEBUG_LEAKCHECK)
286 VG_(printf)("ptr=%p -> block %d\n", ptr, sh_no);
287
288 if (sh_no == -1)
289 return;
290
sewardj76754cf2005-03-14 00:14:04 +0000291 tl_assert(sh_no >= 0 && sh_no < lc_n_shadows);
292 tl_assert(ptr <= lc_shadows[sh_no]->data + lc_shadows[sh_no]->size);
sewardjb5f6f512005-03-10 23:59:00 +0000293
294 if (lc_markstack[sh_no].state == Unreached) {
295 if (0)
296 VG_(printf)("pushing %p-%p\n", lc_shadows[sh_no]->data,
297 lc_shadows[sh_no]->data + lc_shadows[sh_no]->size);
298
sewardj76754cf2005-03-14 00:14:04 +0000299 tl_assert(lc_markstack[sh_no].next == -1);
sewardjb5f6f512005-03-10 23:59:00 +0000300 lc_markstack[sh_no].next = lc_markstack_top;
301 lc_markstack_top = sh_no;
302 }
303
304 if (clique != -1) {
305 if (0)
306 VG_(printf)("mopup: %d: %p is %d\n",
307 sh_no, lc_shadows[sh_no]->data, lc_markstack[sh_no].state);
308
309 /* An unmarked block - add it to the clique. Add its size to
310 the clique-leader's indirect size. If the new block was
311 itself a clique leader, it isn't any more, so add its
312 indirect to the new clique leader.
313
314 If this block *is* the clique leader, it means this is a
315 cyclic structure, so none of this applies. */
316 if (lc_markstack[sh_no].state == Unreached) {
317 lc_markstack[sh_no].state = IndirectLeak;
318
319 if (sh_no != clique) {
320 if (VG_DEBUG_CLIQUE) {
321 if (lc_markstack[sh_no].indirect)
322 VG_(printf)(" clique %d joining clique %d adding %d+%d bytes\n",
323 sh_no, clique,
324 lc_shadows[sh_no]->size, lc_markstack[sh_no].indirect);
325 else
326 VG_(printf)(" %d joining %d adding %d\n",
327 sh_no, clique, lc_shadows[sh_no]->size);
328 }
329
330 lc_markstack[clique].indirect += lc_shadows[sh_no]->size;
331 lc_markstack[clique].indirect += lc_markstack[sh_no].indirect;
332 lc_markstack[sh_no].indirect = 0; /* shouldn't matter */
333 }
334 }
335 } else if (ptr == lc_shadows[sh_no]->data) {
336 lc_markstack[sh_no].state = Proper;
337 } else {
338 if (lc_markstack[sh_no].state == Unreached)
339 lc_markstack[sh_no].state = Interior;
340 }
341}
342
343static void lc_markstack_push(Addr ptr)
344{
345 _lc_markstack_push(ptr, -1);
346}
347
348/* Return the top of the mark stack, if any. */
349static Int lc_markstack_pop(void)
350{
351 Int ret = lc_markstack_top;
352
353 if (ret != -1) {
354 lc_markstack_top = lc_markstack[ret].next;
355 lc_markstack[ret].next = -1;
356 }
357
358 return ret;
359}
360
sewardj45d94cc2005-04-20 14:44:11 +0000361
sewardjb5f6f512005-03-10 23:59:00 +0000362/* Scan a block of memory between [start, start+len). This range may
363 be bogus, inaccessable, or otherwise strange; we deal with it.
364
365 If clique != -1, it means we're gathering leaked memory into
366 cliques, and clique is the index of the current clique leader. */
367static void _lc_scan_memory(Addr start, SizeT len, Int clique)
368{
njn13bfd852005-06-02 03:52:53 +0000369 Addr ptr = VG_ROUNDUP(start, sizeof(Addr));
370 Addr end = VG_ROUNDDN(start+len, sizeof(Addr));
sewardjb5f6f512005-03-10 23:59:00 +0000371 vki_sigset_t sigmask;
372
373 if (VG_DEBUG_LEAKCHECK)
374 VG_(printf)("scan %p-%p\n", start, len);
375 VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &sigmask);
njn695c16e2005-03-27 03:40:28 +0000376 VG_(set_fault_catcher)(scan_all_valid_memory_catcher);
sewardjb5f6f512005-03-10 23:59:00 +0000377
378 lc_scanned += end-ptr;
379
380 if (!VG_(is_client_addr)(ptr) ||
381 !VG_(is_addressable)(ptr, sizeof(Addr), VKI_PROT_READ))
njn13bfd852005-06-02 03:52:53 +0000382 ptr = VG_PGROUNDUP(ptr+1); /* first page bad */
sewardjb5f6f512005-03-10 23:59:00 +0000383
sewardj05fe85e2005-04-27 22:46:36 +0000384 while (ptr < end) {
sewardjb5f6f512005-03-10 23:59:00 +0000385 Addr addr;
386
387 /* Skip invalid chunks */
sewardj05fe85e2005-04-27 22:46:36 +0000388 if (!(*lc_is_within_valid_secondary)(ptr)) {
njn13bfd852005-06-02 03:52:53 +0000389 ptr = VG_ROUNDUP(ptr+1, SECONDARY_SIZE);
sewardjb5f6f512005-03-10 23:59:00 +0000390 continue;
391 }
392
393 /* Look to see if this page seems reasonble */
394 if ((ptr % VKI_PAGE_SIZE) == 0) {
395 if (!VG_(is_client_addr)(ptr) ||
396 !VG_(is_addressable)(ptr, sizeof(Addr), VKI_PROT_READ))
397 ptr += VKI_PAGE_SIZE; /* bad page - skip it */
398 }
399
400 if (__builtin_setjmp(memscan_jmpbuf) == 0) {
sewardj05fe85e2005-04-27 22:46:36 +0000401 if ((*lc_is_valid_aligned_word)(ptr)) {
sewardjb5f6f512005-03-10 23:59:00 +0000402 addr = *(Addr *)ptr;
403 _lc_markstack_push(addr, clique);
404 } else if (0 && VG_DEBUG_LEAKCHECK)
405 VG_(printf)("%p not valid\n", ptr);
406 ptr += sizeof(Addr);
407 } else {
408 /* We need to restore the signal mask, because we were
409 longjmped out of a signal handler. */
410 VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL);
411
njn13bfd852005-06-02 03:52:53 +0000412 ptr = VG_PGROUNDUP(ptr+1); /* bad page - skip it */
sewardjb5f6f512005-03-10 23:59:00 +0000413 }
414 }
415
416 VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL);
417 VG_(set_fault_catcher)(NULL);
418}
419
sewardj45d94cc2005-04-20 14:44:11 +0000420
sewardjb5f6f512005-03-10 23:59:00 +0000421static void lc_scan_memory(Addr start, SizeT len)
422{
423 _lc_scan_memory(start, len, -1);
424}
425
426/* Process the mark stack until empty. If mopup is true, then we're
427 actually gathering leaked blocks, so they should be marked
428 IndirectLeak. */
429static void lc_do_leakcheck(Int clique)
430{
431 Int top;
432
433 while((top = lc_markstack_pop()) != -1) {
sewardj76754cf2005-03-14 00:14:04 +0000434 tl_assert(top >= 0 && top < lc_n_shadows);
435 tl_assert(lc_markstack[top].state != Unreached);
sewardjb5f6f512005-03-10 23:59:00 +0000436
437 _lc_scan_memory(lc_shadows[top]->data, lc_shadows[top]->size, clique);
438 }
439}
440
441static Int blocks_leaked;
442static Int blocks_indirect;
443static Int blocks_dubious;
444static Int blocks_reachable;
445static Int blocks_suppressed;
446
njnb8dca862005-03-14 02:42:44 +0000447static void full_report(ThreadId tid)
sewardjb5f6f512005-03-10 23:59:00 +0000448{
449 Int i;
450 Int n_lossrecords;
451 LossRecord* errlist;
452 LossRecord* p;
453 Bool is_suppressed;
njn02977032005-05-17 04:00:11 +0000454 LeakExtra leak_extra;
sewardjb5f6f512005-03-10 23:59:00 +0000455
456 /* Go through and group lost structures into cliques. For each
457 Unreached block, push it onto the mark stack, and find all the
458 blocks linked to it. These are marked IndirectLeak, and their
459 size is added to the clique leader's indirect size. If one of
460 the found blocks was itself a clique leader (from a previous
461 pass), then the cliques are merged. */
462 for (i = 0; i < lc_n_shadows; i++) {
463 if (VG_DEBUG_CLIQUE)
464 VG_(printf)("cliques: %d at %p -> %s\n",
njn02977032005-05-17 04:00:11 +0000465 i, lc_shadows[i]->data, str_lossmode(lc_markstack[i].state));
sewardjb5f6f512005-03-10 23:59:00 +0000466 if (lc_markstack[i].state != Unreached)
467 continue;
468
sewardj76754cf2005-03-14 00:14:04 +0000469 tl_assert(lc_markstack_top == -1);
sewardjb5f6f512005-03-10 23:59:00 +0000470
471 if (VG_DEBUG_CLIQUE)
472 VG_(printf)("%d: gathering clique %p\n", i, lc_shadows[i]->data);
473
474 _lc_markstack_push(lc_shadows[i]->data, i);
475
476 lc_do_leakcheck(i);
477
sewardj76754cf2005-03-14 00:14:04 +0000478 tl_assert(lc_markstack_top == -1);
479 tl_assert(lc_markstack[i].state == IndirectLeak);
sewardjb5f6f512005-03-10 23:59:00 +0000480
481 lc_markstack[i].state = Unreached; /* Return to unreached state,
482 to indicate its a clique
483 leader */
484 }
485
486 /* Common up the lost blocks so we can print sensible error messages. */
487 n_lossrecords = 0;
488 errlist = NULL;
489 for (i = 0; i < lc_n_shadows; i++) {
490 ExeContext* where = lc_shadows[i]->where;
491
492 for (p = errlist; p != NULL; p = p->next) {
493 if (p->loss_mode == lc_markstack[i].state
494 && VG_(eq_ExeContext) ( MAC_(clo_leak_resolution),
495 p->allocated_at,
496 where) ) {
497 break;
498 }
499 }
500 if (p != NULL) {
501 p->num_blocks ++;
502 p->total_bytes += lc_shadows[i]->size;
503 p->indirect_bytes += lc_markstack[i].indirect;
504 } else {
505 n_lossrecords ++;
506 p = VG_(malloc)(sizeof(LossRecord));
507 p->loss_mode = lc_markstack[i].state;
508 p->allocated_at = where;
509 p->total_bytes = lc_shadows[i]->size;
510 p->indirect_bytes = lc_markstack[i].indirect;
511 p->num_blocks = 1;
512 p->next = errlist;
513 errlist = p;
514 }
515 }
516
517 /* Print out the commoned-up blocks and collect summary stats. */
518 for (i = 0; i < n_lossrecords; i++) {
519 Bool print_record;
520 LossRecord* p_min = NULL;
521 UInt n_min = 0xFFFFFFFF;
522 for (p = errlist; p != NULL; p = p->next) {
523 if (p->num_blocks > 0 && p->total_bytes < n_min) {
524 n_min = p->total_bytes + p->indirect_bytes;
525 p_min = p;
526 }
527 }
sewardj76754cf2005-03-14 00:14:04 +0000528 tl_assert(p_min != NULL);
sewardjb5f6f512005-03-10 23:59:00 +0000529
530 /* Ok to have tst==NULL; it's only used if --gdb-attach=yes, and
531 we disallow that when --leak-check=yes.
532
njn02977032005-05-17 04:00:11 +0000533 Prints the error if not suppressed, unless it's reachable (Proper
534 or IndirectLeak) and --show-reachable=no */
sewardjb5f6f512005-03-10 23:59:00 +0000535
536 print_record = ( MAC_(clo_show_reachable) ||
njn02977032005-05-17 04:00:11 +0000537 Unreached == p_min->loss_mode ||
538 Interior == p_min->loss_mode );
539
540 // Nb: because VG_(unique_error) does all the error processing
541 // immediately, and doesn't save the error, leakExtra can be
542 // stack-allocated.
543 leak_extra.n_this_record = i+1;
544 leak_extra.n_total_records = n_lossrecords;
545 leak_extra.lossRecord = p_min;
sewardjb5f6f512005-03-10 23:59:00 +0000546 is_suppressed =
njn02977032005-05-17 04:00:11 +0000547 VG_(unique_error) ( tid, LeakErr, /*Addr*/0, /*s*/NULL,
548 /*extra*/&leak_extra,
549 /*where*/p_min->allocated_at, print_record,
sewardjb5f6f512005-03-10 23:59:00 +0000550 /*allow_GDB_attach*/False, /*count_error*/False );
551
552 if (is_suppressed) {
553 blocks_suppressed += p_min->num_blocks;
554 MAC_(bytes_suppressed) += p_min->total_bytes;
555
556 } else if (Unreached == p_min->loss_mode) {
557 blocks_leaked += p_min->num_blocks;
558 MAC_(bytes_leaked) += p_min->total_bytes;
559
560 } else if (IndirectLeak == p_min->loss_mode) {
561 blocks_indirect += p_min->num_blocks;
562 MAC_(bytes_indirect)+= p_min->total_bytes;
563
564 } else if (Interior == p_min->loss_mode) {
565 blocks_dubious += p_min->num_blocks;
566 MAC_(bytes_dubious) += p_min->total_bytes;
567
568 } else if (Proper == p_min->loss_mode) {
569 blocks_reachable += p_min->num_blocks;
570 MAC_(bytes_reachable) += p_min->total_bytes;
571
572 } else {
sewardj76754cf2005-03-14 00:14:04 +0000573 VG_(tool_panic)("generic_detect_memory_leaks: unknown loss mode");
sewardjb5f6f512005-03-10 23:59:00 +0000574 }
575 p_min->num_blocks = 0;
576 }
577}
578
579/* Compute a quick summary of the leak check. */
580static void make_summary()
581{
582 Int i;
583
584 for(i = 0; i < lc_n_shadows; i++) {
585 SizeT size = lc_shadows[i]->size;
586
587 switch(lc_markstack[i].state) {
588 case Unreached:
589 blocks_leaked++;
590 MAC_(bytes_leaked) += size;
591 break;
592
593 case Proper:
594 blocks_reachable++;
595 MAC_(bytes_reachable) += size;
596 break;
597
598 case Interior:
599 blocks_dubious++;
600 MAC_(bytes_dubious) += size;
601 break;
602
603 case IndirectLeak: /* shouldn't happen */
604 blocks_indirect++;
605 MAC_(bytes_indirect) += size;
606 break;
607 }
608 }
609}
610
njn43c799e2003-04-08 00:08:52 +0000611/* Top level entry point to leak detector. Call here, passing in
612 suitable address-validating functions (see comment at top of
njn695c16e2005-03-27 03:40:28 +0000613 scan_all_valid_memory above). All this is to avoid duplication
nethercote996901a2004-08-03 13:29:09 +0000614 of the leak-detection code for Memcheck and Addrcheck.
615 Also pass in a tool-specific function to extract the .where field
njn43c799e2003-04-08 00:08:52 +0000616 for allocated blocks, an indication of the resolution wanted for
617 distinguishing different allocation points, and whether or not
618 reachable blocks should be shown.
619*/
620void MAC_(do_detect_memory_leaks) (
njnb8dca862005-03-14 02:42:44 +0000621 ThreadId tid, LeakCheckMode mode,
sewardj05fe85e2005-04-27 22:46:36 +0000622 Bool (*is_within_valid_secondary) ( Addr ),
623 Bool (*is_valid_aligned_word) ( Addr )
njn43c799e2003-04-08 00:08:52 +0000624)
625{
njnb8dca862005-03-14 02:42:44 +0000626 Int i;
njn43c799e2003-04-08 00:08:52 +0000627
sewardj76754cf2005-03-14 00:14:04 +0000628 tl_assert(mode != LC_Off);
njn43c799e2003-04-08 00:08:52 +0000629
njn06072ec2003-09-30 15:35:13 +0000630 /* VG_(HT_to_array) allocates storage for shadows */
631 lc_shadows = (MAC_Chunk**)VG_(HT_to_array)( MAC_(malloc_list),
632 &lc_n_shadows );
633
634 /* Sort the array. */
635 VG_(ssort)((void*)lc_shadows, lc_n_shadows, sizeof(VgHashNode*), lc_compar);
636
637 /* Sanity check; assert that the blocks are now in order */
638 for (i = 0; i < lc_n_shadows-1; i++) {
sewardj76754cf2005-03-14 00:14:04 +0000639 tl_assert( lc_shadows[i]->data <= lc_shadows[i+1]->data);
njn06072ec2003-09-30 15:35:13 +0000640 }
njn3e884182003-04-15 13:03:23 +0000641
642 /* Sanity check -- make sure they don't overlap */
643 for (i = 0; i < lc_n_shadows-1; i++) {
sewardj76754cf2005-03-14 00:14:04 +0000644 tl_assert( lc_shadows[i]->data + lc_shadows[i]->size
njn3e884182003-04-15 13:03:23 +0000645 < lc_shadows[i+1]->data );
646 }
647
648 if (lc_n_shadows == 0) {
sewardj76754cf2005-03-14 00:14:04 +0000649 tl_assert(lc_shadows == NULL);
sewardj71bc3cb2005-05-19 00:25:45 +0000650 if (VG_(clo_verbosity) >= 1 && !VG_(clo_xml)) {
sewardj37d06f22003-09-17 21:48:26 +0000651 VG_(message)(Vg_UserMsg,
652 "No malloc'd blocks -- no leaks are possible.");
653 }
njn43c799e2003-04-08 00:08:52 +0000654 return;
655 }
656
sewardj71bc3cb2005-05-19 00:25:45 +0000657 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
nethercote0f19bce2003-12-02 10:17:44 +0000658 VG_(message)(Vg_UserMsg,
659 "searching for pointers to %d not-freed blocks.",
660 lc_n_shadows );
njn43c799e2003-04-08 00:08:52 +0000661
njn3e884182003-04-15 13:03:23 +0000662 lc_min_mallocd_addr = lc_shadows[0]->data;
663 lc_max_mallocd_addr = lc_shadows[lc_n_shadows-1]->data
sewardjb5f6f512005-03-10 23:59:00 +0000664 + lc_shadows[lc_n_shadows-1]->size;
njn43c799e2003-04-08 00:08:52 +0000665
sewardjb5f6f512005-03-10 23:59:00 +0000666 lc_markstack = VG_(malloc)( lc_n_shadows * sizeof(*lc_markstack) );
667 for (i = 0; i < lc_n_shadows; i++) {
668 lc_markstack[i].next = -1;
669 lc_markstack[i].state = Unreached;
670 lc_markstack[i].indirect = 0;
671 }
672 lc_markstack_top = -1;
njn43c799e2003-04-08 00:08:52 +0000673
sewardj05fe85e2005-04-27 22:46:36 +0000674 lc_is_within_valid_secondary = is_within_valid_secondary;
675 lc_is_valid_aligned_word = is_valid_aligned_word;
sewardjb5f6f512005-03-10 23:59:00 +0000676
677 lc_scanned = 0;
678
679 /* Do the scan of memory, pushing any pointers onto the mark stack */
680 VG_(find_root_memory)(lc_scan_memory);
681
682 /* Push registers onto mark stack */
683 VG_(mark_from_registers)(lc_markstack_push);
684
685 /* Keep walking the heap until everything is found */
686 lc_do_leakcheck(-1);
njn43c799e2003-04-08 00:08:52 +0000687
sewardj71bc3cb2005-05-19 00:25:45 +0000688 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
sewardjb5f6f512005-03-10 23:59:00 +0000689 VG_(message)(Vg_UserMsg, "checked %d bytes.", lc_scanned);
njn43c799e2003-04-08 00:08:52 +0000690
njne8b5c052003-07-22 22:03:58 +0000691 blocks_leaked = MAC_(bytes_leaked) = 0;
sewardjb5f6f512005-03-10 23:59:00 +0000692 blocks_indirect = MAC_(bytes_indirect) = 0;
njne8b5c052003-07-22 22:03:58 +0000693 blocks_dubious = MAC_(bytes_dubious) = 0;
694 blocks_reachable = MAC_(bytes_reachable) = 0;
695 blocks_suppressed = MAC_(bytes_suppressed) = 0;
njn43c799e2003-04-08 00:08:52 +0000696
sewardjb5f6f512005-03-10 23:59:00 +0000697 if (mode == LC_Full)
njnb8dca862005-03-14 02:42:44 +0000698 full_report(tid);
sewardjb5f6f512005-03-10 23:59:00 +0000699 else
700 make_summary();
njn43c799e2003-04-08 00:08:52 +0000701
sewardj71bc3cb2005-05-19 00:25:45 +0000702 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) {
nethercote0f19bce2003-12-02 10:17:44 +0000703 VG_(message)(Vg_UserMsg, "");
704 VG_(message)(Vg_UserMsg, "LEAK SUMMARY:");
705 VG_(message)(Vg_UserMsg, " definitely lost: %d bytes in %d blocks.",
706 MAC_(bytes_leaked), blocks_leaked );
sewardjb5f6f512005-03-10 23:59:00 +0000707 if (blocks_indirect > 0)
708 VG_(message)(Vg_UserMsg, " indirectly lost: %d bytes in %d blocks.",
709 MAC_(bytes_indirect), blocks_indirect );
710 VG_(message)(Vg_UserMsg, " possibly lost: %d bytes in %d blocks.",
nethercote0f19bce2003-12-02 10:17:44 +0000711 MAC_(bytes_dubious), blocks_dubious );
712 VG_(message)(Vg_UserMsg, " still reachable: %d bytes in %d blocks.",
713 MAC_(bytes_reachable), blocks_reachable );
714 VG_(message)(Vg_UserMsg, " suppressed: %d bytes in %d blocks.",
715 MAC_(bytes_suppressed), blocks_suppressed );
njn6a329422005-03-12 20:38:13 +0000716 if (mode == LC_Summary && blocks_leaked > 0)
sewardjb5f6f512005-03-10 23:59:00 +0000717 VG_(message)(Vg_UserMsg,
718 "Use --leak-check=full to see details of leaked memory.");
719 else if (!MAC_(clo_show_reachable)) {
nethercote0f19bce2003-12-02 10:17:44 +0000720 VG_(message)(Vg_UserMsg,
721 "Reachable blocks (those to which a pointer was found) are not shown.");
722 VG_(message)(Vg_UserMsg,
723 "To see them, rerun with: --show-reachable=yes");
724 }
njn43c799e2003-04-08 00:08:52 +0000725 }
njn43c799e2003-04-08 00:08:52 +0000726
njn3e884182003-04-15 13:03:23 +0000727 VG_(free) ( lc_shadows );
sewardjb5f6f512005-03-10 23:59:00 +0000728 VG_(free) ( lc_markstack );
njn43c799e2003-04-08 00:08:52 +0000729}
730
731/*--------------------------------------------------------------------*/
732/*--- end mac_leakcheck.c ---*/
733/*--------------------------------------------------------------------*/
734