blob: fa93ab7b04b615708f097ec9b92be9528a104b54 [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
41#define ROUNDDN(p, a) ((Addr)(p) & ~((a)-1))
42#define ROUNDUP(p, a) ROUNDDN((p)+(a)-1, (a))
43#define PGROUNDDN(p) ROUNDDN(p, VKI_PAGE_SIZE)
44#define PGROUNDUP(p) ROUNDUP(p, VKI_PAGE_SIZE)
njn43c799e2003-04-08 00:08:52 +000045
46/*------------------------------------------------------------*/
47/*--- Low-level address-space scanning, for the leak ---*/
48/*--- detector. ---*/
49/*------------------------------------------------------------*/
50
51static
52jmp_buf memscan_jmpbuf;
53
54
55static
njn695c16e2005-03-27 03:40:28 +000056void scan_all_valid_memory_catcher ( Int sigNo, Addr addr )
njn43c799e2003-04-08 00:08:52 +000057{
sewardjb5f6f512005-03-10 23:59:00 +000058 if (0)
59 VG_(printf)("OUCH! sig=%d addr=%p\n", sigNo, addr);
60 if (sigNo == VKI_SIGSEGV || sigNo == VKI_SIGBUS)
61 __builtin_longjmp(memscan_jmpbuf, 1);
njn43c799e2003-04-08 00:08:52 +000062}
63
64/*------------------------------------------------------------*/
65/*--- Detecting leaked (unreachable) malloc'd blocks. ---*/
66/*------------------------------------------------------------*/
67
68/* A block is either
69 -- Proper-ly reached; a pointer to its start has been found
70 -- Interior-ly reached; only an interior pointer to it has been found
71 -- Unreached; so far, no pointers to any part of it have been found.
sewardjb5f6f512005-03-10 23:59:00 +000072 -- IndirectLeak; leaked, but referred to by another leaked block
njn43c799e2003-04-08 00:08:52 +000073*/
sewardjb5f6f512005-03-10 23:59:00 +000074typedef enum {
75 Unreached,
76 IndirectLeak,
77 Interior,
78 Proper
79 } Reachedness;
80
81/* An entry in the mark stack */
82typedef struct {
83 Int next:30; /* Index of next in mark stack */
84 UInt state:2; /* Reachedness */
85 SizeT indirect; /* if Unreached, how much is unreachable from here */
86} MarkStack;
njn43c799e2003-04-08 00:08:52 +000087
88/* A block record, used for generating err msgs. */
89typedef
90 struct _LossRecord {
91 struct _LossRecord* next;
92 /* Where these lost blocks were allocated. */
93 ExeContext* allocated_at;
94 /* Their reachability. */
95 Reachedness loss_mode;
96 /* Number of blocks and total # bytes involved. */
97 UInt total_bytes;
sewardjb5f6f512005-03-10 23:59:00 +000098 UInt indirect_bytes;
njn43c799e2003-04-08 00:08:52 +000099 UInt num_blocks;
100 }
101 LossRecord;
102
njn02977032005-05-17 04:00:11 +0000103/* The 'extra' struct for leak errors. */
104typedef struct {
105 UInt n_this_record;
106 UInt n_total_records;
107 LossRecord* lossRecord;
108} LeakExtra;
njn43c799e2003-04-08 00:08:52 +0000109
110/* Find the i such that ptr points at or inside the block described by
111 shadows[i]. Return -1 if none found. This assumes that shadows[]
112 has been sorted on the ->data field. */
113
sewardjb5f6f512005-03-10 23:59:00 +0000114#if VG_DEBUG_LEAKCHECK
njn43c799e2003-04-08 00:08:52 +0000115/* Used to sanity-check the fast binary-search mechanism. */
116static
njn3e884182003-04-15 13:03:23 +0000117Int find_shadow_for_OLD ( Addr ptr,
118 MAC_Chunk** shadows,
119 Int n_shadows )
njn43c799e2003-04-08 00:08:52 +0000120
121{
122 Int i;
123 Addr a_lo, a_hi;
124 PROF_EVENT(70);
125 for (i = 0; i < n_shadows; i++) {
126 PROF_EVENT(71);
127 a_lo = shadows[i]->data;
sewardjb5f6f512005-03-10 23:59:00 +0000128 a_hi = ((Addr)shadows[i]->data) + shadows[i]->size;
njn43c799e2003-04-08 00:08:52 +0000129 if (a_lo <= ptr && ptr <= a_hi)
130 return i;
131 }
132 return -1;
133}
134#endif
135
136
137static
njn3e884182003-04-15 13:03:23 +0000138Int find_shadow_for ( Addr ptr,
139 MAC_Chunk** shadows,
140 Int n_shadows )
njn43c799e2003-04-08 00:08:52 +0000141{
142 Addr a_mid_lo, a_mid_hi;
143 Int lo, mid, hi, retVal;
144 /* VG_(printf)("find shadow for %p = ", ptr); */
145 retVal = -1;
146 lo = 0;
147 hi = n_shadows-1;
148 while (True) {
njn3e884182003-04-15 13:03:23 +0000149 /* invariant: current unsearched space is from lo to hi, inclusive. */
njn43c799e2003-04-08 00:08:52 +0000150 if (lo > hi) break; /* not found */
151
152 mid = (lo + hi) / 2;
njn3e884182003-04-15 13:03:23 +0000153 a_mid_lo = shadows[mid]->data;
sewardjb5f6f512005-03-10 23:59:00 +0000154 a_mid_hi = shadows[mid]->data + shadows[mid]->size;
njn43c799e2003-04-08 00:08:52 +0000155
156 if (ptr < a_mid_lo) {
157 hi = mid-1;
158 continue;
159 }
160 if (ptr > a_mid_hi) {
161 lo = mid+1;
162 continue;
163 }
sewardj76754cf2005-03-14 00:14:04 +0000164 tl_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
njn43c799e2003-04-08 00:08:52 +0000165 retVal = mid;
166 break;
167 }
168
sewardjb5f6f512005-03-10 23:59:00 +0000169# if VG_DEBUG_LEAKCHECK
sewardj76754cf2005-03-14 00:14:04 +0000170 tl_assert(retVal == find_shadow_for_OLD ( ptr, shadows, n_shadows ));
njn43c799e2003-04-08 00:08:52 +0000171# endif
172 /* VG_(printf)("%d\n", retVal); */
173 return retVal;
174}
175
176/* Globals, for the following callback used by VG_(detect_memory_leaks). */
njn3e884182003-04-15 13:03:23 +0000177static MAC_Chunk** lc_shadows;
178static Int lc_n_shadows;
sewardjb5f6f512005-03-10 23:59:00 +0000179static MarkStack* lc_markstack;
180static Int lc_markstack_top;
njn3e884182003-04-15 13:03:23 +0000181static Addr lc_min_mallocd_addr;
182static Addr lc_max_mallocd_addr;
sewardjb5f6f512005-03-10 23:59:00 +0000183static SizeT lc_scanned;
njn43c799e2003-04-08 00:08:52 +0000184
sewardj05fe85e2005-04-27 22:46:36 +0000185static Bool (*lc_is_within_valid_secondary) (Addr addr);
186static Bool (*lc_is_valid_aligned_word) (Addr addr);
sewardjb5f6f512005-03-10 23:59:00 +0000187
sewardj71bc3cb2005-05-19 00:25:45 +0000188static const HChar* str_lossmode ( Reachedness lossmode )
njn43c799e2003-04-08 00:08:52 +0000189{
sewardj71bc3cb2005-05-19 00:25:45 +0000190 const HChar *loss = "?";
191 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 return loss;
njn43c799e2003-04-08 00:08:52 +0000198}
199
sewardj71bc3cb2005-05-19 00:25:45 +0000200static const HChar* xml_kind ( Reachedness lossmode )
201{
202 const HChar *loss = "?";
203 switch (lossmode) {
204 case Unreached: loss = "Leak_DefinitelyLost"; break;
205 case IndirectLeak: loss = "Leak_IndirectlyLost"; break;
206 case Interior: loss = "Leak_PossiblyLost"; break;
207 case Proper: loss = "Leak_StillReachable"; break;
208 }
209 return loss;
210}
211
212
njn43c799e2003-04-08 00:08:52 +0000213/* Used for printing leak errors, avoids exposing the LossRecord type (which
214 comes in as void*, requiring a cast. */
njn02977032005-05-17 04:00:11 +0000215void MAC_(pp_LeakError)(void* vextra)
njn43c799e2003-04-08 00:08:52 +0000216{
sewardj71bc3cb2005-05-19 00:25:45 +0000217 HChar* xpre = VG_(clo_xml) ? " <what>" : "";
218 HChar* xpost = VG_(clo_xml) ? "</what>" : "";
219
njn02977032005-05-17 04:00:11 +0000220 LeakExtra* extra = (LeakExtra*)vextra;
221 LossRecord* l = extra->lossRecord;
222 const Char *loss = str_lossmode(l->loss_mode);
njn43c799e2003-04-08 00:08:52 +0000223
sewardj71bc3cb2005-05-19 00:25:45 +0000224 if (VG_(clo_xml)) {
225 VG_(message)(Vg_UserMsg, " <kind>%s</kind>", xml_kind(l->loss_mode));
226 } else {
227 VG_(message)(Vg_UserMsg, "");
228 }
229
sewardjb5f6f512005-03-10 23:59:00 +0000230 if (l->indirect_bytes) {
231 VG_(message)(Vg_UserMsg,
sewardj71bc3cb2005-05-19 00:25:45 +0000232 "%s%d (%d direct, %d indirect) bytes in %d blocks"
233 " are %s in loss record %d of %d%s",
234 xpre,
235 l->total_bytes + l->indirect_bytes,
236 l->total_bytes, l->indirect_bytes, l->num_blocks,
237 loss, extra->n_this_record, extra->n_total_records,
238 xpost
239 );
240 if (VG_(clo_xml)) {
241 VG_(message)(Vg_UserMsg, " <leakedbytes>%d</leakedbytes>",
242 l->total_bytes + l->indirect_bytes);
243 VG_(message)(Vg_UserMsg, " <leakedblocks>%d</leakedblocks>",
244 l->num_blocks);
245 }
sewardjb5f6f512005-03-10 23:59:00 +0000246 } else {
sewardj71bc3cb2005-05-19 00:25:45 +0000247 VG_(message)(
248 Vg_UserMsg,
249 "%s%d bytes in %d blocks are %s in loss record %d of %d%s",
250 xpre,
251 l->total_bytes, l->num_blocks,
252 loss, extra->n_this_record, extra->n_total_records,
253 xpost
254 );
255 if (VG_(clo_xml)) {
256 VG_(message)(Vg_UserMsg, " <leakedbytes>%d</leakedbytes>",
257 l->total_bytes);
258 VG_(message)(Vg_UserMsg, " <leakedblocks>%d</leakedblocks>",
259 l->num_blocks);
260 }
sewardjb5f6f512005-03-10 23:59:00 +0000261 }
njn43c799e2003-04-08 00:08:52 +0000262 VG_(pp_ExeContext)(l->allocated_at);
263}
264
njne8b5c052003-07-22 22:03:58 +0000265Int MAC_(bytes_leaked) = 0;
sewardjb5f6f512005-03-10 23:59:00 +0000266Int MAC_(bytes_indirect) = 0;
njne8b5c052003-07-22 22:03:58 +0000267Int MAC_(bytes_dubious) = 0;
268Int MAC_(bytes_reachable) = 0;
269Int MAC_(bytes_suppressed) = 0;
njn47363ab2003-04-21 13:24:40 +0000270
njn06072ec2003-09-30 15:35:13 +0000271static Int lc_compar(void* n1, void* n2)
272{
273 MAC_Chunk* mc1 = *(MAC_Chunk**)n1;
274 MAC_Chunk* mc2 = *(MAC_Chunk**)n2;
275 return (mc1->data < mc2->data ? -1 : 1);
276}
277
sewardjb5f6f512005-03-10 23:59:00 +0000278/* If ptr is pointing to a heap-allocated block which hasn't been seen
279 before, push it onto the mark stack. Clique is the index of the
280 clique leader; -1 if none. */
281static void _lc_markstack_push(Addr ptr, Int clique)
282{
283 Int sh_no;
284
285 if (!VG_(is_client_addr)(ptr)) /* quick filter */
286 return;
287
288 sh_no = find_shadow_for(ptr, lc_shadows, lc_n_shadows);
289
290 if (VG_DEBUG_LEAKCHECK)
291 VG_(printf)("ptr=%p -> block %d\n", ptr, sh_no);
292
293 if (sh_no == -1)
294 return;
295
sewardj76754cf2005-03-14 00:14:04 +0000296 tl_assert(sh_no >= 0 && sh_no < lc_n_shadows);
297 tl_assert(ptr <= lc_shadows[sh_no]->data + lc_shadows[sh_no]->size);
sewardjb5f6f512005-03-10 23:59:00 +0000298
299 if (lc_markstack[sh_no].state == Unreached) {
300 if (0)
301 VG_(printf)("pushing %p-%p\n", lc_shadows[sh_no]->data,
302 lc_shadows[sh_no]->data + lc_shadows[sh_no]->size);
303
sewardj76754cf2005-03-14 00:14:04 +0000304 tl_assert(lc_markstack[sh_no].next == -1);
sewardjb5f6f512005-03-10 23:59:00 +0000305 lc_markstack[sh_no].next = lc_markstack_top;
306 lc_markstack_top = sh_no;
307 }
308
309 if (clique != -1) {
310 if (0)
311 VG_(printf)("mopup: %d: %p is %d\n",
312 sh_no, lc_shadows[sh_no]->data, lc_markstack[sh_no].state);
313
314 /* An unmarked block - add it to the clique. Add its size to
315 the clique-leader's indirect size. If the new block was
316 itself a clique leader, it isn't any more, so add its
317 indirect to the new clique leader.
318
319 If this block *is* the clique leader, it means this is a
320 cyclic structure, so none of this applies. */
321 if (lc_markstack[sh_no].state == Unreached) {
322 lc_markstack[sh_no].state = IndirectLeak;
323
324 if (sh_no != clique) {
325 if (VG_DEBUG_CLIQUE) {
326 if (lc_markstack[sh_no].indirect)
327 VG_(printf)(" clique %d joining clique %d adding %d+%d bytes\n",
328 sh_no, clique,
329 lc_shadows[sh_no]->size, lc_markstack[sh_no].indirect);
330 else
331 VG_(printf)(" %d joining %d adding %d\n",
332 sh_no, clique, lc_shadows[sh_no]->size);
333 }
334
335 lc_markstack[clique].indirect += lc_shadows[sh_no]->size;
336 lc_markstack[clique].indirect += lc_markstack[sh_no].indirect;
337 lc_markstack[sh_no].indirect = 0; /* shouldn't matter */
338 }
339 }
340 } else if (ptr == lc_shadows[sh_no]->data) {
341 lc_markstack[sh_no].state = Proper;
342 } else {
343 if (lc_markstack[sh_no].state == Unreached)
344 lc_markstack[sh_no].state = Interior;
345 }
346}
347
348static void lc_markstack_push(Addr ptr)
349{
350 _lc_markstack_push(ptr, -1);
351}
352
353/* Return the top of the mark stack, if any. */
354static Int lc_markstack_pop(void)
355{
356 Int ret = lc_markstack_top;
357
358 if (ret != -1) {
359 lc_markstack_top = lc_markstack[ret].next;
360 lc_markstack[ret].next = -1;
361 }
362
363 return ret;
364}
365
sewardj45d94cc2005-04-20 14:44:11 +0000366
sewardjb5f6f512005-03-10 23:59:00 +0000367/* Scan a block of memory between [start, start+len). This range may
368 be bogus, inaccessable, or otherwise strange; we deal with it.
369
370 If clique != -1, it means we're gathering leaked memory into
371 cliques, and clique is the index of the current clique leader. */
372static void _lc_scan_memory(Addr start, SizeT len, Int clique)
373{
374 Addr ptr = ROUNDUP(start, sizeof(Addr));
375 Addr end = ROUNDDN(start+len, sizeof(Addr));
376 vki_sigset_t sigmask;
377
378 if (VG_DEBUG_LEAKCHECK)
379 VG_(printf)("scan %p-%p\n", start, len);
380 VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &sigmask);
njn695c16e2005-03-27 03:40:28 +0000381 VG_(set_fault_catcher)(scan_all_valid_memory_catcher);
sewardjb5f6f512005-03-10 23:59:00 +0000382
383 lc_scanned += end-ptr;
384
385 if (!VG_(is_client_addr)(ptr) ||
386 !VG_(is_addressable)(ptr, sizeof(Addr), VKI_PROT_READ))
387 ptr = PGROUNDUP(ptr+1); /* first page bad */
388
sewardj05fe85e2005-04-27 22:46:36 +0000389 while (ptr < end) {
sewardjb5f6f512005-03-10 23:59:00 +0000390 Addr addr;
391
392 /* Skip invalid chunks */
sewardj05fe85e2005-04-27 22:46:36 +0000393 if (!(*lc_is_within_valid_secondary)(ptr)) {
sewardjb5f6f512005-03-10 23:59:00 +0000394 ptr = ROUNDUP(ptr+1, SECONDARY_SIZE);
395 continue;
396 }
397
398 /* Look to see if this page seems reasonble */
399 if ((ptr % VKI_PAGE_SIZE) == 0) {
400 if (!VG_(is_client_addr)(ptr) ||
401 !VG_(is_addressable)(ptr, sizeof(Addr), VKI_PROT_READ))
402 ptr += VKI_PAGE_SIZE; /* bad page - skip it */
403 }
404
405 if (__builtin_setjmp(memscan_jmpbuf) == 0) {
sewardj05fe85e2005-04-27 22:46:36 +0000406 if ((*lc_is_valid_aligned_word)(ptr)) {
sewardjb5f6f512005-03-10 23:59:00 +0000407 addr = *(Addr *)ptr;
408 _lc_markstack_push(addr, clique);
409 } else if (0 && VG_DEBUG_LEAKCHECK)
410 VG_(printf)("%p not valid\n", ptr);
411 ptr += sizeof(Addr);
412 } else {
413 /* We need to restore the signal mask, because we were
414 longjmped out of a signal handler. */
415 VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL);
416
417 ptr = PGROUNDUP(ptr+1); /* bad page - skip it */
418 }
419 }
420
421 VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL);
422 VG_(set_fault_catcher)(NULL);
423}
424
sewardj45d94cc2005-04-20 14:44:11 +0000425
sewardjb5f6f512005-03-10 23:59:00 +0000426static void lc_scan_memory(Addr start, SizeT len)
427{
428 _lc_scan_memory(start, len, -1);
429}
430
431/* Process the mark stack until empty. If mopup is true, then we're
432 actually gathering leaked blocks, so they should be marked
433 IndirectLeak. */
434static void lc_do_leakcheck(Int clique)
435{
436 Int top;
437
438 while((top = lc_markstack_pop()) != -1) {
sewardj76754cf2005-03-14 00:14:04 +0000439 tl_assert(top >= 0 && top < lc_n_shadows);
440 tl_assert(lc_markstack[top].state != Unreached);
sewardjb5f6f512005-03-10 23:59:00 +0000441
442 _lc_scan_memory(lc_shadows[top]->data, lc_shadows[top]->size, clique);
443 }
444}
445
446static Int blocks_leaked;
447static Int blocks_indirect;
448static Int blocks_dubious;
449static Int blocks_reachable;
450static Int blocks_suppressed;
451
njnb8dca862005-03-14 02:42:44 +0000452static void full_report(ThreadId tid)
sewardjb5f6f512005-03-10 23:59:00 +0000453{
454 Int i;
455 Int n_lossrecords;
456 LossRecord* errlist;
457 LossRecord* p;
458 Bool is_suppressed;
njn02977032005-05-17 04:00:11 +0000459 LeakExtra leak_extra;
sewardjb5f6f512005-03-10 23:59:00 +0000460
461 /* Go through and group lost structures into cliques. For each
462 Unreached block, push it onto the mark stack, and find all the
463 blocks linked to it. These are marked IndirectLeak, and their
464 size is added to the clique leader's indirect size. If one of
465 the found blocks was itself a clique leader (from a previous
466 pass), then the cliques are merged. */
467 for (i = 0; i < lc_n_shadows; i++) {
468 if (VG_DEBUG_CLIQUE)
469 VG_(printf)("cliques: %d at %p -> %s\n",
njn02977032005-05-17 04:00:11 +0000470 i, lc_shadows[i]->data, str_lossmode(lc_markstack[i].state));
sewardjb5f6f512005-03-10 23:59:00 +0000471 if (lc_markstack[i].state != Unreached)
472 continue;
473
sewardj76754cf2005-03-14 00:14:04 +0000474 tl_assert(lc_markstack_top == -1);
sewardjb5f6f512005-03-10 23:59:00 +0000475
476 if (VG_DEBUG_CLIQUE)
477 VG_(printf)("%d: gathering clique %p\n", i, lc_shadows[i]->data);
478
479 _lc_markstack_push(lc_shadows[i]->data, i);
480
481 lc_do_leakcheck(i);
482
sewardj76754cf2005-03-14 00:14:04 +0000483 tl_assert(lc_markstack_top == -1);
484 tl_assert(lc_markstack[i].state == IndirectLeak);
sewardjb5f6f512005-03-10 23:59:00 +0000485
486 lc_markstack[i].state = Unreached; /* Return to unreached state,
487 to indicate its a clique
488 leader */
489 }
490
491 /* Common up the lost blocks so we can print sensible error messages. */
492 n_lossrecords = 0;
493 errlist = NULL;
494 for (i = 0; i < lc_n_shadows; i++) {
495 ExeContext* where = lc_shadows[i]->where;
496
497 for (p = errlist; p != NULL; p = p->next) {
498 if (p->loss_mode == lc_markstack[i].state
499 && VG_(eq_ExeContext) ( MAC_(clo_leak_resolution),
500 p->allocated_at,
501 where) ) {
502 break;
503 }
504 }
505 if (p != NULL) {
506 p->num_blocks ++;
507 p->total_bytes += lc_shadows[i]->size;
508 p->indirect_bytes += lc_markstack[i].indirect;
509 } else {
510 n_lossrecords ++;
511 p = VG_(malloc)(sizeof(LossRecord));
512 p->loss_mode = lc_markstack[i].state;
513 p->allocated_at = where;
514 p->total_bytes = lc_shadows[i]->size;
515 p->indirect_bytes = lc_markstack[i].indirect;
516 p->num_blocks = 1;
517 p->next = errlist;
518 errlist = p;
519 }
520 }
521
522 /* Print out the commoned-up blocks and collect summary stats. */
523 for (i = 0; i < n_lossrecords; i++) {
524 Bool print_record;
525 LossRecord* p_min = NULL;
526 UInt n_min = 0xFFFFFFFF;
527 for (p = errlist; p != NULL; p = p->next) {
528 if (p->num_blocks > 0 && p->total_bytes < n_min) {
529 n_min = p->total_bytes + p->indirect_bytes;
530 p_min = p;
531 }
532 }
sewardj76754cf2005-03-14 00:14:04 +0000533 tl_assert(p_min != NULL);
sewardjb5f6f512005-03-10 23:59:00 +0000534
535 /* Ok to have tst==NULL; it's only used if --gdb-attach=yes, and
536 we disallow that when --leak-check=yes.
537
njn02977032005-05-17 04:00:11 +0000538 Prints the error if not suppressed, unless it's reachable (Proper
539 or IndirectLeak) and --show-reachable=no */
sewardjb5f6f512005-03-10 23:59:00 +0000540
541 print_record = ( MAC_(clo_show_reachable) ||
njn02977032005-05-17 04:00:11 +0000542 Unreached == p_min->loss_mode ||
543 Interior == p_min->loss_mode );
544
545 // Nb: because VG_(unique_error) does all the error processing
546 // immediately, and doesn't save the error, leakExtra can be
547 // stack-allocated.
548 leak_extra.n_this_record = i+1;
549 leak_extra.n_total_records = n_lossrecords;
550 leak_extra.lossRecord = p_min;
sewardjb5f6f512005-03-10 23:59:00 +0000551 is_suppressed =
njn02977032005-05-17 04:00:11 +0000552 VG_(unique_error) ( tid, LeakErr, /*Addr*/0, /*s*/NULL,
553 /*extra*/&leak_extra,
554 /*where*/p_min->allocated_at, print_record,
sewardjb5f6f512005-03-10 23:59:00 +0000555 /*allow_GDB_attach*/False, /*count_error*/False );
556
557 if (is_suppressed) {
558 blocks_suppressed += p_min->num_blocks;
559 MAC_(bytes_suppressed) += p_min->total_bytes;
560
561 } else if (Unreached == p_min->loss_mode) {
562 blocks_leaked += p_min->num_blocks;
563 MAC_(bytes_leaked) += p_min->total_bytes;
564
565 } else if (IndirectLeak == p_min->loss_mode) {
566 blocks_indirect += p_min->num_blocks;
567 MAC_(bytes_indirect)+= p_min->total_bytes;
568
569 } else if (Interior == p_min->loss_mode) {
570 blocks_dubious += p_min->num_blocks;
571 MAC_(bytes_dubious) += p_min->total_bytes;
572
573 } else if (Proper == p_min->loss_mode) {
574 blocks_reachable += p_min->num_blocks;
575 MAC_(bytes_reachable) += p_min->total_bytes;
576
577 } else {
sewardj76754cf2005-03-14 00:14:04 +0000578 VG_(tool_panic)("generic_detect_memory_leaks: unknown loss mode");
sewardjb5f6f512005-03-10 23:59:00 +0000579 }
580 p_min->num_blocks = 0;
581 }
582}
583
584/* Compute a quick summary of the leak check. */
585static void make_summary()
586{
587 Int i;
588
589 for(i = 0; i < lc_n_shadows; i++) {
590 SizeT size = lc_shadows[i]->size;
591
592 switch(lc_markstack[i].state) {
593 case Unreached:
594 blocks_leaked++;
595 MAC_(bytes_leaked) += size;
596 break;
597
598 case Proper:
599 blocks_reachable++;
600 MAC_(bytes_reachable) += size;
601 break;
602
603 case Interior:
604 blocks_dubious++;
605 MAC_(bytes_dubious) += size;
606 break;
607
608 case IndirectLeak: /* shouldn't happen */
609 blocks_indirect++;
610 MAC_(bytes_indirect) += size;
611 break;
612 }
613 }
614}
615
njn43c799e2003-04-08 00:08:52 +0000616/* Top level entry point to leak detector. Call here, passing in
617 suitable address-validating functions (see comment at top of
njn695c16e2005-03-27 03:40:28 +0000618 scan_all_valid_memory above). All this is to avoid duplication
nethercote996901a2004-08-03 13:29:09 +0000619 of the leak-detection code for Memcheck and Addrcheck.
620 Also pass in a tool-specific function to extract the .where field
njn43c799e2003-04-08 00:08:52 +0000621 for allocated blocks, an indication of the resolution wanted for
622 distinguishing different allocation points, and whether or not
623 reachable blocks should be shown.
624*/
625void MAC_(do_detect_memory_leaks) (
njnb8dca862005-03-14 02:42:44 +0000626 ThreadId tid, LeakCheckMode mode,
sewardj05fe85e2005-04-27 22:46:36 +0000627 Bool (*is_within_valid_secondary) ( Addr ),
628 Bool (*is_valid_aligned_word) ( Addr )
njn43c799e2003-04-08 00:08:52 +0000629)
630{
njnb8dca862005-03-14 02:42:44 +0000631 Int i;
njn43c799e2003-04-08 00:08:52 +0000632
sewardj76754cf2005-03-14 00:14:04 +0000633 tl_assert(mode != LC_Off);
njn43c799e2003-04-08 00:08:52 +0000634
njn06072ec2003-09-30 15:35:13 +0000635 /* VG_(HT_to_array) allocates storage for shadows */
636 lc_shadows = (MAC_Chunk**)VG_(HT_to_array)( MAC_(malloc_list),
637 &lc_n_shadows );
638
639 /* Sort the array. */
640 VG_(ssort)((void*)lc_shadows, lc_n_shadows, sizeof(VgHashNode*), lc_compar);
641
642 /* Sanity check; assert that the blocks are now in order */
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+1]->data);
njn06072ec2003-09-30 15:35:13 +0000645 }
njn3e884182003-04-15 13:03:23 +0000646
647 /* Sanity check -- make sure they don't overlap */
648 for (i = 0; i < lc_n_shadows-1; i++) {
sewardj76754cf2005-03-14 00:14:04 +0000649 tl_assert( lc_shadows[i]->data + lc_shadows[i]->size
njn3e884182003-04-15 13:03:23 +0000650 < lc_shadows[i+1]->data );
651 }
652
653 if (lc_n_shadows == 0) {
sewardj76754cf2005-03-14 00:14:04 +0000654 tl_assert(lc_shadows == NULL);
sewardj71bc3cb2005-05-19 00:25:45 +0000655 if (VG_(clo_verbosity) >= 1 && !VG_(clo_xml)) {
sewardj37d06f22003-09-17 21:48:26 +0000656 VG_(message)(Vg_UserMsg,
657 "No malloc'd blocks -- no leaks are possible.");
658 }
njn43c799e2003-04-08 00:08:52 +0000659 return;
660 }
661
sewardj71bc3cb2005-05-19 00:25:45 +0000662 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
nethercote0f19bce2003-12-02 10:17:44 +0000663 VG_(message)(Vg_UserMsg,
664 "searching for pointers to %d not-freed blocks.",
665 lc_n_shadows );
njn43c799e2003-04-08 00:08:52 +0000666
njn3e884182003-04-15 13:03:23 +0000667 lc_min_mallocd_addr = lc_shadows[0]->data;
668 lc_max_mallocd_addr = lc_shadows[lc_n_shadows-1]->data
sewardjb5f6f512005-03-10 23:59:00 +0000669 + lc_shadows[lc_n_shadows-1]->size;
njn43c799e2003-04-08 00:08:52 +0000670
sewardjb5f6f512005-03-10 23:59:00 +0000671 lc_markstack = VG_(malloc)( lc_n_shadows * sizeof(*lc_markstack) );
672 for (i = 0; i < lc_n_shadows; i++) {
673 lc_markstack[i].next = -1;
674 lc_markstack[i].state = Unreached;
675 lc_markstack[i].indirect = 0;
676 }
677 lc_markstack_top = -1;
njn43c799e2003-04-08 00:08:52 +0000678
sewardj05fe85e2005-04-27 22:46:36 +0000679 lc_is_within_valid_secondary = is_within_valid_secondary;
680 lc_is_valid_aligned_word = is_valid_aligned_word;
sewardjb5f6f512005-03-10 23:59:00 +0000681
682 lc_scanned = 0;
683
684 /* Do the scan of memory, pushing any pointers onto the mark stack */
685 VG_(find_root_memory)(lc_scan_memory);
686
687 /* Push registers onto mark stack */
688 VG_(mark_from_registers)(lc_markstack_push);
689
690 /* Keep walking the heap until everything is found */
691 lc_do_leakcheck(-1);
njn43c799e2003-04-08 00:08:52 +0000692
sewardj71bc3cb2005-05-19 00:25:45 +0000693 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
sewardjb5f6f512005-03-10 23:59:00 +0000694 VG_(message)(Vg_UserMsg, "checked %d bytes.", lc_scanned);
njn43c799e2003-04-08 00:08:52 +0000695
njne8b5c052003-07-22 22:03:58 +0000696 blocks_leaked = MAC_(bytes_leaked) = 0;
sewardjb5f6f512005-03-10 23:59:00 +0000697 blocks_indirect = MAC_(bytes_indirect) = 0;
njne8b5c052003-07-22 22:03:58 +0000698 blocks_dubious = MAC_(bytes_dubious) = 0;
699 blocks_reachable = MAC_(bytes_reachable) = 0;
700 blocks_suppressed = MAC_(bytes_suppressed) = 0;
njn43c799e2003-04-08 00:08:52 +0000701
sewardjb5f6f512005-03-10 23:59:00 +0000702 if (mode == LC_Full)
njnb8dca862005-03-14 02:42:44 +0000703 full_report(tid);
sewardjb5f6f512005-03-10 23:59:00 +0000704 else
705 make_summary();
njn43c799e2003-04-08 00:08:52 +0000706
sewardj71bc3cb2005-05-19 00:25:45 +0000707 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) {
nethercote0f19bce2003-12-02 10:17:44 +0000708 VG_(message)(Vg_UserMsg, "");
709 VG_(message)(Vg_UserMsg, "LEAK SUMMARY:");
710 VG_(message)(Vg_UserMsg, " definitely lost: %d bytes in %d blocks.",
711 MAC_(bytes_leaked), blocks_leaked );
sewardjb5f6f512005-03-10 23:59:00 +0000712 if (blocks_indirect > 0)
713 VG_(message)(Vg_UserMsg, " indirectly lost: %d bytes in %d blocks.",
714 MAC_(bytes_indirect), blocks_indirect );
715 VG_(message)(Vg_UserMsg, " possibly lost: %d bytes in %d blocks.",
nethercote0f19bce2003-12-02 10:17:44 +0000716 MAC_(bytes_dubious), blocks_dubious );
717 VG_(message)(Vg_UserMsg, " still reachable: %d bytes in %d blocks.",
718 MAC_(bytes_reachable), blocks_reachable );
719 VG_(message)(Vg_UserMsg, " suppressed: %d bytes in %d blocks.",
720 MAC_(bytes_suppressed), blocks_suppressed );
njn6a329422005-03-12 20:38:13 +0000721 if (mode == LC_Summary && blocks_leaked > 0)
sewardjb5f6f512005-03-10 23:59:00 +0000722 VG_(message)(Vg_UserMsg,
723 "Use --leak-check=full to see details of leaked memory.");
724 else if (!MAC_(clo_show_reachable)) {
nethercote0f19bce2003-12-02 10:17:44 +0000725 VG_(message)(Vg_UserMsg,
726 "Reachable blocks (those to which a pointer was found) are not shown.");
727 VG_(message)(Vg_UserMsg,
728 "To see them, rerun with: --show-reachable=yes");
729 }
njn43c799e2003-04-08 00:08:52 +0000730 }
njn43c799e2003-04-08 00:08:52 +0000731
njn3e884182003-04-15 13:03:23 +0000732 VG_(free) ( lc_shadows );
sewardjb5f6f512005-03-10 23:59:00 +0000733 VG_(free) ( lc_markstack );
njn43c799e2003-04-08 00:08:52 +0000734}
735
736/*--------------------------------------------------------------------*/
737/*--- end mac_leakcheck.c ---*/
738/*--------------------------------------------------------------------*/
739