blob: 38e6d49ddfbbe2c3962935f413678d03db0359e4 [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"
35
36/* Define to debug the memory-leak-detector. */
sewardjb5f6f512005-03-10 23:59:00 +000037#define VG_DEBUG_LEAKCHECK 0
38#define VG_DEBUG_CLIQUE 0
39
40#define ROUNDDN(p, a) ((Addr)(p) & ~((a)-1))
41#define ROUNDUP(p, a) ROUNDDN((p)+(a)-1, (a))
42#define PGROUNDDN(p) ROUNDDN(p, VKI_PAGE_SIZE)
43#define PGROUNDUP(p) ROUNDUP(p, VKI_PAGE_SIZE)
njn43c799e2003-04-08 00:08:52 +000044
45/*------------------------------------------------------------*/
46/*--- Low-level address-space scanning, for the leak ---*/
47/*--- detector. ---*/
48/*------------------------------------------------------------*/
49
50static
51jmp_buf memscan_jmpbuf;
52
53
54static
njn695c16e2005-03-27 03:40:28 +000055void scan_all_valid_memory_catcher ( Int sigNo, Addr addr )
njn43c799e2003-04-08 00:08:52 +000056{
sewardjb5f6f512005-03-10 23:59:00 +000057 if (0)
58 VG_(printf)("OUCH! sig=%d addr=%p\n", sigNo, addr);
59 if (sigNo == VKI_SIGSEGV || sigNo == VKI_SIGBUS)
60 __builtin_longjmp(memscan_jmpbuf, 1);
njn43c799e2003-04-08 00:08:52 +000061}
62
63/*------------------------------------------------------------*/
64/*--- Detecting leaked (unreachable) malloc'd blocks. ---*/
65/*------------------------------------------------------------*/
66
67/* A block is either
68 -- Proper-ly reached; a pointer to its start has been found
69 -- Interior-ly reached; only an interior pointer to it has been found
70 -- Unreached; so far, no pointers to any part of it have been found.
sewardjb5f6f512005-03-10 23:59:00 +000071 -- IndirectLeak; leaked, but referred to by another leaked block
njn43c799e2003-04-08 00:08:52 +000072*/
sewardjb5f6f512005-03-10 23:59:00 +000073typedef enum {
74 Unreached,
75 IndirectLeak,
76 Interior,
77 Proper
78 } Reachedness;
79
80/* An entry in the mark stack */
81typedef struct {
82 Int next:30; /* Index of next in mark stack */
83 UInt state:2; /* Reachedness */
84 SizeT indirect; /* if Unreached, how much is unreachable from here */
85} MarkStack;
njn43c799e2003-04-08 00:08:52 +000086
87/* A block record, used for generating err msgs. */
88typedef
89 struct _LossRecord {
90 struct _LossRecord* next;
91 /* Where these lost blocks were allocated. */
92 ExeContext* allocated_at;
93 /* Their reachability. */
94 Reachedness loss_mode;
95 /* Number of blocks and total # bytes involved. */
96 UInt total_bytes;
sewardjb5f6f512005-03-10 23:59:00 +000097 UInt indirect_bytes;
njn43c799e2003-04-08 00:08:52 +000098 UInt num_blocks;
99 }
100 LossRecord;
101
njn02977032005-05-17 04:00:11 +0000102/* The 'extra' struct for leak errors. */
103typedef struct {
104 UInt n_this_record;
105 UInt n_total_records;
106 LossRecord* lossRecord;
107} LeakExtra;
njn43c799e2003-04-08 00:08:52 +0000108
109/* Find the i such that ptr points at or inside the block described by
110 shadows[i]. Return -1 if none found. This assumes that shadows[]
111 has been sorted on the ->data field. */
112
sewardjb5f6f512005-03-10 23:59:00 +0000113#if VG_DEBUG_LEAKCHECK
njn43c799e2003-04-08 00:08:52 +0000114/* Used to sanity-check the fast binary-search mechanism. */
115static
njn3e884182003-04-15 13:03:23 +0000116Int find_shadow_for_OLD ( Addr ptr,
117 MAC_Chunk** shadows,
118 Int n_shadows )
njn43c799e2003-04-08 00:08:52 +0000119
120{
121 Int i;
122 Addr a_lo, a_hi;
123 PROF_EVENT(70);
124 for (i = 0; i < n_shadows; i++) {
125 PROF_EVENT(71);
126 a_lo = shadows[i]->data;
sewardjb5f6f512005-03-10 23:59:00 +0000127 a_hi = ((Addr)shadows[i]->data) + shadows[i]->size;
njn43c799e2003-04-08 00:08:52 +0000128 if (a_lo <= ptr && ptr <= a_hi)
129 return i;
130 }
131 return -1;
132}
133#endif
134
135
136static
njn3e884182003-04-15 13:03:23 +0000137Int find_shadow_for ( Addr ptr,
138 MAC_Chunk** shadows,
139 Int n_shadows )
njn43c799e2003-04-08 00:08:52 +0000140{
141 Addr a_mid_lo, a_mid_hi;
142 Int lo, mid, hi, retVal;
143 /* VG_(printf)("find shadow for %p = ", ptr); */
144 retVal = -1;
145 lo = 0;
146 hi = n_shadows-1;
147 while (True) {
njn3e884182003-04-15 13:03:23 +0000148 /* invariant: current unsearched space is from lo to hi, inclusive. */
njn43c799e2003-04-08 00:08:52 +0000149 if (lo > hi) break; /* not found */
150
151 mid = (lo + hi) / 2;
njn3e884182003-04-15 13:03:23 +0000152 a_mid_lo = shadows[mid]->data;
sewardjb5f6f512005-03-10 23:59:00 +0000153 a_mid_hi = shadows[mid]->data + shadows[mid]->size;
njn43c799e2003-04-08 00:08:52 +0000154
155 if (ptr < a_mid_lo) {
156 hi = mid-1;
157 continue;
158 }
159 if (ptr > a_mid_hi) {
160 lo = mid+1;
161 continue;
162 }
sewardj76754cf2005-03-14 00:14:04 +0000163 tl_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
njn43c799e2003-04-08 00:08:52 +0000164 retVal = mid;
165 break;
166 }
167
sewardjb5f6f512005-03-10 23:59:00 +0000168# if VG_DEBUG_LEAKCHECK
sewardj76754cf2005-03-14 00:14:04 +0000169 tl_assert(retVal == find_shadow_for_OLD ( ptr, shadows, n_shadows ));
njn43c799e2003-04-08 00:08:52 +0000170# endif
171 /* VG_(printf)("%d\n", retVal); */
172 return retVal;
173}
174
175/* Globals, for the following callback used by VG_(detect_memory_leaks). */
njn3e884182003-04-15 13:03:23 +0000176static MAC_Chunk** lc_shadows;
177static Int lc_n_shadows;
sewardjb5f6f512005-03-10 23:59:00 +0000178static MarkStack* lc_markstack;
179static Int lc_markstack_top;
njn3e884182003-04-15 13:03:23 +0000180static Addr lc_min_mallocd_addr;
181static Addr lc_max_mallocd_addr;
sewardjb5f6f512005-03-10 23:59:00 +0000182static SizeT lc_scanned;
njn43c799e2003-04-08 00:08:52 +0000183
sewardj05fe85e2005-04-27 22:46:36 +0000184static Bool (*lc_is_within_valid_secondary) (Addr addr);
185static Bool (*lc_is_valid_aligned_word) (Addr addr);
sewardjb5f6f512005-03-10 23:59:00 +0000186
njn02977032005-05-17 04:00:11 +0000187static const Char *str_lossmode(Reachedness lossmode)
njn43c799e2003-04-08 00:08:52 +0000188{
sewardjb5f6f512005-03-10 23:59:00 +0000189 const Char *loss = "?";
njn43c799e2003-04-08 00:08:52 +0000190
sewardjb5f6f512005-03-10 23:59:00 +0000191 switch(lossmode) {
192 case Unreached: loss = "definitely lost"; break;
193 case IndirectLeak: loss = "indirectly lost"; break;
194 case Interior: loss = "possibly lost"; break;
195 case Proper: loss = "still reachable"; break;
njn43c799e2003-04-08 00:08:52 +0000196 }
sewardjb5f6f512005-03-10 23:59:00 +0000197
198 return loss;
njn43c799e2003-04-08 00:08:52 +0000199}
200
201/* Used for printing leak errors, avoids exposing the LossRecord type (which
202 comes in as void*, requiring a cast. */
njn02977032005-05-17 04:00:11 +0000203void MAC_(pp_LeakError)(void* vextra)
njn43c799e2003-04-08 00:08:52 +0000204{
njn02977032005-05-17 04:00:11 +0000205 LeakExtra* extra = (LeakExtra*)vextra;
206 LossRecord* l = extra->lossRecord;
207 const Char *loss = str_lossmode(l->loss_mode);
njn43c799e2003-04-08 00:08:52 +0000208
209 VG_(message)(Vg_UserMsg, "");
sewardjb5f6f512005-03-10 23:59:00 +0000210 if (l->indirect_bytes) {
211 VG_(message)(Vg_UserMsg,
212 "%d (%d direct, %d indirect) bytes in %d blocks are %s in loss record %d of %d",
213 l->total_bytes + l->indirect_bytes,
214 l->total_bytes, l->indirect_bytes, l->num_blocks,
njn02977032005-05-17 04:00:11 +0000215 loss, extra->n_this_record, extra->n_total_records);
sewardjb5f6f512005-03-10 23:59:00 +0000216 } else {
217 VG_(message)(Vg_UserMsg,
218 "%d bytes in %d blocks are %s in loss record %d of %d",
219 l->total_bytes, l->num_blocks,
njn02977032005-05-17 04:00:11 +0000220 loss, extra->n_this_record, extra->n_total_records);
sewardjb5f6f512005-03-10 23:59:00 +0000221 }
njn43c799e2003-04-08 00:08:52 +0000222 VG_(pp_ExeContext)(l->allocated_at);
223}
224
njne8b5c052003-07-22 22:03:58 +0000225Int MAC_(bytes_leaked) = 0;
sewardjb5f6f512005-03-10 23:59:00 +0000226Int MAC_(bytes_indirect) = 0;
njne8b5c052003-07-22 22:03:58 +0000227Int MAC_(bytes_dubious) = 0;
228Int MAC_(bytes_reachable) = 0;
229Int MAC_(bytes_suppressed) = 0;
njn47363ab2003-04-21 13:24:40 +0000230
njn06072ec2003-09-30 15:35:13 +0000231static Int lc_compar(void* n1, void* n2)
232{
233 MAC_Chunk* mc1 = *(MAC_Chunk**)n1;
234 MAC_Chunk* mc2 = *(MAC_Chunk**)n2;
235 return (mc1->data < mc2->data ? -1 : 1);
236}
237
sewardjb5f6f512005-03-10 23:59:00 +0000238/* If ptr is pointing to a heap-allocated block which hasn't been seen
239 before, push it onto the mark stack. Clique is the index of the
240 clique leader; -1 if none. */
241static void _lc_markstack_push(Addr ptr, Int clique)
242{
243 Int sh_no;
244
245 if (!VG_(is_client_addr)(ptr)) /* quick filter */
246 return;
247
248 sh_no = find_shadow_for(ptr, lc_shadows, lc_n_shadows);
249
250 if (VG_DEBUG_LEAKCHECK)
251 VG_(printf)("ptr=%p -> block %d\n", ptr, sh_no);
252
253 if (sh_no == -1)
254 return;
255
sewardj76754cf2005-03-14 00:14:04 +0000256 tl_assert(sh_no >= 0 && sh_no < lc_n_shadows);
257 tl_assert(ptr <= lc_shadows[sh_no]->data + lc_shadows[sh_no]->size);
sewardjb5f6f512005-03-10 23:59:00 +0000258
259 if (lc_markstack[sh_no].state == Unreached) {
260 if (0)
261 VG_(printf)("pushing %p-%p\n", lc_shadows[sh_no]->data,
262 lc_shadows[sh_no]->data + lc_shadows[sh_no]->size);
263
sewardj76754cf2005-03-14 00:14:04 +0000264 tl_assert(lc_markstack[sh_no].next == -1);
sewardjb5f6f512005-03-10 23:59:00 +0000265 lc_markstack[sh_no].next = lc_markstack_top;
266 lc_markstack_top = sh_no;
267 }
268
269 if (clique != -1) {
270 if (0)
271 VG_(printf)("mopup: %d: %p is %d\n",
272 sh_no, lc_shadows[sh_no]->data, lc_markstack[sh_no].state);
273
274 /* An unmarked block - add it to the clique. Add its size to
275 the clique-leader's indirect size. If the new block was
276 itself a clique leader, it isn't any more, so add its
277 indirect to the new clique leader.
278
279 If this block *is* the clique leader, it means this is a
280 cyclic structure, so none of this applies. */
281 if (lc_markstack[sh_no].state == Unreached) {
282 lc_markstack[sh_no].state = IndirectLeak;
283
284 if (sh_no != clique) {
285 if (VG_DEBUG_CLIQUE) {
286 if (lc_markstack[sh_no].indirect)
287 VG_(printf)(" clique %d joining clique %d adding %d+%d bytes\n",
288 sh_no, clique,
289 lc_shadows[sh_no]->size, lc_markstack[sh_no].indirect);
290 else
291 VG_(printf)(" %d joining %d adding %d\n",
292 sh_no, clique, lc_shadows[sh_no]->size);
293 }
294
295 lc_markstack[clique].indirect += lc_shadows[sh_no]->size;
296 lc_markstack[clique].indirect += lc_markstack[sh_no].indirect;
297 lc_markstack[sh_no].indirect = 0; /* shouldn't matter */
298 }
299 }
300 } else if (ptr == lc_shadows[sh_no]->data) {
301 lc_markstack[sh_no].state = Proper;
302 } else {
303 if (lc_markstack[sh_no].state == Unreached)
304 lc_markstack[sh_no].state = Interior;
305 }
306}
307
308static void lc_markstack_push(Addr ptr)
309{
310 _lc_markstack_push(ptr, -1);
311}
312
313/* Return the top of the mark stack, if any. */
314static Int lc_markstack_pop(void)
315{
316 Int ret = lc_markstack_top;
317
318 if (ret != -1) {
319 lc_markstack_top = lc_markstack[ret].next;
320 lc_markstack[ret].next = -1;
321 }
322
323 return ret;
324}
325
sewardj45d94cc2005-04-20 14:44:11 +0000326
sewardjb5f6f512005-03-10 23:59:00 +0000327/* Scan a block of memory between [start, start+len). This range may
328 be bogus, inaccessable, or otherwise strange; we deal with it.
329
330 If clique != -1, it means we're gathering leaked memory into
331 cliques, and clique is the index of the current clique leader. */
332static void _lc_scan_memory(Addr start, SizeT len, Int clique)
333{
334 Addr ptr = ROUNDUP(start, sizeof(Addr));
335 Addr end = ROUNDDN(start+len, sizeof(Addr));
336 vki_sigset_t sigmask;
337
338 if (VG_DEBUG_LEAKCHECK)
339 VG_(printf)("scan %p-%p\n", start, len);
340 VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &sigmask);
njn695c16e2005-03-27 03:40:28 +0000341 VG_(set_fault_catcher)(scan_all_valid_memory_catcher);
sewardjb5f6f512005-03-10 23:59:00 +0000342
343 lc_scanned += end-ptr;
344
345 if (!VG_(is_client_addr)(ptr) ||
346 !VG_(is_addressable)(ptr, sizeof(Addr), VKI_PROT_READ))
347 ptr = PGROUNDUP(ptr+1); /* first page bad */
348
sewardj05fe85e2005-04-27 22:46:36 +0000349 while (ptr < end) {
sewardjb5f6f512005-03-10 23:59:00 +0000350 Addr addr;
351
352 /* Skip invalid chunks */
sewardj05fe85e2005-04-27 22:46:36 +0000353 if (!(*lc_is_within_valid_secondary)(ptr)) {
sewardjb5f6f512005-03-10 23:59:00 +0000354 ptr = ROUNDUP(ptr+1, SECONDARY_SIZE);
355 continue;
356 }
357
358 /* Look to see if this page seems reasonble */
359 if ((ptr % VKI_PAGE_SIZE) == 0) {
360 if (!VG_(is_client_addr)(ptr) ||
361 !VG_(is_addressable)(ptr, sizeof(Addr), VKI_PROT_READ))
362 ptr += VKI_PAGE_SIZE; /* bad page - skip it */
363 }
364
365 if (__builtin_setjmp(memscan_jmpbuf) == 0) {
sewardj05fe85e2005-04-27 22:46:36 +0000366 if ((*lc_is_valid_aligned_word)(ptr)) {
sewardjb5f6f512005-03-10 23:59:00 +0000367 addr = *(Addr *)ptr;
368 _lc_markstack_push(addr, clique);
369 } else if (0 && VG_DEBUG_LEAKCHECK)
370 VG_(printf)("%p not valid\n", ptr);
371 ptr += sizeof(Addr);
372 } else {
373 /* We need to restore the signal mask, because we were
374 longjmped out of a signal handler. */
375 VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL);
376
377 ptr = PGROUNDUP(ptr+1); /* bad page - skip it */
378 }
379 }
380
381 VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL);
382 VG_(set_fault_catcher)(NULL);
383}
384
sewardj45d94cc2005-04-20 14:44:11 +0000385
sewardjb5f6f512005-03-10 23:59:00 +0000386static void lc_scan_memory(Addr start, SizeT len)
387{
388 _lc_scan_memory(start, len, -1);
389}
390
391/* Process the mark stack until empty. If mopup is true, then we're
392 actually gathering leaked blocks, so they should be marked
393 IndirectLeak. */
394static void lc_do_leakcheck(Int clique)
395{
396 Int top;
397
398 while((top = lc_markstack_pop()) != -1) {
sewardj76754cf2005-03-14 00:14:04 +0000399 tl_assert(top >= 0 && top < lc_n_shadows);
400 tl_assert(lc_markstack[top].state != Unreached);
sewardjb5f6f512005-03-10 23:59:00 +0000401
402 _lc_scan_memory(lc_shadows[top]->data, lc_shadows[top]->size, clique);
403 }
404}
405
406static Int blocks_leaked;
407static Int blocks_indirect;
408static Int blocks_dubious;
409static Int blocks_reachable;
410static Int blocks_suppressed;
411
njnb8dca862005-03-14 02:42:44 +0000412static void full_report(ThreadId tid)
sewardjb5f6f512005-03-10 23:59:00 +0000413{
414 Int i;
415 Int n_lossrecords;
416 LossRecord* errlist;
417 LossRecord* p;
418 Bool is_suppressed;
njn02977032005-05-17 04:00:11 +0000419 LeakExtra leak_extra;
sewardjb5f6f512005-03-10 23:59:00 +0000420
421 /* Go through and group lost structures into cliques. For each
422 Unreached block, push it onto the mark stack, and find all the
423 blocks linked to it. These are marked IndirectLeak, and their
424 size is added to the clique leader's indirect size. If one of
425 the found blocks was itself a clique leader (from a previous
426 pass), then the cliques are merged. */
427 for (i = 0; i < lc_n_shadows; i++) {
428 if (VG_DEBUG_CLIQUE)
429 VG_(printf)("cliques: %d at %p -> %s\n",
njn02977032005-05-17 04:00:11 +0000430 i, lc_shadows[i]->data, str_lossmode(lc_markstack[i].state));
sewardjb5f6f512005-03-10 23:59:00 +0000431 if (lc_markstack[i].state != Unreached)
432 continue;
433
sewardj76754cf2005-03-14 00:14:04 +0000434 tl_assert(lc_markstack_top == -1);
sewardjb5f6f512005-03-10 23:59:00 +0000435
436 if (VG_DEBUG_CLIQUE)
437 VG_(printf)("%d: gathering clique %p\n", i, lc_shadows[i]->data);
438
439 _lc_markstack_push(lc_shadows[i]->data, i);
440
441 lc_do_leakcheck(i);
442
sewardj76754cf2005-03-14 00:14:04 +0000443 tl_assert(lc_markstack_top == -1);
444 tl_assert(lc_markstack[i].state == IndirectLeak);
sewardjb5f6f512005-03-10 23:59:00 +0000445
446 lc_markstack[i].state = Unreached; /* Return to unreached state,
447 to indicate its a clique
448 leader */
449 }
450
451 /* Common up the lost blocks so we can print sensible error messages. */
452 n_lossrecords = 0;
453 errlist = NULL;
454 for (i = 0; i < lc_n_shadows; i++) {
455 ExeContext* where = lc_shadows[i]->where;
456
457 for (p = errlist; p != NULL; p = p->next) {
458 if (p->loss_mode == lc_markstack[i].state
459 && VG_(eq_ExeContext) ( MAC_(clo_leak_resolution),
460 p->allocated_at,
461 where) ) {
462 break;
463 }
464 }
465 if (p != NULL) {
466 p->num_blocks ++;
467 p->total_bytes += lc_shadows[i]->size;
468 p->indirect_bytes += lc_markstack[i].indirect;
469 } else {
470 n_lossrecords ++;
471 p = VG_(malloc)(sizeof(LossRecord));
472 p->loss_mode = lc_markstack[i].state;
473 p->allocated_at = where;
474 p->total_bytes = lc_shadows[i]->size;
475 p->indirect_bytes = lc_markstack[i].indirect;
476 p->num_blocks = 1;
477 p->next = errlist;
478 errlist = p;
479 }
480 }
481
482 /* Print out the commoned-up blocks and collect summary stats. */
483 for (i = 0; i < n_lossrecords; i++) {
484 Bool print_record;
485 LossRecord* p_min = NULL;
486 UInt n_min = 0xFFFFFFFF;
487 for (p = errlist; p != NULL; p = p->next) {
488 if (p->num_blocks > 0 && p->total_bytes < n_min) {
489 n_min = p->total_bytes + p->indirect_bytes;
490 p_min = p;
491 }
492 }
sewardj76754cf2005-03-14 00:14:04 +0000493 tl_assert(p_min != NULL);
sewardjb5f6f512005-03-10 23:59:00 +0000494
495 /* Ok to have tst==NULL; it's only used if --gdb-attach=yes, and
496 we disallow that when --leak-check=yes.
497
njn02977032005-05-17 04:00:11 +0000498 Prints the error if not suppressed, unless it's reachable (Proper
499 or IndirectLeak) and --show-reachable=no */
sewardjb5f6f512005-03-10 23:59:00 +0000500
501 print_record = ( MAC_(clo_show_reachable) ||
njn02977032005-05-17 04:00:11 +0000502 Unreached == p_min->loss_mode ||
503 Interior == p_min->loss_mode );
504
505 // Nb: because VG_(unique_error) does all the error processing
506 // immediately, and doesn't save the error, leakExtra can be
507 // stack-allocated.
508 leak_extra.n_this_record = i+1;
509 leak_extra.n_total_records = n_lossrecords;
510 leak_extra.lossRecord = p_min;
sewardjb5f6f512005-03-10 23:59:00 +0000511 is_suppressed =
njn02977032005-05-17 04:00:11 +0000512 VG_(unique_error) ( tid, LeakErr, /*Addr*/0, /*s*/NULL,
513 /*extra*/&leak_extra,
514 /*where*/p_min->allocated_at, print_record,
sewardjb5f6f512005-03-10 23:59:00 +0000515 /*allow_GDB_attach*/False, /*count_error*/False );
516
517 if (is_suppressed) {
518 blocks_suppressed += p_min->num_blocks;
519 MAC_(bytes_suppressed) += p_min->total_bytes;
520
521 } else if (Unreached == p_min->loss_mode) {
522 blocks_leaked += p_min->num_blocks;
523 MAC_(bytes_leaked) += p_min->total_bytes;
524
525 } else if (IndirectLeak == p_min->loss_mode) {
526 blocks_indirect += p_min->num_blocks;
527 MAC_(bytes_indirect)+= p_min->total_bytes;
528
529 } else if (Interior == p_min->loss_mode) {
530 blocks_dubious += p_min->num_blocks;
531 MAC_(bytes_dubious) += p_min->total_bytes;
532
533 } else if (Proper == p_min->loss_mode) {
534 blocks_reachable += p_min->num_blocks;
535 MAC_(bytes_reachable) += p_min->total_bytes;
536
537 } else {
sewardj76754cf2005-03-14 00:14:04 +0000538 VG_(tool_panic)("generic_detect_memory_leaks: unknown loss mode");
sewardjb5f6f512005-03-10 23:59:00 +0000539 }
540 p_min->num_blocks = 0;
541 }
542}
543
544/* Compute a quick summary of the leak check. */
545static void make_summary()
546{
547 Int i;
548
549 for(i = 0; i < lc_n_shadows; i++) {
550 SizeT size = lc_shadows[i]->size;
551
552 switch(lc_markstack[i].state) {
553 case Unreached:
554 blocks_leaked++;
555 MAC_(bytes_leaked) += size;
556 break;
557
558 case Proper:
559 blocks_reachable++;
560 MAC_(bytes_reachable) += size;
561 break;
562
563 case Interior:
564 blocks_dubious++;
565 MAC_(bytes_dubious) += size;
566 break;
567
568 case IndirectLeak: /* shouldn't happen */
569 blocks_indirect++;
570 MAC_(bytes_indirect) += size;
571 break;
572 }
573 }
574}
575
njn43c799e2003-04-08 00:08:52 +0000576/* Top level entry point to leak detector. Call here, passing in
577 suitable address-validating functions (see comment at top of
njn695c16e2005-03-27 03:40:28 +0000578 scan_all_valid_memory above). All this is to avoid duplication
nethercote996901a2004-08-03 13:29:09 +0000579 of the leak-detection code for Memcheck and Addrcheck.
580 Also pass in a tool-specific function to extract the .where field
njn43c799e2003-04-08 00:08:52 +0000581 for allocated blocks, an indication of the resolution wanted for
582 distinguishing different allocation points, and whether or not
583 reachable blocks should be shown.
584*/
585void MAC_(do_detect_memory_leaks) (
njnb8dca862005-03-14 02:42:44 +0000586 ThreadId tid, LeakCheckMode mode,
sewardj05fe85e2005-04-27 22:46:36 +0000587 Bool (*is_within_valid_secondary) ( Addr ),
588 Bool (*is_valid_aligned_word) ( Addr )
njn43c799e2003-04-08 00:08:52 +0000589)
590{
njnb8dca862005-03-14 02:42:44 +0000591 Int i;
njn43c799e2003-04-08 00:08:52 +0000592
sewardj76754cf2005-03-14 00:14:04 +0000593 tl_assert(mode != LC_Off);
njn43c799e2003-04-08 00:08:52 +0000594
njn06072ec2003-09-30 15:35:13 +0000595 /* VG_(HT_to_array) allocates storage for shadows */
596 lc_shadows = (MAC_Chunk**)VG_(HT_to_array)( MAC_(malloc_list),
597 &lc_n_shadows );
598
599 /* Sort the array. */
600 VG_(ssort)((void*)lc_shadows, lc_n_shadows, sizeof(VgHashNode*), lc_compar);
601
602 /* Sanity check; assert that the blocks are now in order */
603 for (i = 0; i < lc_n_shadows-1; i++) {
sewardj76754cf2005-03-14 00:14:04 +0000604 tl_assert( lc_shadows[i]->data <= lc_shadows[i+1]->data);
njn06072ec2003-09-30 15:35:13 +0000605 }
njn3e884182003-04-15 13:03:23 +0000606
607 /* Sanity check -- make sure they don't overlap */
608 for (i = 0; i < lc_n_shadows-1; i++) {
sewardj76754cf2005-03-14 00:14:04 +0000609 tl_assert( lc_shadows[i]->data + lc_shadows[i]->size
njn3e884182003-04-15 13:03:23 +0000610 < lc_shadows[i+1]->data );
611 }
612
613 if (lc_n_shadows == 0) {
sewardj76754cf2005-03-14 00:14:04 +0000614 tl_assert(lc_shadows == NULL);
sewardj37d06f22003-09-17 21:48:26 +0000615 if (VG_(clo_verbosity) >= 1) {
616 VG_(message)(Vg_UserMsg,
617 "No malloc'd blocks -- no leaks are possible.");
618 }
njn43c799e2003-04-08 00:08:52 +0000619 return;
620 }
621
nethercote0f19bce2003-12-02 10:17:44 +0000622 if (VG_(clo_verbosity) > 0)
623 VG_(message)(Vg_UserMsg,
624 "searching for pointers to %d not-freed blocks.",
625 lc_n_shadows );
njn43c799e2003-04-08 00:08:52 +0000626
njn3e884182003-04-15 13:03:23 +0000627 lc_min_mallocd_addr = lc_shadows[0]->data;
628 lc_max_mallocd_addr = lc_shadows[lc_n_shadows-1]->data
sewardjb5f6f512005-03-10 23:59:00 +0000629 + lc_shadows[lc_n_shadows-1]->size;
njn43c799e2003-04-08 00:08:52 +0000630
sewardjb5f6f512005-03-10 23:59:00 +0000631 lc_markstack = VG_(malloc)( lc_n_shadows * sizeof(*lc_markstack) );
632 for (i = 0; i < lc_n_shadows; i++) {
633 lc_markstack[i].next = -1;
634 lc_markstack[i].state = Unreached;
635 lc_markstack[i].indirect = 0;
636 }
637 lc_markstack_top = -1;
njn43c799e2003-04-08 00:08:52 +0000638
sewardj05fe85e2005-04-27 22:46:36 +0000639 lc_is_within_valid_secondary = is_within_valid_secondary;
640 lc_is_valid_aligned_word = is_valid_aligned_word;
sewardjb5f6f512005-03-10 23:59:00 +0000641
642 lc_scanned = 0;
643
644 /* Do the scan of memory, pushing any pointers onto the mark stack */
645 VG_(find_root_memory)(lc_scan_memory);
646
647 /* Push registers onto mark stack */
648 VG_(mark_from_registers)(lc_markstack_push);
649
650 /* Keep walking the heap until everything is found */
651 lc_do_leakcheck(-1);
njn43c799e2003-04-08 00:08:52 +0000652
nethercote0f19bce2003-12-02 10:17:44 +0000653 if (VG_(clo_verbosity) > 0)
sewardjb5f6f512005-03-10 23:59:00 +0000654 VG_(message)(Vg_UserMsg, "checked %d bytes.", lc_scanned);
njn43c799e2003-04-08 00:08:52 +0000655
njne8b5c052003-07-22 22:03:58 +0000656 blocks_leaked = MAC_(bytes_leaked) = 0;
sewardjb5f6f512005-03-10 23:59:00 +0000657 blocks_indirect = MAC_(bytes_indirect) = 0;
njne8b5c052003-07-22 22:03:58 +0000658 blocks_dubious = MAC_(bytes_dubious) = 0;
659 blocks_reachable = MAC_(bytes_reachable) = 0;
660 blocks_suppressed = MAC_(bytes_suppressed) = 0;
njn43c799e2003-04-08 00:08:52 +0000661
sewardjb5f6f512005-03-10 23:59:00 +0000662 if (mode == LC_Full)
njnb8dca862005-03-14 02:42:44 +0000663 full_report(tid);
sewardjb5f6f512005-03-10 23:59:00 +0000664 else
665 make_summary();
njn43c799e2003-04-08 00:08:52 +0000666
nethercote0f19bce2003-12-02 10:17:44 +0000667 if (VG_(clo_verbosity) > 0) {
668 VG_(message)(Vg_UserMsg, "");
669 VG_(message)(Vg_UserMsg, "LEAK SUMMARY:");
670 VG_(message)(Vg_UserMsg, " definitely lost: %d bytes in %d blocks.",
671 MAC_(bytes_leaked), blocks_leaked );
sewardjb5f6f512005-03-10 23:59:00 +0000672 if (blocks_indirect > 0)
673 VG_(message)(Vg_UserMsg, " indirectly lost: %d bytes in %d blocks.",
674 MAC_(bytes_indirect), blocks_indirect );
675 VG_(message)(Vg_UserMsg, " possibly lost: %d bytes in %d blocks.",
nethercote0f19bce2003-12-02 10:17:44 +0000676 MAC_(bytes_dubious), blocks_dubious );
677 VG_(message)(Vg_UserMsg, " still reachable: %d bytes in %d blocks.",
678 MAC_(bytes_reachable), blocks_reachable );
679 VG_(message)(Vg_UserMsg, " suppressed: %d bytes in %d blocks.",
680 MAC_(bytes_suppressed), blocks_suppressed );
njn6a329422005-03-12 20:38:13 +0000681 if (mode == LC_Summary && blocks_leaked > 0)
sewardjb5f6f512005-03-10 23:59:00 +0000682 VG_(message)(Vg_UserMsg,
683 "Use --leak-check=full to see details of leaked memory.");
684 else if (!MAC_(clo_show_reachable)) {
nethercote0f19bce2003-12-02 10:17:44 +0000685 VG_(message)(Vg_UserMsg,
686 "Reachable blocks (those to which a pointer was found) are not shown.");
687 VG_(message)(Vg_UserMsg,
688 "To see them, rerun with: --show-reachable=yes");
689 }
njn43c799e2003-04-08 00:08:52 +0000690 }
njn43c799e2003-04-08 00:08:52 +0000691
njn3e884182003-04-15 13:03:23 +0000692 VG_(free) ( lc_shadows );
sewardjb5f6f512005-03-10 23:59:00 +0000693 VG_(free) ( lc_markstack );
njn43c799e2003-04-08 00:08:52 +0000694}
695
696/*--------------------------------------------------------------------*/
697/*--- end mac_leakcheck.c ---*/
698/*--------------------------------------------------------------------*/
699