blob: d97730de51c72c1ab546660f05a170fb8baa6cb0 [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
sewardj71bc3cb2005-05-19 00:25:45 +0000187static const HChar* str_lossmode ( Reachedness lossmode )
njn43c799e2003-04-08 00:08:52 +0000188{
sewardj71bc3cb2005-05-19 00:25:45 +0000189 const HChar *loss = "?";
190 switch (lossmode) {
191 case Unreached: loss = "definitely lost"; break;
192 case IndirectLeak: loss = "indirectly lost"; break;
193 case Interior: loss = "possibly lost"; break;
194 case Proper: loss = "still reachable"; break;
njn43c799e2003-04-08 00:08:52 +0000195 }
sewardjb5f6f512005-03-10 23:59:00 +0000196 return loss;
njn43c799e2003-04-08 00:08:52 +0000197}
198
sewardj71bc3cb2005-05-19 00:25:45 +0000199static const HChar* xml_kind ( Reachedness lossmode )
200{
201 const HChar *loss = "?";
202 switch (lossmode) {
203 case Unreached: loss = "Leak_DefinitelyLost"; break;
204 case IndirectLeak: loss = "Leak_IndirectlyLost"; break;
205 case Interior: loss = "Leak_PossiblyLost"; break;
206 case Proper: loss = "Leak_StillReachable"; break;
207 }
208 return loss;
209}
210
211
njn43c799e2003-04-08 00:08:52 +0000212/* Used for printing leak errors, avoids exposing the LossRecord type (which
213 comes in as void*, requiring a cast. */
njn02977032005-05-17 04:00:11 +0000214void MAC_(pp_LeakError)(void* vextra)
njn43c799e2003-04-08 00:08:52 +0000215{
sewardj71bc3cb2005-05-19 00:25:45 +0000216 HChar* xpre = VG_(clo_xml) ? " <what>" : "";
217 HChar* xpost = VG_(clo_xml) ? "</what>" : "";
218
njn02977032005-05-17 04:00:11 +0000219 LeakExtra* extra = (LeakExtra*)vextra;
220 LossRecord* l = extra->lossRecord;
221 const Char *loss = str_lossmode(l->loss_mode);
njn43c799e2003-04-08 00:08:52 +0000222
sewardj71bc3cb2005-05-19 00:25:45 +0000223 if (VG_(clo_xml)) {
224 VG_(message)(Vg_UserMsg, " <kind>%s</kind>", xml_kind(l->loss_mode));
225 } else {
226 VG_(message)(Vg_UserMsg, "");
227 }
228
sewardjb5f6f512005-03-10 23:59:00 +0000229 if (l->indirect_bytes) {
230 VG_(message)(Vg_UserMsg,
sewardj71bc3cb2005-05-19 00:25:45 +0000231 "%s%d (%d direct, %d indirect) bytes in %d blocks"
232 " are %s in loss record %d of %d%s",
233 xpre,
234 l->total_bytes + l->indirect_bytes,
235 l->total_bytes, l->indirect_bytes, l->num_blocks,
236 loss, extra->n_this_record, extra->n_total_records,
237 xpost
238 );
239 if (VG_(clo_xml)) {
240 VG_(message)(Vg_UserMsg, " <leakedbytes>%d</leakedbytes>",
241 l->total_bytes + l->indirect_bytes);
242 VG_(message)(Vg_UserMsg, " <leakedblocks>%d</leakedblocks>",
243 l->num_blocks);
244 }
sewardjb5f6f512005-03-10 23:59:00 +0000245 } else {
sewardj71bc3cb2005-05-19 00:25:45 +0000246 VG_(message)(
247 Vg_UserMsg,
248 "%s%d bytes in %d blocks are %s in loss record %d of %d%s",
249 xpre,
250 l->total_bytes, l->num_blocks,
251 loss, extra->n_this_record, extra->n_total_records,
252 xpost
253 );
254 if (VG_(clo_xml)) {
255 VG_(message)(Vg_UserMsg, " <leakedbytes>%d</leakedbytes>",
256 l->total_bytes);
257 VG_(message)(Vg_UserMsg, " <leakedblocks>%d</leakedblocks>",
258 l->num_blocks);
259 }
sewardjb5f6f512005-03-10 23:59:00 +0000260 }
njn43c799e2003-04-08 00:08:52 +0000261 VG_(pp_ExeContext)(l->allocated_at);
262}
263
njne8b5c052003-07-22 22:03:58 +0000264Int MAC_(bytes_leaked) = 0;
sewardjb5f6f512005-03-10 23:59:00 +0000265Int MAC_(bytes_indirect) = 0;
njne8b5c052003-07-22 22:03:58 +0000266Int MAC_(bytes_dubious) = 0;
267Int MAC_(bytes_reachable) = 0;
268Int MAC_(bytes_suppressed) = 0;
njn47363ab2003-04-21 13:24:40 +0000269
njn06072ec2003-09-30 15:35:13 +0000270static Int lc_compar(void* n1, void* n2)
271{
272 MAC_Chunk* mc1 = *(MAC_Chunk**)n1;
273 MAC_Chunk* mc2 = *(MAC_Chunk**)n2;
274 return (mc1->data < mc2->data ? -1 : 1);
275}
276
sewardjb5f6f512005-03-10 23:59:00 +0000277/* If ptr is pointing to a heap-allocated block which hasn't been seen
278 before, push it onto the mark stack. Clique is the index of the
279 clique leader; -1 if none. */
280static void _lc_markstack_push(Addr ptr, Int clique)
281{
282 Int sh_no;
283
284 if (!VG_(is_client_addr)(ptr)) /* quick filter */
285 return;
286
287 sh_no = find_shadow_for(ptr, lc_shadows, lc_n_shadows);
288
289 if (VG_DEBUG_LEAKCHECK)
290 VG_(printf)("ptr=%p -> block %d\n", ptr, sh_no);
291
292 if (sh_no == -1)
293 return;
294
sewardj76754cf2005-03-14 00:14:04 +0000295 tl_assert(sh_no >= 0 && sh_no < lc_n_shadows);
296 tl_assert(ptr <= lc_shadows[sh_no]->data + lc_shadows[sh_no]->size);
sewardjb5f6f512005-03-10 23:59:00 +0000297
298 if (lc_markstack[sh_no].state == Unreached) {
299 if (0)
300 VG_(printf)("pushing %p-%p\n", lc_shadows[sh_no]->data,
301 lc_shadows[sh_no]->data + lc_shadows[sh_no]->size);
302
sewardj76754cf2005-03-14 00:14:04 +0000303 tl_assert(lc_markstack[sh_no].next == -1);
sewardjb5f6f512005-03-10 23:59:00 +0000304 lc_markstack[sh_no].next = lc_markstack_top;
305 lc_markstack_top = sh_no;
306 }
307
308 if (clique != -1) {
309 if (0)
310 VG_(printf)("mopup: %d: %p is %d\n",
311 sh_no, lc_shadows[sh_no]->data, lc_markstack[sh_no].state);
312
313 /* An unmarked block - add it to the clique. Add its size to
314 the clique-leader's indirect size. If the new block was
315 itself a clique leader, it isn't any more, so add its
316 indirect to the new clique leader.
317
318 If this block *is* the clique leader, it means this is a
319 cyclic structure, so none of this applies. */
320 if (lc_markstack[sh_no].state == Unreached) {
321 lc_markstack[sh_no].state = IndirectLeak;
322
323 if (sh_no != clique) {
324 if (VG_DEBUG_CLIQUE) {
325 if (lc_markstack[sh_no].indirect)
326 VG_(printf)(" clique %d joining clique %d adding %d+%d bytes\n",
327 sh_no, clique,
328 lc_shadows[sh_no]->size, lc_markstack[sh_no].indirect);
329 else
330 VG_(printf)(" %d joining %d adding %d\n",
331 sh_no, clique, lc_shadows[sh_no]->size);
332 }
333
334 lc_markstack[clique].indirect += lc_shadows[sh_no]->size;
335 lc_markstack[clique].indirect += lc_markstack[sh_no].indirect;
336 lc_markstack[sh_no].indirect = 0; /* shouldn't matter */
337 }
338 }
339 } else if (ptr == lc_shadows[sh_no]->data) {
340 lc_markstack[sh_no].state = Proper;
341 } else {
342 if (lc_markstack[sh_no].state == Unreached)
343 lc_markstack[sh_no].state = Interior;
344 }
345}
346
347static void lc_markstack_push(Addr ptr)
348{
349 _lc_markstack_push(ptr, -1);
350}
351
352/* Return the top of the mark stack, if any. */
353static Int lc_markstack_pop(void)
354{
355 Int ret = lc_markstack_top;
356
357 if (ret != -1) {
358 lc_markstack_top = lc_markstack[ret].next;
359 lc_markstack[ret].next = -1;
360 }
361
362 return ret;
363}
364
sewardj45d94cc2005-04-20 14:44:11 +0000365
sewardjb5f6f512005-03-10 23:59:00 +0000366/* Scan a block of memory between [start, start+len). This range may
367 be bogus, inaccessable, or otherwise strange; we deal with it.
368
369 If clique != -1, it means we're gathering leaked memory into
370 cliques, and clique is the index of the current clique leader. */
371static void _lc_scan_memory(Addr start, SizeT len, Int clique)
372{
373 Addr ptr = ROUNDUP(start, sizeof(Addr));
374 Addr end = ROUNDDN(start+len, sizeof(Addr));
375 vki_sigset_t sigmask;
376
377 if (VG_DEBUG_LEAKCHECK)
378 VG_(printf)("scan %p-%p\n", start, len);
379 VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &sigmask);
njn695c16e2005-03-27 03:40:28 +0000380 VG_(set_fault_catcher)(scan_all_valid_memory_catcher);
sewardjb5f6f512005-03-10 23:59:00 +0000381
382 lc_scanned += end-ptr;
383
384 if (!VG_(is_client_addr)(ptr) ||
385 !VG_(is_addressable)(ptr, sizeof(Addr), VKI_PROT_READ))
386 ptr = PGROUNDUP(ptr+1); /* first page bad */
387
sewardj05fe85e2005-04-27 22:46:36 +0000388 while (ptr < end) {
sewardjb5f6f512005-03-10 23:59:00 +0000389 Addr addr;
390
391 /* Skip invalid chunks */
sewardj05fe85e2005-04-27 22:46:36 +0000392 if (!(*lc_is_within_valid_secondary)(ptr)) {
sewardjb5f6f512005-03-10 23:59:00 +0000393 ptr = ROUNDUP(ptr+1, SECONDARY_SIZE);
394 continue;
395 }
396
397 /* Look to see if this page seems reasonble */
398 if ((ptr % VKI_PAGE_SIZE) == 0) {
399 if (!VG_(is_client_addr)(ptr) ||
400 !VG_(is_addressable)(ptr, sizeof(Addr), VKI_PROT_READ))
401 ptr += VKI_PAGE_SIZE; /* bad page - skip it */
402 }
403
404 if (__builtin_setjmp(memscan_jmpbuf) == 0) {
sewardj05fe85e2005-04-27 22:46:36 +0000405 if ((*lc_is_valid_aligned_word)(ptr)) {
sewardjb5f6f512005-03-10 23:59:00 +0000406 addr = *(Addr *)ptr;
407 _lc_markstack_push(addr, clique);
408 } else if (0 && VG_DEBUG_LEAKCHECK)
409 VG_(printf)("%p not valid\n", ptr);
410 ptr += sizeof(Addr);
411 } else {
412 /* We need to restore the signal mask, because we were
413 longjmped out of a signal handler. */
414 VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL);
415
416 ptr = PGROUNDUP(ptr+1); /* bad page - skip it */
417 }
418 }
419
420 VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL);
421 VG_(set_fault_catcher)(NULL);
422}
423
sewardj45d94cc2005-04-20 14:44:11 +0000424
sewardjb5f6f512005-03-10 23:59:00 +0000425static void lc_scan_memory(Addr start, SizeT len)
426{
427 _lc_scan_memory(start, len, -1);
428}
429
430/* Process the mark stack until empty. If mopup is true, then we're
431 actually gathering leaked blocks, so they should be marked
432 IndirectLeak. */
433static void lc_do_leakcheck(Int clique)
434{
435 Int top;
436
437 while((top = lc_markstack_pop()) != -1) {
sewardj76754cf2005-03-14 00:14:04 +0000438 tl_assert(top >= 0 && top < lc_n_shadows);
439 tl_assert(lc_markstack[top].state != Unreached);
sewardjb5f6f512005-03-10 23:59:00 +0000440
441 _lc_scan_memory(lc_shadows[top]->data, lc_shadows[top]->size, clique);
442 }
443}
444
445static Int blocks_leaked;
446static Int blocks_indirect;
447static Int blocks_dubious;
448static Int blocks_reachable;
449static Int blocks_suppressed;
450
njnb8dca862005-03-14 02:42:44 +0000451static void full_report(ThreadId tid)
sewardjb5f6f512005-03-10 23:59:00 +0000452{
453 Int i;
454 Int n_lossrecords;
455 LossRecord* errlist;
456 LossRecord* p;
457 Bool is_suppressed;
njn02977032005-05-17 04:00:11 +0000458 LeakExtra leak_extra;
sewardjb5f6f512005-03-10 23:59:00 +0000459
460 /* Go through and group lost structures into cliques. For each
461 Unreached block, push it onto the mark stack, and find all the
462 blocks linked to it. These are marked IndirectLeak, and their
463 size is added to the clique leader's indirect size. If one of
464 the found blocks was itself a clique leader (from a previous
465 pass), then the cliques are merged. */
466 for (i = 0; i < lc_n_shadows; i++) {
467 if (VG_DEBUG_CLIQUE)
468 VG_(printf)("cliques: %d at %p -> %s\n",
njn02977032005-05-17 04:00:11 +0000469 i, lc_shadows[i]->data, str_lossmode(lc_markstack[i].state));
sewardjb5f6f512005-03-10 23:59:00 +0000470 if (lc_markstack[i].state != Unreached)
471 continue;
472
sewardj76754cf2005-03-14 00:14:04 +0000473 tl_assert(lc_markstack_top == -1);
sewardjb5f6f512005-03-10 23:59:00 +0000474
475 if (VG_DEBUG_CLIQUE)
476 VG_(printf)("%d: gathering clique %p\n", i, lc_shadows[i]->data);
477
478 _lc_markstack_push(lc_shadows[i]->data, i);
479
480 lc_do_leakcheck(i);
481
sewardj76754cf2005-03-14 00:14:04 +0000482 tl_assert(lc_markstack_top == -1);
483 tl_assert(lc_markstack[i].state == IndirectLeak);
sewardjb5f6f512005-03-10 23:59:00 +0000484
485 lc_markstack[i].state = Unreached; /* Return to unreached state,
486 to indicate its a clique
487 leader */
488 }
489
490 /* Common up the lost blocks so we can print sensible error messages. */
491 n_lossrecords = 0;
492 errlist = NULL;
493 for (i = 0; i < lc_n_shadows; i++) {
494 ExeContext* where = lc_shadows[i]->where;
495
496 for (p = errlist; p != NULL; p = p->next) {
497 if (p->loss_mode == lc_markstack[i].state
498 && VG_(eq_ExeContext) ( MAC_(clo_leak_resolution),
499 p->allocated_at,
500 where) ) {
501 break;
502 }
503 }
504 if (p != NULL) {
505 p->num_blocks ++;
506 p->total_bytes += lc_shadows[i]->size;
507 p->indirect_bytes += lc_markstack[i].indirect;
508 } else {
509 n_lossrecords ++;
510 p = VG_(malloc)(sizeof(LossRecord));
511 p->loss_mode = lc_markstack[i].state;
512 p->allocated_at = where;
513 p->total_bytes = lc_shadows[i]->size;
514 p->indirect_bytes = lc_markstack[i].indirect;
515 p->num_blocks = 1;
516 p->next = errlist;
517 errlist = p;
518 }
519 }
520
521 /* Print out the commoned-up blocks and collect summary stats. */
522 for (i = 0; i < n_lossrecords; i++) {
523 Bool print_record;
524 LossRecord* p_min = NULL;
525 UInt n_min = 0xFFFFFFFF;
526 for (p = errlist; p != NULL; p = p->next) {
527 if (p->num_blocks > 0 && p->total_bytes < n_min) {
528 n_min = p->total_bytes + p->indirect_bytes;
529 p_min = p;
530 }
531 }
sewardj76754cf2005-03-14 00:14:04 +0000532 tl_assert(p_min != NULL);
sewardjb5f6f512005-03-10 23:59:00 +0000533
534 /* Ok to have tst==NULL; it's only used if --gdb-attach=yes, and
535 we disallow that when --leak-check=yes.
536
njn02977032005-05-17 04:00:11 +0000537 Prints the error if not suppressed, unless it's reachable (Proper
538 or IndirectLeak) and --show-reachable=no */
sewardjb5f6f512005-03-10 23:59:00 +0000539
540 print_record = ( MAC_(clo_show_reachable) ||
njn02977032005-05-17 04:00:11 +0000541 Unreached == p_min->loss_mode ||
542 Interior == p_min->loss_mode );
543
544 // Nb: because VG_(unique_error) does all the error processing
545 // immediately, and doesn't save the error, leakExtra can be
546 // stack-allocated.
547 leak_extra.n_this_record = i+1;
548 leak_extra.n_total_records = n_lossrecords;
549 leak_extra.lossRecord = p_min;
sewardjb5f6f512005-03-10 23:59:00 +0000550 is_suppressed =
njn02977032005-05-17 04:00:11 +0000551 VG_(unique_error) ( tid, LeakErr, /*Addr*/0, /*s*/NULL,
552 /*extra*/&leak_extra,
553 /*where*/p_min->allocated_at, print_record,
sewardjb5f6f512005-03-10 23:59:00 +0000554 /*allow_GDB_attach*/False, /*count_error*/False );
555
556 if (is_suppressed) {
557 blocks_suppressed += p_min->num_blocks;
558 MAC_(bytes_suppressed) += p_min->total_bytes;
559
560 } else if (Unreached == p_min->loss_mode) {
561 blocks_leaked += p_min->num_blocks;
562 MAC_(bytes_leaked) += p_min->total_bytes;
563
564 } else if (IndirectLeak == p_min->loss_mode) {
565 blocks_indirect += p_min->num_blocks;
566 MAC_(bytes_indirect)+= p_min->total_bytes;
567
568 } else if (Interior == p_min->loss_mode) {
569 blocks_dubious += p_min->num_blocks;
570 MAC_(bytes_dubious) += p_min->total_bytes;
571
572 } else if (Proper == p_min->loss_mode) {
573 blocks_reachable += p_min->num_blocks;
574 MAC_(bytes_reachable) += p_min->total_bytes;
575
576 } else {
sewardj76754cf2005-03-14 00:14:04 +0000577 VG_(tool_panic)("generic_detect_memory_leaks: unknown loss mode");
sewardjb5f6f512005-03-10 23:59:00 +0000578 }
579 p_min->num_blocks = 0;
580 }
581}
582
583/* Compute a quick summary of the leak check. */
584static void make_summary()
585{
586 Int i;
587
588 for(i = 0; i < lc_n_shadows; i++) {
589 SizeT size = lc_shadows[i]->size;
590
591 switch(lc_markstack[i].state) {
592 case Unreached:
593 blocks_leaked++;
594 MAC_(bytes_leaked) += size;
595 break;
596
597 case Proper:
598 blocks_reachable++;
599 MAC_(bytes_reachable) += size;
600 break;
601
602 case Interior:
603 blocks_dubious++;
604 MAC_(bytes_dubious) += size;
605 break;
606
607 case IndirectLeak: /* shouldn't happen */
608 blocks_indirect++;
609 MAC_(bytes_indirect) += size;
610 break;
611 }
612 }
613}
614
njn43c799e2003-04-08 00:08:52 +0000615/* Top level entry point to leak detector. Call here, passing in
616 suitable address-validating functions (see comment at top of
njn695c16e2005-03-27 03:40:28 +0000617 scan_all_valid_memory above). All this is to avoid duplication
nethercote996901a2004-08-03 13:29:09 +0000618 of the leak-detection code for Memcheck and Addrcheck.
619 Also pass in a tool-specific function to extract the .where field
njn43c799e2003-04-08 00:08:52 +0000620 for allocated blocks, an indication of the resolution wanted for
621 distinguishing different allocation points, and whether or not
622 reachable blocks should be shown.
623*/
624void MAC_(do_detect_memory_leaks) (
njnb8dca862005-03-14 02:42:44 +0000625 ThreadId tid, LeakCheckMode mode,
sewardj05fe85e2005-04-27 22:46:36 +0000626 Bool (*is_within_valid_secondary) ( Addr ),
627 Bool (*is_valid_aligned_word) ( Addr )
njn43c799e2003-04-08 00:08:52 +0000628)
629{
njnb8dca862005-03-14 02:42:44 +0000630 Int i;
njn43c799e2003-04-08 00:08:52 +0000631
sewardj76754cf2005-03-14 00:14:04 +0000632 tl_assert(mode != LC_Off);
njn43c799e2003-04-08 00:08:52 +0000633
njn06072ec2003-09-30 15:35:13 +0000634 /* VG_(HT_to_array) allocates storage for shadows */
635 lc_shadows = (MAC_Chunk**)VG_(HT_to_array)( MAC_(malloc_list),
636 &lc_n_shadows );
637
638 /* Sort the array. */
639 VG_(ssort)((void*)lc_shadows, lc_n_shadows, sizeof(VgHashNode*), lc_compar);
640
641 /* Sanity check; assert that the blocks are now in order */
642 for (i = 0; i < lc_n_shadows-1; i++) {
sewardj76754cf2005-03-14 00:14:04 +0000643 tl_assert( lc_shadows[i]->data <= lc_shadows[i+1]->data);
njn06072ec2003-09-30 15:35:13 +0000644 }
njn3e884182003-04-15 13:03:23 +0000645
646 /* Sanity check -- make sure they don't overlap */
647 for (i = 0; i < lc_n_shadows-1; i++) {
sewardj76754cf2005-03-14 00:14:04 +0000648 tl_assert( lc_shadows[i]->data + lc_shadows[i]->size
njn3e884182003-04-15 13:03:23 +0000649 < lc_shadows[i+1]->data );
650 }
651
652 if (lc_n_shadows == 0) {
sewardj76754cf2005-03-14 00:14:04 +0000653 tl_assert(lc_shadows == NULL);
sewardj71bc3cb2005-05-19 00:25:45 +0000654 if (VG_(clo_verbosity) >= 1 && !VG_(clo_xml)) {
sewardj37d06f22003-09-17 21:48:26 +0000655 VG_(message)(Vg_UserMsg,
656 "No malloc'd blocks -- no leaks are possible.");
657 }
njn43c799e2003-04-08 00:08:52 +0000658 return;
659 }
660
sewardj71bc3cb2005-05-19 00:25:45 +0000661 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
nethercote0f19bce2003-12-02 10:17:44 +0000662 VG_(message)(Vg_UserMsg,
663 "searching for pointers to %d not-freed blocks.",
664 lc_n_shadows );
njn43c799e2003-04-08 00:08:52 +0000665
njn3e884182003-04-15 13:03:23 +0000666 lc_min_mallocd_addr = lc_shadows[0]->data;
667 lc_max_mallocd_addr = lc_shadows[lc_n_shadows-1]->data
sewardjb5f6f512005-03-10 23:59:00 +0000668 + lc_shadows[lc_n_shadows-1]->size;
njn43c799e2003-04-08 00:08:52 +0000669
sewardjb5f6f512005-03-10 23:59:00 +0000670 lc_markstack = VG_(malloc)( lc_n_shadows * sizeof(*lc_markstack) );
671 for (i = 0; i < lc_n_shadows; i++) {
672 lc_markstack[i].next = -1;
673 lc_markstack[i].state = Unreached;
674 lc_markstack[i].indirect = 0;
675 }
676 lc_markstack_top = -1;
njn43c799e2003-04-08 00:08:52 +0000677
sewardj05fe85e2005-04-27 22:46:36 +0000678 lc_is_within_valid_secondary = is_within_valid_secondary;
679 lc_is_valid_aligned_word = is_valid_aligned_word;
sewardjb5f6f512005-03-10 23:59:00 +0000680
681 lc_scanned = 0;
682
683 /* Do the scan of memory, pushing any pointers onto the mark stack */
684 VG_(find_root_memory)(lc_scan_memory);
685
686 /* Push registers onto mark stack */
687 VG_(mark_from_registers)(lc_markstack_push);
688
689 /* Keep walking the heap until everything is found */
690 lc_do_leakcheck(-1);
njn43c799e2003-04-08 00:08:52 +0000691
sewardj71bc3cb2005-05-19 00:25:45 +0000692 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
sewardjb5f6f512005-03-10 23:59:00 +0000693 VG_(message)(Vg_UserMsg, "checked %d bytes.", lc_scanned);
njn43c799e2003-04-08 00:08:52 +0000694
njne8b5c052003-07-22 22:03:58 +0000695 blocks_leaked = MAC_(bytes_leaked) = 0;
sewardjb5f6f512005-03-10 23:59:00 +0000696 blocks_indirect = MAC_(bytes_indirect) = 0;
njne8b5c052003-07-22 22:03:58 +0000697 blocks_dubious = MAC_(bytes_dubious) = 0;
698 blocks_reachable = MAC_(bytes_reachable) = 0;
699 blocks_suppressed = MAC_(bytes_suppressed) = 0;
njn43c799e2003-04-08 00:08:52 +0000700
sewardjb5f6f512005-03-10 23:59:00 +0000701 if (mode == LC_Full)
njnb8dca862005-03-14 02:42:44 +0000702 full_report(tid);
sewardjb5f6f512005-03-10 23:59:00 +0000703 else
704 make_summary();
njn43c799e2003-04-08 00:08:52 +0000705
sewardj71bc3cb2005-05-19 00:25:45 +0000706 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) {
nethercote0f19bce2003-12-02 10:17:44 +0000707 VG_(message)(Vg_UserMsg, "");
708 VG_(message)(Vg_UserMsg, "LEAK SUMMARY:");
709 VG_(message)(Vg_UserMsg, " definitely lost: %d bytes in %d blocks.",
710 MAC_(bytes_leaked), blocks_leaked );
sewardjb5f6f512005-03-10 23:59:00 +0000711 if (blocks_indirect > 0)
712 VG_(message)(Vg_UserMsg, " indirectly lost: %d bytes in %d blocks.",
713 MAC_(bytes_indirect), blocks_indirect );
714 VG_(message)(Vg_UserMsg, " possibly lost: %d bytes in %d blocks.",
nethercote0f19bce2003-12-02 10:17:44 +0000715 MAC_(bytes_dubious), blocks_dubious );
716 VG_(message)(Vg_UserMsg, " still reachable: %d bytes in %d blocks.",
717 MAC_(bytes_reachable), blocks_reachable );
718 VG_(message)(Vg_UserMsg, " suppressed: %d bytes in %d blocks.",
719 MAC_(bytes_suppressed), blocks_suppressed );
njn6a329422005-03-12 20:38:13 +0000720 if (mode == LC_Summary && blocks_leaked > 0)
sewardjb5f6f512005-03-10 23:59:00 +0000721 VG_(message)(Vg_UserMsg,
722 "Use --leak-check=full to see details of leaked memory.");
723 else if (!MAC_(clo_show_reachable)) {
nethercote0f19bce2003-12-02 10:17:44 +0000724 VG_(message)(Vg_UserMsg,
725 "Reachable blocks (those to which a pointer was found) are not shown.");
726 VG_(message)(Vg_UserMsg,
727 "To see them, rerun with: --show-reachable=yes");
728 }
njn43c799e2003-04-08 00:08:52 +0000729 }
njn43c799e2003-04-08 00:08:52 +0000730
njn3e884182003-04-15 13:03:23 +0000731 VG_(free) ( lc_shadows );
sewardjb5f6f512005-03-10 23:59:00 +0000732 VG_(free) ( lc_markstack );
njn43c799e2003-04-08 00:08:52 +0000733}
734
735/*--------------------------------------------------------------------*/
736/*--- end mac_leakcheck.c ---*/
737/*--------------------------------------------------------------------*/
738