blob: f8bda97a4991fbf0ac1844d69e767f10e02b9516 [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"
njn4802b382005-06-11 04:58:29 +000035#include "pub_tool_aspacemgr.h"
njn97405b22005-06-02 03:39:33 +000036#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000037#include "pub_tool_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000038#include "pub_tool_libcprint.h"
njnde62cbf2005-06-10 22:08:14 +000039#include "pub_tool_libcsignal.h"
njn6ace3ea2005-06-17 03:06:27 +000040#include "pub_tool_machine.h"
njn73c51342005-06-18 15:18:15 +000041#include "pub_tool_signals.h"
njn43c799e2003-04-08 00:08:52 +000042
43/* Define to debug the memory-leak-detector. */
sewardjb5f6f512005-03-10 23:59:00 +000044#define VG_DEBUG_LEAKCHECK 0
45#define VG_DEBUG_CLIQUE 0
46
njn43c799e2003-04-08 00:08:52 +000047/*------------------------------------------------------------*/
48/*--- Low-level address-space scanning, for the leak ---*/
49/*--- detector. ---*/
50/*------------------------------------------------------------*/
51
52static
53jmp_buf memscan_jmpbuf;
54
55
56static
njn695c16e2005-03-27 03:40:28 +000057void scan_all_valid_memory_catcher ( Int sigNo, Addr addr )
njn43c799e2003-04-08 00:08:52 +000058{
sewardjb5f6f512005-03-10 23:59:00 +000059 if (0)
60 VG_(printf)("OUCH! sig=%d addr=%p\n", sigNo, addr);
61 if (sigNo == VKI_SIGSEGV || sigNo == VKI_SIGBUS)
62 __builtin_longjmp(memscan_jmpbuf, 1);
njn43c799e2003-04-08 00:08:52 +000063}
64
65/*------------------------------------------------------------*/
66/*--- Detecting leaked (unreachable) malloc'd blocks. ---*/
67/*------------------------------------------------------------*/
68
69/* A block is either
70 -- Proper-ly reached; a pointer to its start has been found
71 -- Interior-ly reached; only an interior pointer to it has been found
72 -- Unreached; so far, no pointers to any part of it have been found.
sewardjb5f6f512005-03-10 23:59:00 +000073 -- IndirectLeak; leaked, but referred to by another leaked block
njn43c799e2003-04-08 00:08:52 +000074*/
sewardjb5f6f512005-03-10 23:59:00 +000075typedef enum {
76 Unreached,
77 IndirectLeak,
78 Interior,
79 Proper
80 } Reachedness;
81
82/* An entry in the mark stack */
83typedef struct {
84 Int next:30; /* Index of next in mark stack */
85 UInt state:2; /* Reachedness */
86 SizeT indirect; /* if Unreached, how much is unreachable from here */
87} MarkStack;
njn43c799e2003-04-08 00:08:52 +000088
89/* A block record, used for generating err msgs. */
90typedef
91 struct _LossRecord {
92 struct _LossRecord* next;
93 /* Where these lost blocks were allocated. */
94 ExeContext* allocated_at;
95 /* Their reachability. */
96 Reachedness loss_mode;
97 /* Number of blocks and total # bytes involved. */
98 UInt total_bytes;
sewardjb5f6f512005-03-10 23:59:00 +000099 UInt indirect_bytes;
njn43c799e2003-04-08 00:08:52 +0000100 UInt num_blocks;
101 }
102 LossRecord;
103
njn02977032005-05-17 04:00:11 +0000104/* The 'extra' struct for leak errors. */
105typedef struct {
106 UInt n_this_record;
107 UInt n_total_records;
108 LossRecord* lossRecord;
109} LeakExtra;
njn43c799e2003-04-08 00:08:52 +0000110
111/* Find the i such that ptr points at or inside the block described by
112 shadows[i]. Return -1 if none found. This assumes that shadows[]
113 has been sorted on the ->data field. */
114
sewardjb5f6f512005-03-10 23:59:00 +0000115#if VG_DEBUG_LEAKCHECK
njn43c799e2003-04-08 00:08:52 +0000116/* Used to sanity-check the fast binary-search mechanism. */
117static
njn3e884182003-04-15 13:03:23 +0000118Int find_shadow_for_OLD ( Addr ptr,
119 MAC_Chunk** shadows,
120 Int n_shadows )
njn43c799e2003-04-08 00:08:52 +0000121
122{
123 Int i;
124 Addr a_lo, a_hi;
125 PROF_EVENT(70);
126 for (i = 0; i < n_shadows; i++) {
127 PROF_EVENT(71);
128 a_lo = shadows[i]->data;
sewardjb5f6f512005-03-10 23:59:00 +0000129 a_hi = ((Addr)shadows[i]->data) + shadows[i]->size;
njn43c799e2003-04-08 00:08:52 +0000130 if (a_lo <= ptr && ptr <= a_hi)
131 return i;
132 }
133 return -1;
134}
135#endif
136
137
138static
njn3e884182003-04-15 13:03:23 +0000139Int find_shadow_for ( Addr ptr,
140 MAC_Chunk** shadows,
141 Int n_shadows )
njn43c799e2003-04-08 00:08:52 +0000142{
143 Addr a_mid_lo, a_mid_hi;
144 Int lo, mid, hi, retVal;
145 /* VG_(printf)("find shadow for %p = ", ptr); */
146 retVal = -1;
147 lo = 0;
148 hi = n_shadows-1;
149 while (True) {
njn3e884182003-04-15 13:03:23 +0000150 /* invariant: current unsearched space is from lo to hi, inclusive. */
njn43c799e2003-04-08 00:08:52 +0000151 if (lo > hi) break; /* not found */
152
153 mid = (lo + hi) / 2;
njn3e884182003-04-15 13:03:23 +0000154 a_mid_lo = shadows[mid]->data;
sewardjb5f6f512005-03-10 23:59:00 +0000155 a_mid_hi = shadows[mid]->data + shadows[mid]->size;
njn43c799e2003-04-08 00:08:52 +0000156
157 if (ptr < a_mid_lo) {
158 hi = mid-1;
159 continue;
160 }
161 if (ptr > a_mid_hi) {
162 lo = mid+1;
163 continue;
164 }
sewardj76754cf2005-03-14 00:14:04 +0000165 tl_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
njn43c799e2003-04-08 00:08:52 +0000166 retVal = mid;
167 break;
168 }
169
sewardjb5f6f512005-03-10 23:59:00 +0000170# if VG_DEBUG_LEAKCHECK
sewardj76754cf2005-03-14 00:14:04 +0000171 tl_assert(retVal == find_shadow_for_OLD ( ptr, shadows, n_shadows ));
njn43c799e2003-04-08 00:08:52 +0000172# endif
173 /* VG_(printf)("%d\n", retVal); */
174 return retVal;
175}
176
177/* Globals, for the following callback used by VG_(detect_memory_leaks). */
njn3e884182003-04-15 13:03:23 +0000178static MAC_Chunk** lc_shadows;
179static Int lc_n_shadows;
sewardjb5f6f512005-03-10 23:59:00 +0000180static MarkStack* lc_markstack;
181static Int lc_markstack_top;
njn3e884182003-04-15 13:03:23 +0000182static Addr lc_min_mallocd_addr;
183static Addr lc_max_mallocd_addr;
sewardjb5f6f512005-03-10 23:59:00 +0000184static SizeT lc_scanned;
njn43c799e2003-04-08 00:08:52 +0000185
sewardj05fe85e2005-04-27 22:46:36 +0000186static Bool (*lc_is_within_valid_secondary) (Addr addr);
187static Bool (*lc_is_valid_aligned_word) (Addr addr);
sewardjb5f6f512005-03-10 23:59:00 +0000188
sewardj71bc3cb2005-05-19 00:25:45 +0000189static const HChar* str_lossmode ( Reachedness lossmode )
njn43c799e2003-04-08 00:08:52 +0000190{
sewardj71bc3cb2005-05-19 00:25:45 +0000191 const HChar *loss = "?";
192 switch (lossmode) {
193 case Unreached: loss = "definitely lost"; break;
194 case IndirectLeak: loss = "indirectly lost"; break;
195 case Interior: loss = "possibly lost"; break;
196 case Proper: loss = "still reachable"; break;
njn43c799e2003-04-08 00:08:52 +0000197 }
sewardjb5f6f512005-03-10 23:59:00 +0000198 return loss;
njn43c799e2003-04-08 00:08:52 +0000199}
200
sewardj71bc3cb2005-05-19 00:25:45 +0000201static const HChar* xml_kind ( Reachedness lossmode )
202{
203 const HChar *loss = "?";
204 switch (lossmode) {
205 case Unreached: loss = "Leak_DefinitelyLost"; break;
206 case IndirectLeak: loss = "Leak_IndirectlyLost"; break;
207 case Interior: loss = "Leak_PossiblyLost"; break;
208 case Proper: loss = "Leak_StillReachable"; break;
209 }
210 return loss;
211}
212
213
njn43c799e2003-04-08 00:08:52 +0000214/* Used for printing leak errors, avoids exposing the LossRecord type (which
215 comes in as void*, requiring a cast. */
njn02977032005-05-17 04:00:11 +0000216void MAC_(pp_LeakError)(void* vextra)
njn43c799e2003-04-08 00:08:52 +0000217{
sewardj71bc3cb2005-05-19 00:25:45 +0000218 HChar* xpre = VG_(clo_xml) ? " <what>" : "";
219 HChar* xpost = VG_(clo_xml) ? "</what>" : "";
220
njn02977032005-05-17 04:00:11 +0000221 LeakExtra* extra = (LeakExtra*)vextra;
222 LossRecord* l = extra->lossRecord;
223 const Char *loss = str_lossmode(l->loss_mode);
njn43c799e2003-04-08 00:08:52 +0000224
sewardj71bc3cb2005-05-19 00:25:45 +0000225 if (VG_(clo_xml)) {
226 VG_(message)(Vg_UserMsg, " <kind>%s</kind>", xml_kind(l->loss_mode));
227 } else {
228 VG_(message)(Vg_UserMsg, "");
229 }
230
sewardjb5f6f512005-03-10 23:59:00 +0000231 if (l->indirect_bytes) {
232 VG_(message)(Vg_UserMsg,
sewardj71bc3cb2005-05-19 00:25:45 +0000233 "%s%d (%d direct, %d indirect) bytes in %d blocks"
234 " are %s in loss record %d of %d%s",
235 xpre,
236 l->total_bytes + l->indirect_bytes,
237 l->total_bytes, l->indirect_bytes, l->num_blocks,
238 loss, extra->n_this_record, extra->n_total_records,
239 xpost
240 );
241 if (VG_(clo_xml)) {
242 VG_(message)(Vg_UserMsg, " <leakedbytes>%d</leakedbytes>",
243 l->total_bytes + l->indirect_bytes);
244 VG_(message)(Vg_UserMsg, " <leakedblocks>%d</leakedblocks>",
245 l->num_blocks);
246 }
sewardjb5f6f512005-03-10 23:59:00 +0000247 } else {
sewardj71bc3cb2005-05-19 00:25:45 +0000248 VG_(message)(
249 Vg_UserMsg,
250 "%s%d bytes in %d blocks are %s in loss record %d of %d%s",
251 xpre,
252 l->total_bytes, l->num_blocks,
253 loss, extra->n_this_record, extra->n_total_records,
254 xpost
255 );
256 if (VG_(clo_xml)) {
257 VG_(message)(Vg_UserMsg, " <leakedbytes>%d</leakedbytes>",
258 l->total_bytes);
259 VG_(message)(Vg_UserMsg, " <leakedblocks>%d</leakedblocks>",
260 l->num_blocks);
261 }
sewardjb5f6f512005-03-10 23:59:00 +0000262 }
njn43c799e2003-04-08 00:08:52 +0000263 VG_(pp_ExeContext)(l->allocated_at);
264}
265
njne8b5c052003-07-22 22:03:58 +0000266Int MAC_(bytes_leaked) = 0;
sewardjb5f6f512005-03-10 23:59:00 +0000267Int MAC_(bytes_indirect) = 0;
njne8b5c052003-07-22 22:03:58 +0000268Int MAC_(bytes_dubious) = 0;
269Int MAC_(bytes_reachable) = 0;
270Int MAC_(bytes_suppressed) = 0;
njn47363ab2003-04-21 13:24:40 +0000271
njn06072ec2003-09-30 15:35:13 +0000272static Int lc_compar(void* n1, void* n2)
273{
274 MAC_Chunk* mc1 = *(MAC_Chunk**)n1;
275 MAC_Chunk* mc2 = *(MAC_Chunk**)n2;
276 return (mc1->data < mc2->data ? -1 : 1);
277}
278
sewardjb5f6f512005-03-10 23:59:00 +0000279/* If ptr is pointing to a heap-allocated block which hasn't been seen
280 before, push it onto the mark stack. Clique is the index of the
281 clique leader; -1 if none. */
282static void _lc_markstack_push(Addr ptr, Int clique)
283{
284 Int sh_no;
285
286 if (!VG_(is_client_addr)(ptr)) /* quick filter */
287 return;
288
289 sh_no = find_shadow_for(ptr, lc_shadows, lc_n_shadows);
290
291 if (VG_DEBUG_LEAKCHECK)
292 VG_(printf)("ptr=%p -> block %d\n", ptr, sh_no);
293
294 if (sh_no == -1)
295 return;
296
sewardj76754cf2005-03-14 00:14:04 +0000297 tl_assert(sh_no >= 0 && sh_no < lc_n_shadows);
298 tl_assert(ptr <= lc_shadows[sh_no]->data + lc_shadows[sh_no]->size);
sewardjb5f6f512005-03-10 23:59:00 +0000299
300 if (lc_markstack[sh_no].state == Unreached) {
301 if (0)
302 VG_(printf)("pushing %p-%p\n", lc_shadows[sh_no]->data,
303 lc_shadows[sh_no]->data + lc_shadows[sh_no]->size);
304
sewardj76754cf2005-03-14 00:14:04 +0000305 tl_assert(lc_markstack[sh_no].next == -1);
sewardjb5f6f512005-03-10 23:59:00 +0000306 lc_markstack[sh_no].next = lc_markstack_top;
307 lc_markstack_top = sh_no;
308 }
309
310 if (clique != -1) {
311 if (0)
312 VG_(printf)("mopup: %d: %p is %d\n",
313 sh_no, lc_shadows[sh_no]->data, lc_markstack[sh_no].state);
314
315 /* An unmarked block - add it to the clique. Add its size to
316 the clique-leader's indirect size. If the new block was
317 itself a clique leader, it isn't any more, so add its
318 indirect to the new clique leader.
319
320 If this block *is* the clique leader, it means this is a
321 cyclic structure, so none of this applies. */
322 if (lc_markstack[sh_no].state == Unreached) {
323 lc_markstack[sh_no].state = IndirectLeak;
324
325 if (sh_no != clique) {
326 if (VG_DEBUG_CLIQUE) {
327 if (lc_markstack[sh_no].indirect)
328 VG_(printf)(" clique %d joining clique %d adding %d+%d bytes\n",
329 sh_no, clique,
330 lc_shadows[sh_no]->size, lc_markstack[sh_no].indirect);
331 else
332 VG_(printf)(" %d joining %d adding %d\n",
333 sh_no, clique, lc_shadows[sh_no]->size);
334 }
335
336 lc_markstack[clique].indirect += lc_shadows[sh_no]->size;
337 lc_markstack[clique].indirect += lc_markstack[sh_no].indirect;
338 lc_markstack[sh_no].indirect = 0; /* shouldn't matter */
339 }
340 }
341 } else if (ptr == lc_shadows[sh_no]->data) {
342 lc_markstack[sh_no].state = Proper;
343 } else {
344 if (lc_markstack[sh_no].state == Unreached)
345 lc_markstack[sh_no].state = Interior;
346 }
347}
348
349static void lc_markstack_push(Addr ptr)
350{
351 _lc_markstack_push(ptr, -1);
352}
353
354/* Return the top of the mark stack, if any. */
355static Int lc_markstack_pop(void)
356{
357 Int ret = lc_markstack_top;
358
359 if (ret != -1) {
360 lc_markstack_top = lc_markstack[ret].next;
361 lc_markstack[ret].next = -1;
362 }
363
364 return ret;
365}
366
sewardj45d94cc2005-04-20 14:44:11 +0000367
sewardjb5f6f512005-03-10 23:59:00 +0000368/* Scan a block of memory between [start, start+len). This range may
369 be bogus, inaccessable, or otherwise strange; we deal with it.
370
371 If clique != -1, it means we're gathering leaked memory into
372 cliques, and clique is the index of the current clique leader. */
373static void _lc_scan_memory(Addr start, SizeT len, Int clique)
374{
njn13bfd852005-06-02 03:52:53 +0000375 Addr ptr = VG_ROUNDUP(start, sizeof(Addr));
376 Addr end = VG_ROUNDDN(start+len, sizeof(Addr));
sewardjb5f6f512005-03-10 23:59:00 +0000377 vki_sigset_t sigmask;
378
379 if (VG_DEBUG_LEAKCHECK)
380 VG_(printf)("scan %p-%p\n", start, len);
381 VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &sigmask);
njn695c16e2005-03-27 03:40:28 +0000382 VG_(set_fault_catcher)(scan_all_valid_memory_catcher);
sewardjb5f6f512005-03-10 23:59:00 +0000383
384 lc_scanned += end-ptr;
385
386 if (!VG_(is_client_addr)(ptr) ||
387 !VG_(is_addressable)(ptr, sizeof(Addr), VKI_PROT_READ))
njn13bfd852005-06-02 03:52:53 +0000388 ptr = VG_PGROUNDUP(ptr+1); /* first page bad */
sewardjb5f6f512005-03-10 23:59:00 +0000389
sewardj05fe85e2005-04-27 22:46:36 +0000390 while (ptr < end) {
sewardjb5f6f512005-03-10 23:59:00 +0000391 Addr addr;
392
393 /* Skip invalid chunks */
sewardj05fe85e2005-04-27 22:46:36 +0000394 if (!(*lc_is_within_valid_secondary)(ptr)) {
njn13bfd852005-06-02 03:52:53 +0000395 ptr = VG_ROUNDUP(ptr+1, SECONDARY_SIZE);
sewardjb5f6f512005-03-10 23:59:00 +0000396 continue;
397 }
398
399 /* Look to see if this page seems reasonble */
400 if ((ptr % VKI_PAGE_SIZE) == 0) {
401 if (!VG_(is_client_addr)(ptr) ||
402 !VG_(is_addressable)(ptr, sizeof(Addr), VKI_PROT_READ))
403 ptr += VKI_PAGE_SIZE; /* bad page - skip it */
404 }
405
406 if (__builtin_setjmp(memscan_jmpbuf) == 0) {
sewardj05fe85e2005-04-27 22:46:36 +0000407 if ((*lc_is_valid_aligned_word)(ptr)) {
sewardjb5f6f512005-03-10 23:59:00 +0000408 addr = *(Addr *)ptr;
409 _lc_markstack_push(addr, clique);
410 } else if (0 && VG_DEBUG_LEAKCHECK)
411 VG_(printf)("%p not valid\n", ptr);
412 ptr += sizeof(Addr);
413 } else {
414 /* We need to restore the signal mask, because we were
415 longjmped out of a signal handler. */
416 VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL);
417
njn13bfd852005-06-02 03:52:53 +0000418 ptr = VG_PGROUNDUP(ptr+1); /* bad page - skip it */
sewardjb5f6f512005-03-10 23:59:00 +0000419 }
420 }
421
422 VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL);
423 VG_(set_fault_catcher)(NULL);
424}
425
sewardj45d94cc2005-04-20 14:44:11 +0000426
sewardjb5f6f512005-03-10 23:59:00 +0000427static void lc_scan_memory(Addr start, SizeT len)
428{
429 _lc_scan_memory(start, len, -1);
430}
431
432/* Process the mark stack until empty. If mopup is true, then we're
433 actually gathering leaked blocks, so they should be marked
434 IndirectLeak. */
435static void lc_do_leakcheck(Int clique)
436{
437 Int top;
438
439 while((top = lc_markstack_pop()) != -1) {
sewardj76754cf2005-03-14 00:14:04 +0000440 tl_assert(top >= 0 && top < lc_n_shadows);
441 tl_assert(lc_markstack[top].state != Unreached);
sewardjb5f6f512005-03-10 23:59:00 +0000442
443 _lc_scan_memory(lc_shadows[top]->data, lc_shadows[top]->size, clique);
444 }
445}
446
447static Int blocks_leaked;
448static Int blocks_indirect;
449static Int blocks_dubious;
450static Int blocks_reachable;
451static Int blocks_suppressed;
452
njnb8dca862005-03-14 02:42:44 +0000453static void full_report(ThreadId tid)
sewardjb5f6f512005-03-10 23:59:00 +0000454{
455 Int i;
456 Int n_lossrecords;
457 LossRecord* errlist;
458 LossRecord* p;
459 Bool is_suppressed;
njn02977032005-05-17 04:00:11 +0000460 LeakExtra leak_extra;
sewardjb5f6f512005-03-10 23:59:00 +0000461
462 /* Go through and group lost structures into cliques. For each
463 Unreached block, push it onto the mark stack, and find all the
464 blocks linked to it. These are marked IndirectLeak, and their
465 size is added to the clique leader's indirect size. If one of
466 the found blocks was itself a clique leader (from a previous
467 pass), then the cliques are merged. */
468 for (i = 0; i < lc_n_shadows; i++) {
469 if (VG_DEBUG_CLIQUE)
470 VG_(printf)("cliques: %d at %p -> %s\n",
njn02977032005-05-17 04:00:11 +0000471 i, lc_shadows[i]->data, str_lossmode(lc_markstack[i].state));
sewardjb5f6f512005-03-10 23:59:00 +0000472 if (lc_markstack[i].state != Unreached)
473 continue;
474
sewardj76754cf2005-03-14 00:14:04 +0000475 tl_assert(lc_markstack_top == -1);
sewardjb5f6f512005-03-10 23:59:00 +0000476
477 if (VG_DEBUG_CLIQUE)
478 VG_(printf)("%d: gathering clique %p\n", i, lc_shadows[i]->data);
479
480 _lc_markstack_push(lc_shadows[i]->data, i);
481
482 lc_do_leakcheck(i);
483
sewardj76754cf2005-03-14 00:14:04 +0000484 tl_assert(lc_markstack_top == -1);
485 tl_assert(lc_markstack[i].state == IndirectLeak);
sewardjb5f6f512005-03-10 23:59:00 +0000486
487 lc_markstack[i].state = Unreached; /* Return to unreached state,
488 to indicate its a clique
489 leader */
490 }
491
492 /* Common up the lost blocks so we can print sensible error messages. */
493 n_lossrecords = 0;
494 errlist = NULL;
495 for (i = 0; i < lc_n_shadows; i++) {
496 ExeContext* where = lc_shadows[i]->where;
497
498 for (p = errlist; p != NULL; p = p->next) {
499 if (p->loss_mode == lc_markstack[i].state
500 && VG_(eq_ExeContext) ( MAC_(clo_leak_resolution),
501 p->allocated_at,
502 where) ) {
503 break;
504 }
505 }
506 if (p != NULL) {
507 p->num_blocks ++;
508 p->total_bytes += lc_shadows[i]->size;
509 p->indirect_bytes += lc_markstack[i].indirect;
510 } else {
511 n_lossrecords ++;
512 p = VG_(malloc)(sizeof(LossRecord));
513 p->loss_mode = lc_markstack[i].state;
514 p->allocated_at = where;
515 p->total_bytes = lc_shadows[i]->size;
516 p->indirect_bytes = lc_markstack[i].indirect;
517 p->num_blocks = 1;
518 p->next = errlist;
519 errlist = p;
520 }
521 }
522
523 /* Print out the commoned-up blocks and collect summary stats. */
524 for (i = 0; i < n_lossrecords; i++) {
525 Bool print_record;
526 LossRecord* p_min = NULL;
527 UInt n_min = 0xFFFFFFFF;
528 for (p = errlist; p != NULL; p = p->next) {
529 if (p->num_blocks > 0 && p->total_bytes < n_min) {
530 n_min = p->total_bytes + p->indirect_bytes;
531 p_min = p;
532 }
533 }
sewardj76754cf2005-03-14 00:14:04 +0000534 tl_assert(p_min != NULL);
sewardjb5f6f512005-03-10 23:59:00 +0000535
536 /* Ok to have tst==NULL; it's only used if --gdb-attach=yes, and
537 we disallow that when --leak-check=yes.
538
njn02977032005-05-17 04:00:11 +0000539 Prints the error if not suppressed, unless it's reachable (Proper
540 or IndirectLeak) and --show-reachable=no */
sewardjb5f6f512005-03-10 23:59:00 +0000541
542 print_record = ( MAC_(clo_show_reachable) ||
njn02977032005-05-17 04:00:11 +0000543 Unreached == p_min->loss_mode ||
544 Interior == p_min->loss_mode );
545
546 // Nb: because VG_(unique_error) does all the error processing
547 // immediately, and doesn't save the error, leakExtra can be
548 // stack-allocated.
549 leak_extra.n_this_record = i+1;
550 leak_extra.n_total_records = n_lossrecords;
551 leak_extra.lossRecord = p_min;
sewardjb5f6f512005-03-10 23:59:00 +0000552 is_suppressed =
njn02977032005-05-17 04:00:11 +0000553 VG_(unique_error) ( tid, LeakErr, /*Addr*/0, /*s*/NULL,
554 /*extra*/&leak_extra,
555 /*where*/p_min->allocated_at, print_record,
sewardjb5f6f512005-03-10 23:59:00 +0000556 /*allow_GDB_attach*/False, /*count_error*/False );
557
558 if (is_suppressed) {
559 blocks_suppressed += p_min->num_blocks;
560 MAC_(bytes_suppressed) += p_min->total_bytes;
561
562 } else if (Unreached == p_min->loss_mode) {
563 blocks_leaked += p_min->num_blocks;
564 MAC_(bytes_leaked) += p_min->total_bytes;
565
566 } else if (IndirectLeak == p_min->loss_mode) {
567 blocks_indirect += p_min->num_blocks;
568 MAC_(bytes_indirect)+= p_min->total_bytes;
569
570 } else if (Interior == p_min->loss_mode) {
571 blocks_dubious += p_min->num_blocks;
572 MAC_(bytes_dubious) += p_min->total_bytes;
573
574 } else if (Proper == p_min->loss_mode) {
575 blocks_reachable += p_min->num_blocks;
576 MAC_(bytes_reachable) += p_min->total_bytes;
577
578 } else {
sewardj76754cf2005-03-14 00:14:04 +0000579 VG_(tool_panic)("generic_detect_memory_leaks: unknown loss mode");
sewardjb5f6f512005-03-10 23:59:00 +0000580 }
581 p_min->num_blocks = 0;
582 }
583}
584
585/* Compute a quick summary of the leak check. */
586static void make_summary()
587{
588 Int i;
589
590 for(i = 0; i < lc_n_shadows; i++) {
591 SizeT size = lc_shadows[i]->size;
592
593 switch(lc_markstack[i].state) {
594 case Unreached:
595 blocks_leaked++;
596 MAC_(bytes_leaked) += size;
597 break;
598
599 case Proper:
600 blocks_reachable++;
601 MAC_(bytes_reachable) += size;
602 break;
603
604 case Interior:
605 blocks_dubious++;
606 MAC_(bytes_dubious) += size;
607 break;
608
609 case IndirectLeak: /* shouldn't happen */
610 blocks_indirect++;
611 MAC_(bytes_indirect) += size;
612 break;
613 }
614 }
615}
616
njn43c799e2003-04-08 00:08:52 +0000617/* Top level entry point to leak detector. Call here, passing in
618 suitable address-validating functions (see comment at top of
njn695c16e2005-03-27 03:40:28 +0000619 scan_all_valid_memory above). All this is to avoid duplication
nethercote996901a2004-08-03 13:29:09 +0000620 of the leak-detection code for Memcheck and Addrcheck.
621 Also pass in a tool-specific function to extract the .where field
njn43c799e2003-04-08 00:08:52 +0000622 for allocated blocks, an indication of the resolution wanted for
623 distinguishing different allocation points, and whether or not
624 reachable blocks should be shown.
625*/
626void MAC_(do_detect_memory_leaks) (
njnb8dca862005-03-14 02:42:44 +0000627 ThreadId tid, LeakCheckMode mode,
sewardj05fe85e2005-04-27 22:46:36 +0000628 Bool (*is_within_valid_secondary) ( Addr ),
629 Bool (*is_valid_aligned_word) ( Addr )
njn43c799e2003-04-08 00:08:52 +0000630)
631{
njnb8dca862005-03-14 02:42:44 +0000632 Int i;
njn43c799e2003-04-08 00:08:52 +0000633
sewardj76754cf2005-03-14 00:14:04 +0000634 tl_assert(mode != LC_Off);
njn43c799e2003-04-08 00:08:52 +0000635
njn06072ec2003-09-30 15:35:13 +0000636 /* VG_(HT_to_array) allocates storage for shadows */
637 lc_shadows = (MAC_Chunk**)VG_(HT_to_array)( MAC_(malloc_list),
638 &lc_n_shadows );
639
640 /* Sort the array. */
641 VG_(ssort)((void*)lc_shadows, lc_n_shadows, sizeof(VgHashNode*), lc_compar);
642
643 /* Sanity check; assert that the blocks are now in order */
644 for (i = 0; i < lc_n_shadows-1; i++) {
sewardj76754cf2005-03-14 00:14:04 +0000645 tl_assert( lc_shadows[i]->data <= lc_shadows[i+1]->data);
njn06072ec2003-09-30 15:35:13 +0000646 }
njn3e884182003-04-15 13:03:23 +0000647
648 /* Sanity check -- make sure they don't overlap */
649 for (i = 0; i < lc_n_shadows-1; i++) {
sewardj76754cf2005-03-14 00:14:04 +0000650 tl_assert( lc_shadows[i]->data + lc_shadows[i]->size
njn3e884182003-04-15 13:03:23 +0000651 < lc_shadows[i+1]->data );
652 }
653
654 if (lc_n_shadows == 0) {
sewardj76754cf2005-03-14 00:14:04 +0000655 tl_assert(lc_shadows == NULL);
sewardj71bc3cb2005-05-19 00:25:45 +0000656 if (VG_(clo_verbosity) >= 1 && !VG_(clo_xml)) {
sewardj37d06f22003-09-17 21:48:26 +0000657 VG_(message)(Vg_UserMsg,
658 "No malloc'd blocks -- no leaks are possible.");
659 }
njn43c799e2003-04-08 00:08:52 +0000660 return;
661 }
662
sewardj71bc3cb2005-05-19 00:25:45 +0000663 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
nethercote0f19bce2003-12-02 10:17:44 +0000664 VG_(message)(Vg_UserMsg,
665 "searching for pointers to %d not-freed blocks.",
666 lc_n_shadows );
njn43c799e2003-04-08 00:08:52 +0000667
njn3e884182003-04-15 13:03:23 +0000668 lc_min_mallocd_addr = lc_shadows[0]->data;
669 lc_max_mallocd_addr = lc_shadows[lc_n_shadows-1]->data
sewardjb5f6f512005-03-10 23:59:00 +0000670 + lc_shadows[lc_n_shadows-1]->size;
njn43c799e2003-04-08 00:08:52 +0000671
sewardjb5f6f512005-03-10 23:59:00 +0000672 lc_markstack = VG_(malloc)( lc_n_shadows * sizeof(*lc_markstack) );
673 for (i = 0; i < lc_n_shadows; i++) {
674 lc_markstack[i].next = -1;
675 lc_markstack[i].state = Unreached;
676 lc_markstack[i].indirect = 0;
677 }
678 lc_markstack_top = -1;
njn43c799e2003-04-08 00:08:52 +0000679
sewardj05fe85e2005-04-27 22:46:36 +0000680 lc_is_within_valid_secondary = is_within_valid_secondary;
681 lc_is_valid_aligned_word = is_valid_aligned_word;
sewardjb5f6f512005-03-10 23:59:00 +0000682
683 lc_scanned = 0;
684
685 /* Do the scan of memory, pushing any pointers onto the mark stack */
686 VG_(find_root_memory)(lc_scan_memory);
687
688 /* Push registers onto mark stack */
njn6ace3ea2005-06-17 03:06:27 +0000689 VG_(apply_to_GP_regs)(lc_markstack_push);
sewardjb5f6f512005-03-10 23:59:00 +0000690
691 /* Keep walking the heap until everything is found */
692 lc_do_leakcheck(-1);
njn43c799e2003-04-08 00:08:52 +0000693
sewardj71bc3cb2005-05-19 00:25:45 +0000694 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
sewardjb5f6f512005-03-10 23:59:00 +0000695 VG_(message)(Vg_UserMsg, "checked %d bytes.", lc_scanned);
njn43c799e2003-04-08 00:08:52 +0000696
njne8b5c052003-07-22 22:03:58 +0000697 blocks_leaked = MAC_(bytes_leaked) = 0;
sewardjb5f6f512005-03-10 23:59:00 +0000698 blocks_indirect = MAC_(bytes_indirect) = 0;
njne8b5c052003-07-22 22:03:58 +0000699 blocks_dubious = MAC_(bytes_dubious) = 0;
700 blocks_reachable = MAC_(bytes_reachable) = 0;
701 blocks_suppressed = MAC_(bytes_suppressed) = 0;
njn43c799e2003-04-08 00:08:52 +0000702
sewardjb5f6f512005-03-10 23:59:00 +0000703 if (mode == LC_Full)
njnb8dca862005-03-14 02:42:44 +0000704 full_report(tid);
sewardjb5f6f512005-03-10 23:59:00 +0000705 else
706 make_summary();
njn43c799e2003-04-08 00:08:52 +0000707
sewardj71bc3cb2005-05-19 00:25:45 +0000708 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) {
nethercote0f19bce2003-12-02 10:17:44 +0000709 VG_(message)(Vg_UserMsg, "");
710 VG_(message)(Vg_UserMsg, "LEAK SUMMARY:");
711 VG_(message)(Vg_UserMsg, " definitely lost: %d bytes in %d blocks.",
712 MAC_(bytes_leaked), blocks_leaked );
sewardjb5f6f512005-03-10 23:59:00 +0000713 if (blocks_indirect > 0)
714 VG_(message)(Vg_UserMsg, " indirectly lost: %d bytes in %d blocks.",
715 MAC_(bytes_indirect), blocks_indirect );
716 VG_(message)(Vg_UserMsg, " possibly lost: %d bytes in %d blocks.",
nethercote0f19bce2003-12-02 10:17:44 +0000717 MAC_(bytes_dubious), blocks_dubious );
718 VG_(message)(Vg_UserMsg, " still reachable: %d bytes in %d blocks.",
719 MAC_(bytes_reachable), blocks_reachable );
720 VG_(message)(Vg_UserMsg, " suppressed: %d bytes in %d blocks.",
721 MAC_(bytes_suppressed), blocks_suppressed );
njn6a329422005-03-12 20:38:13 +0000722 if (mode == LC_Summary && blocks_leaked > 0)
sewardjb5f6f512005-03-10 23:59:00 +0000723 VG_(message)(Vg_UserMsg,
724 "Use --leak-check=full to see details of leaked memory.");
725 else if (!MAC_(clo_show_reachable)) {
nethercote0f19bce2003-12-02 10:17:44 +0000726 VG_(message)(Vg_UserMsg,
727 "Reachable blocks (those to which a pointer was found) are not shown.");
728 VG_(message)(Vg_UserMsg,
729 "To see them, rerun with: --show-reachable=yes");
730 }
njn43c799e2003-04-08 00:08:52 +0000731 }
njn43c799e2003-04-08 00:08:52 +0000732
njn3e884182003-04-15 13:03:23 +0000733 VG_(free) ( lc_shadows );
sewardjb5f6f512005-03-10 23:59:00 +0000734 VG_(free) ( lc_markstack );
njn43c799e2003-04-08 00:08:52 +0000735}
736
737/*--------------------------------------------------------------------*/
738/*--- end mac_leakcheck.c ---*/
739/*--------------------------------------------------------------------*/
740