blob: 63c982d77650bf7c21a8359ea8fc7ee2f0af66c8 [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
njnc7561b92005-06-19 01:24:32 +000033#include "pub_tool_basics.h"
njn4802b382005-06-11 04:58:29 +000034#include "pub_tool_aspacemgr.h"
njnc7561b92005-06-19 01:24:32 +000035#include "pub_tool_errormgr.h" // For mac_shared.h
36#include "pub_tool_execontext.h" // For mac_shared.h
37#include "pub_tool_hashtable.h" // For mac_shared.h
njn97405b22005-06-02 03:39:33 +000038#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000039#include "pub_tool_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000040#include "pub_tool_libcprint.h"
njnde62cbf2005-06-10 22:08:14 +000041#include "pub_tool_libcsignal.h"
njn6ace3ea2005-06-17 03:06:27 +000042#include "pub_tool_machine.h"
njnc7561b92005-06-19 01:24:32 +000043#include "pub_tool_mallocfree.h"
44#include "pub_tool_options.h"
45#include "pub_tool_profile.h" // For mac_shared.h
njn73c51342005-06-18 15:18:15 +000046#include "pub_tool_signals.h"
njn43c799e2003-04-08 00:08:52 +000047
njnc7561b92005-06-19 01:24:32 +000048#include "mac_shared.h"
49
50#include <setjmp.h> // For jmp_buf
51
52
njn43c799e2003-04-08 00:08:52 +000053/* Define to debug the memory-leak-detector. */
sewardjb5f6f512005-03-10 23:59:00 +000054#define VG_DEBUG_LEAKCHECK 0
55#define VG_DEBUG_CLIQUE 0
56
njn43c799e2003-04-08 00:08:52 +000057/*------------------------------------------------------------*/
58/*--- Low-level address-space scanning, for the leak ---*/
59/*--- detector. ---*/
60/*------------------------------------------------------------*/
61
62static
63jmp_buf memscan_jmpbuf;
64
65
66static
njn695c16e2005-03-27 03:40:28 +000067void scan_all_valid_memory_catcher ( Int sigNo, Addr addr )
njn43c799e2003-04-08 00:08:52 +000068{
sewardjb5f6f512005-03-10 23:59:00 +000069 if (0)
70 VG_(printf)("OUCH! sig=%d addr=%p\n", sigNo, addr);
71 if (sigNo == VKI_SIGSEGV || sigNo == VKI_SIGBUS)
72 __builtin_longjmp(memscan_jmpbuf, 1);
njn43c799e2003-04-08 00:08:52 +000073}
74
sewardj45f4e7c2005-09-27 19:20:21 +000075
76/* TODO: GIVE THIS A PROPER HOME
77 TODO: MERGE THIS WITH DUPLICATE IN m_main.c
78 Extract from aspacem a vector of the current segment start
79 addresses. The vector is dynamically allocated and should be freed
80 by the caller when done. REQUIRES m_mallocfree to be running.
81 Writes the number of addresses required into *n_acquired. */
82
83static Addr* get_seg_starts ( /*OUT*/Int* n_acquired )
84{
85 Addr* starts;
sewardjae986ca2005-10-12 12:53:20 +000086 Int n_starts, r = 0;
sewardj45f4e7c2005-09-27 19:20:21 +000087
88 n_starts = 1;
89 while (True) {
90 starts = VG_(malloc)( n_starts * sizeof(Addr) );
91 if (starts == NULL)
92 break;
93 r = VG_(am_get_segment_starts)( starts, n_starts );
94 if (r >= 0)
95 break;
96 VG_(free)(starts);
97 n_starts *= 2;
98 }
99
100 if (starts == NULL) {
101 *n_acquired = 0;
102 return NULL;
103 }
104
105 *n_acquired = r;
106 return starts;
107}
108
109
njn43c799e2003-04-08 00:08:52 +0000110/*------------------------------------------------------------*/
111/*--- Detecting leaked (unreachable) malloc'd blocks. ---*/
112/*------------------------------------------------------------*/
113
114/* A block is either
115 -- Proper-ly reached; a pointer to its start has been found
116 -- Interior-ly reached; only an interior pointer to it has been found
117 -- Unreached; so far, no pointers to any part of it have been found.
sewardjb5f6f512005-03-10 23:59:00 +0000118 -- IndirectLeak; leaked, but referred to by another leaked block
njn43c799e2003-04-08 00:08:52 +0000119*/
sewardj45f4e7c2005-09-27 19:20:21 +0000120typedef
121 enum {
122 Unreached,
123 IndirectLeak,
124 Interior,
125 Proper
126 }
127 Reachedness;
sewardjb5f6f512005-03-10 23:59:00 +0000128
129/* An entry in the mark stack */
sewardj45f4e7c2005-09-27 19:20:21 +0000130typedef
131 struct {
132 Int next:30; /* Index of next in mark stack */
133 UInt state:2; /* Reachedness */
134 SizeT indirect; /* if Unreached, how much is unreachable from here */
135 }
136 MarkStack;
njn43c799e2003-04-08 00:08:52 +0000137
138/* A block record, used for generating err msgs. */
139typedef
140 struct _LossRecord {
141 struct _LossRecord* next;
142 /* Where these lost blocks were allocated. */
143 ExeContext* allocated_at;
144 /* Their reachability. */
145 Reachedness loss_mode;
146 /* Number of blocks and total # bytes involved. */
njn0fd92f42005-10-06 03:32:42 +0000147 SizeT total_bytes;
148 SizeT indirect_bytes;
njn43c799e2003-04-08 00:08:52 +0000149 UInt num_blocks;
150 }
151 LossRecord;
152
njn02977032005-05-17 04:00:11 +0000153/* The 'extra' struct for leak errors. */
sewardj45f4e7c2005-09-27 19:20:21 +0000154typedef
155 struct {
156 UInt n_this_record;
157 UInt n_total_records;
158 LossRecord* lossRecord;
159 }
160 LeakExtra;
njn43c799e2003-04-08 00:08:52 +0000161
162/* Find the i such that ptr points at or inside the block described by
163 shadows[i]. Return -1 if none found. This assumes that shadows[]
164 has been sorted on the ->data field. */
165
sewardjb5f6f512005-03-10 23:59:00 +0000166#if VG_DEBUG_LEAKCHECK
njn43c799e2003-04-08 00:08:52 +0000167/* Used to sanity-check the fast binary-search mechanism. */
168static
njn3e884182003-04-15 13:03:23 +0000169Int find_shadow_for_OLD ( Addr ptr,
170 MAC_Chunk** shadows,
171 Int n_shadows )
njn43c799e2003-04-08 00:08:52 +0000172
173{
174 Int i;
175 Addr a_lo, a_hi;
tom16ade0d2005-07-18 09:41:57 +0000176 PROF_EVENT(70, "find_shadow_for_OLD");
njn43c799e2003-04-08 00:08:52 +0000177 for (i = 0; i < n_shadows; i++) {
tom16ade0d2005-07-18 09:41:57 +0000178 PROF_EVENT(71, "find_shadow_for_OLD(loop)");
njn43c799e2003-04-08 00:08:52 +0000179 a_lo = shadows[i]->data;
sewardjb5f6f512005-03-10 23:59:00 +0000180 a_hi = ((Addr)shadows[i]->data) + shadows[i]->size;
njn43c799e2003-04-08 00:08:52 +0000181 if (a_lo <= ptr && ptr <= a_hi)
182 return i;
183 }
184 return -1;
185}
186#endif
187
188
189static
njn3e884182003-04-15 13:03:23 +0000190Int find_shadow_for ( Addr ptr,
191 MAC_Chunk** shadows,
192 Int n_shadows )
njn43c799e2003-04-08 00:08:52 +0000193{
194 Addr a_mid_lo, a_mid_hi;
195 Int lo, mid, hi, retVal;
196 /* VG_(printf)("find shadow for %p = ", ptr); */
197 retVal = -1;
198 lo = 0;
199 hi = n_shadows-1;
200 while (True) {
njn3e884182003-04-15 13:03:23 +0000201 /* invariant: current unsearched space is from lo to hi, inclusive. */
njn43c799e2003-04-08 00:08:52 +0000202 if (lo > hi) break; /* not found */
203
204 mid = (lo + hi) / 2;
njn3e884182003-04-15 13:03:23 +0000205 a_mid_lo = shadows[mid]->data;
sewardjb5f6f512005-03-10 23:59:00 +0000206 a_mid_hi = shadows[mid]->data + shadows[mid]->size;
njn43c799e2003-04-08 00:08:52 +0000207
208 if (ptr < a_mid_lo) {
209 hi = mid-1;
210 continue;
211 }
212 if (ptr > a_mid_hi) {
213 lo = mid+1;
214 continue;
215 }
sewardj76754cf2005-03-14 00:14:04 +0000216 tl_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
njn43c799e2003-04-08 00:08:52 +0000217 retVal = mid;
218 break;
219 }
220
sewardjb5f6f512005-03-10 23:59:00 +0000221# if VG_DEBUG_LEAKCHECK
sewardj76754cf2005-03-14 00:14:04 +0000222 tl_assert(retVal == find_shadow_for_OLD ( ptr, shadows, n_shadows ));
njn43c799e2003-04-08 00:08:52 +0000223# endif
224 /* VG_(printf)("%d\n", retVal); */
225 return retVal;
226}
227
228/* Globals, for the following callback used by VG_(detect_memory_leaks). */
njn3e884182003-04-15 13:03:23 +0000229static MAC_Chunk** lc_shadows;
230static Int lc_n_shadows;
sewardjb5f6f512005-03-10 23:59:00 +0000231static MarkStack* lc_markstack;
232static Int lc_markstack_top;
njn3e884182003-04-15 13:03:23 +0000233static Addr lc_min_mallocd_addr;
234static Addr lc_max_mallocd_addr;
sewardjb5f6f512005-03-10 23:59:00 +0000235static SizeT lc_scanned;
njn43c799e2003-04-08 00:08:52 +0000236
sewardj05fe85e2005-04-27 22:46:36 +0000237static Bool (*lc_is_within_valid_secondary) (Addr addr);
238static Bool (*lc_is_valid_aligned_word) (Addr addr);
sewardjb5f6f512005-03-10 23:59:00 +0000239
sewardj71bc3cb2005-05-19 00:25:45 +0000240static const HChar* str_lossmode ( Reachedness lossmode )
njn43c799e2003-04-08 00:08:52 +0000241{
sewardj71bc3cb2005-05-19 00:25:45 +0000242 const HChar *loss = "?";
243 switch (lossmode) {
244 case Unreached: loss = "definitely lost"; break;
245 case IndirectLeak: loss = "indirectly lost"; break;
246 case Interior: loss = "possibly lost"; break;
247 case Proper: loss = "still reachable"; break;
njn43c799e2003-04-08 00:08:52 +0000248 }
sewardjb5f6f512005-03-10 23:59:00 +0000249 return loss;
njn43c799e2003-04-08 00:08:52 +0000250}
251
sewardj71bc3cb2005-05-19 00:25:45 +0000252static const HChar* xml_kind ( Reachedness lossmode )
253{
254 const HChar *loss = "?";
255 switch (lossmode) {
256 case Unreached: loss = "Leak_DefinitelyLost"; break;
257 case IndirectLeak: loss = "Leak_IndirectlyLost"; break;
258 case Interior: loss = "Leak_PossiblyLost"; break;
259 case Proper: loss = "Leak_StillReachable"; break;
260 }
261 return loss;
262}
263
264
njn43c799e2003-04-08 00:08:52 +0000265/* Used for printing leak errors, avoids exposing the LossRecord type (which
266 comes in as void*, requiring a cast. */
njn02977032005-05-17 04:00:11 +0000267void MAC_(pp_LeakError)(void* vextra)
njn43c799e2003-04-08 00:08:52 +0000268{
sewardj71bc3cb2005-05-19 00:25:45 +0000269 HChar* xpre = VG_(clo_xml) ? " <what>" : "";
270 HChar* xpost = VG_(clo_xml) ? "</what>" : "";
271
njn02977032005-05-17 04:00:11 +0000272 LeakExtra* extra = (LeakExtra*)vextra;
273 LossRecord* l = extra->lossRecord;
274 const Char *loss = str_lossmode(l->loss_mode);
njn43c799e2003-04-08 00:08:52 +0000275
sewardj71bc3cb2005-05-19 00:25:45 +0000276 if (VG_(clo_xml)) {
sewardj97f7e0c2005-07-19 15:00:25 +0000277 VG_(message)(Vg_UserMsg, " <kind>%t</kind>", xml_kind(l->loss_mode));
sewardj71bc3cb2005-05-19 00:25:45 +0000278 } else {
279 VG_(message)(Vg_UserMsg, "");
280 }
281
sewardjb5f6f512005-03-10 23:59:00 +0000282 if (l->indirect_bytes) {
283 VG_(message)(Vg_UserMsg,
njn0fd92f42005-10-06 03:32:42 +0000284 "%s%,lu (%,lu direct, %,lu indirect) bytes in %,u blocks"
285 " are %s in loss record %,u of %,u%s",
sewardj71bc3cb2005-05-19 00:25:45 +0000286 xpre,
287 l->total_bytes + l->indirect_bytes,
288 l->total_bytes, l->indirect_bytes, l->num_blocks,
289 loss, extra->n_this_record, extra->n_total_records,
290 xpost
291 );
292 if (VG_(clo_xml)) {
njn0fd92f42005-10-06 03:32:42 +0000293 // Nb: don't put commas in these XML numbers
294 VG_(message)(Vg_UserMsg, " <leakedbytes>%lu</leakedbytes>",
sewardj71bc3cb2005-05-19 00:25:45 +0000295 l->total_bytes + l->indirect_bytes);
njn0fd92f42005-10-06 03:32:42 +0000296 VG_(message)(Vg_UserMsg, " <leakedblocks>%u</leakedblocks>",
sewardj71bc3cb2005-05-19 00:25:45 +0000297 l->num_blocks);
298 }
sewardjb5f6f512005-03-10 23:59:00 +0000299 } else {
sewardj71bc3cb2005-05-19 00:25:45 +0000300 VG_(message)(
301 Vg_UserMsg,
njn0fd92f42005-10-06 03:32:42 +0000302 "%s%,lu bytes in %,u blocks are %s in loss record %,u of %,u%s",
sewardj71bc3cb2005-05-19 00:25:45 +0000303 xpre,
304 l->total_bytes, l->num_blocks,
305 loss, extra->n_this_record, extra->n_total_records,
306 xpost
307 );
308 if (VG_(clo_xml)) {
309 VG_(message)(Vg_UserMsg, " <leakedbytes>%d</leakedbytes>",
310 l->total_bytes);
311 VG_(message)(Vg_UserMsg, " <leakedblocks>%d</leakedblocks>",
312 l->num_blocks);
313 }
sewardjb5f6f512005-03-10 23:59:00 +0000314 }
njn43c799e2003-04-08 00:08:52 +0000315 VG_(pp_ExeContext)(l->allocated_at);
316}
317
njn0fd92f42005-10-06 03:32:42 +0000318SizeT MAC_(bytes_leaked) = 0;
319SizeT MAC_(bytes_indirect) = 0;
320SizeT MAC_(bytes_dubious) = 0;
321SizeT MAC_(bytes_reachable) = 0;
322SizeT MAC_(bytes_suppressed) = 0;
njn47363ab2003-04-21 13:24:40 +0000323
njn06072ec2003-09-30 15:35:13 +0000324static Int lc_compar(void* n1, void* n2)
325{
326 MAC_Chunk* mc1 = *(MAC_Chunk**)n1;
327 MAC_Chunk* mc2 = *(MAC_Chunk**)n2;
328 return (mc1->data < mc2->data ? -1 : 1);
329}
330
sewardjb5f6f512005-03-10 23:59:00 +0000331/* If ptr is pointing to a heap-allocated block which hasn't been seen
332 before, push it onto the mark stack. Clique is the index of the
333 clique leader; -1 if none. */
sewardj45f4e7c2005-09-27 19:20:21 +0000334static void lc_markstack_push_WRK(Addr ptr, Int clique)
sewardjb5f6f512005-03-10 23:59:00 +0000335{
336 Int sh_no;
337
sewardj45f4e7c2005-09-27 19:20:21 +0000338 /* quick filter */
339 if (!VG_(am_is_valid_for_client)(ptr, 1, VKI_PROT_NONE))
sewardjb5f6f512005-03-10 23:59:00 +0000340 return;
341
342 sh_no = find_shadow_for(ptr, lc_shadows, lc_n_shadows);
343
344 if (VG_DEBUG_LEAKCHECK)
345 VG_(printf)("ptr=%p -> block %d\n", ptr, sh_no);
346
347 if (sh_no == -1)
348 return;
349
sewardj76754cf2005-03-14 00:14:04 +0000350 tl_assert(sh_no >= 0 && sh_no < lc_n_shadows);
351 tl_assert(ptr <= lc_shadows[sh_no]->data + lc_shadows[sh_no]->size);
sewardjb5f6f512005-03-10 23:59:00 +0000352
353 if (lc_markstack[sh_no].state == Unreached) {
354 if (0)
355 VG_(printf)("pushing %p-%p\n", lc_shadows[sh_no]->data,
356 lc_shadows[sh_no]->data + lc_shadows[sh_no]->size);
357
sewardj76754cf2005-03-14 00:14:04 +0000358 tl_assert(lc_markstack[sh_no].next == -1);
sewardjb5f6f512005-03-10 23:59:00 +0000359 lc_markstack[sh_no].next = lc_markstack_top;
360 lc_markstack_top = sh_no;
361 }
362
sewardj45f4e7c2005-09-27 19:20:21 +0000363 tl_assert(clique >= -1 && clique < lc_n_shadows);
364
sewardjb5f6f512005-03-10 23:59:00 +0000365 if (clique != -1) {
366 if (0)
367 VG_(printf)("mopup: %d: %p is %d\n",
368 sh_no, lc_shadows[sh_no]->data, lc_markstack[sh_no].state);
369
370 /* An unmarked block - add it to the clique. Add its size to
371 the clique-leader's indirect size. If the new block was
372 itself a clique leader, it isn't any more, so add its
373 indirect to the new clique leader.
374
375 If this block *is* the clique leader, it means this is a
376 cyclic structure, so none of this applies. */
377 if (lc_markstack[sh_no].state == Unreached) {
378 lc_markstack[sh_no].state = IndirectLeak;
379
380 if (sh_no != clique) {
381 if (VG_DEBUG_CLIQUE) {
382 if (lc_markstack[sh_no].indirect)
383 VG_(printf)(" clique %d joining clique %d adding %d+%d bytes\n",
384 sh_no, clique,
385 lc_shadows[sh_no]->size, lc_markstack[sh_no].indirect);
386 else
387 VG_(printf)(" %d joining %d adding %d\n",
388 sh_no, clique, lc_shadows[sh_no]->size);
389 }
390
391 lc_markstack[clique].indirect += lc_shadows[sh_no]->size;
392 lc_markstack[clique].indirect += lc_markstack[sh_no].indirect;
393 lc_markstack[sh_no].indirect = 0; /* shouldn't matter */
394 }
395 }
396 } else if (ptr == lc_shadows[sh_no]->data) {
397 lc_markstack[sh_no].state = Proper;
398 } else {
399 if (lc_markstack[sh_no].state == Unreached)
400 lc_markstack[sh_no].state = Interior;
401 }
402}
403
404static void lc_markstack_push(Addr ptr)
405{
sewardj45f4e7c2005-09-27 19:20:21 +0000406 lc_markstack_push_WRK(ptr, -1);
sewardjb5f6f512005-03-10 23:59:00 +0000407}
408
409/* Return the top of the mark stack, if any. */
410static Int lc_markstack_pop(void)
411{
412 Int ret = lc_markstack_top;
413
414 if (ret != -1) {
415 lc_markstack_top = lc_markstack[ret].next;
416 lc_markstack[ret].next = -1;
417 }
418
419 return ret;
420}
421
sewardj45d94cc2005-04-20 14:44:11 +0000422
sewardjb5f6f512005-03-10 23:59:00 +0000423/* Scan a block of memory between [start, start+len). This range may
424 be bogus, inaccessable, or otherwise strange; we deal with it.
425
426 If clique != -1, it means we're gathering leaked memory into
427 cliques, and clique is the index of the current clique leader. */
sewardj45f4e7c2005-09-27 19:20:21 +0000428static void lc_scan_memory_WRK(Addr start, SizeT len, Int clique)
sewardjb5f6f512005-03-10 23:59:00 +0000429{
njn13bfd852005-06-02 03:52:53 +0000430 Addr ptr = VG_ROUNDUP(start, sizeof(Addr));
431 Addr end = VG_ROUNDDN(start+len, sizeof(Addr));
sewardjb5f6f512005-03-10 23:59:00 +0000432 vki_sigset_t sigmask;
433
434 if (VG_DEBUG_LEAKCHECK)
tom16ade0d2005-07-18 09:41:57 +0000435 VG_(printf)("scan %p-%p\n", start, start+len);
sewardjb5f6f512005-03-10 23:59:00 +0000436 VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &sigmask);
njn695c16e2005-03-27 03:40:28 +0000437 VG_(set_fault_catcher)(scan_all_valid_memory_catcher);
sewardjb5f6f512005-03-10 23:59:00 +0000438
sewardj45f4e7c2005-09-27 19:20:21 +0000439 // lc_scanned += end-ptr;
sewardjb5f6f512005-03-10 23:59:00 +0000440
sewardj45f4e7c2005-09-27 19:20:21 +0000441 if (!VG_(am_is_valid_for_client)(ptr, sizeof(Addr), VKI_PROT_READ))
njn13bfd852005-06-02 03:52:53 +0000442 ptr = VG_PGROUNDUP(ptr+1); /* first page bad */
sewardjb5f6f512005-03-10 23:59:00 +0000443
sewardj05fe85e2005-04-27 22:46:36 +0000444 while (ptr < end) {
sewardjb5f6f512005-03-10 23:59:00 +0000445 Addr addr;
446
447 /* Skip invalid chunks */
sewardj05fe85e2005-04-27 22:46:36 +0000448 if (!(*lc_is_within_valid_secondary)(ptr)) {
njn13bfd852005-06-02 03:52:53 +0000449 ptr = VG_ROUNDUP(ptr+1, SECONDARY_SIZE);
sewardjb5f6f512005-03-10 23:59:00 +0000450 continue;
451 }
452
453 /* Look to see if this page seems reasonble */
454 if ((ptr % VKI_PAGE_SIZE) == 0) {
sewardj45f4e7c2005-09-27 19:20:21 +0000455 if (!VG_(am_is_valid_for_client)(ptr, sizeof(Addr), VKI_PROT_READ))
sewardjb5f6f512005-03-10 23:59:00 +0000456 ptr += VKI_PAGE_SIZE; /* bad page - skip it */
457 }
458
459 if (__builtin_setjmp(memscan_jmpbuf) == 0) {
sewardj05fe85e2005-04-27 22:46:36 +0000460 if ((*lc_is_valid_aligned_word)(ptr)) {
sewardj45f4e7c2005-09-27 19:20:21 +0000461 lc_scanned += sizeof(Addr);
sewardjb5f6f512005-03-10 23:59:00 +0000462 addr = *(Addr *)ptr;
sewardj45f4e7c2005-09-27 19:20:21 +0000463 lc_markstack_push_WRK(addr, clique);
sewardjb5f6f512005-03-10 23:59:00 +0000464 } else if (0 && VG_DEBUG_LEAKCHECK)
465 VG_(printf)("%p not valid\n", ptr);
466 ptr += sizeof(Addr);
467 } else {
468 /* We need to restore the signal mask, because we were
469 longjmped out of a signal handler. */
470 VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL);
471
njn13bfd852005-06-02 03:52:53 +0000472 ptr = VG_PGROUNDUP(ptr+1); /* bad page - skip it */
sewardjb5f6f512005-03-10 23:59:00 +0000473 }
474 }
475
476 VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL);
477 VG_(set_fault_catcher)(NULL);
478}
479
sewardj45d94cc2005-04-20 14:44:11 +0000480
sewardjb5f6f512005-03-10 23:59:00 +0000481static void lc_scan_memory(Addr start, SizeT len)
482{
sewardj45f4e7c2005-09-27 19:20:21 +0000483 lc_scan_memory_WRK(start, len, -1);
sewardjb5f6f512005-03-10 23:59:00 +0000484}
485
486/* Process the mark stack until empty. If mopup is true, then we're
487 actually gathering leaked blocks, so they should be marked
488 IndirectLeak. */
489static void lc_do_leakcheck(Int clique)
490{
491 Int top;
492
493 while((top = lc_markstack_pop()) != -1) {
sewardj76754cf2005-03-14 00:14:04 +0000494 tl_assert(top >= 0 && top < lc_n_shadows);
495 tl_assert(lc_markstack[top].state != Unreached);
sewardjb5f6f512005-03-10 23:59:00 +0000496
sewardj45f4e7c2005-09-27 19:20:21 +0000497 lc_scan_memory_WRK(lc_shadows[top]->data, lc_shadows[top]->size, clique);
sewardjb5f6f512005-03-10 23:59:00 +0000498 }
499}
500
njn0fd92f42005-10-06 03:32:42 +0000501static SizeT blocks_leaked;
502static SizeT blocks_indirect;
503static SizeT blocks_dubious;
504static SizeT blocks_reachable;
505static SizeT blocks_suppressed;
sewardjb5f6f512005-03-10 23:59:00 +0000506
njnb8dca862005-03-14 02:42:44 +0000507static void full_report(ThreadId tid)
sewardjb5f6f512005-03-10 23:59:00 +0000508{
509 Int i;
510 Int n_lossrecords;
511 LossRecord* errlist;
512 LossRecord* p;
513 Bool is_suppressed;
njn02977032005-05-17 04:00:11 +0000514 LeakExtra leak_extra;
sewardjb5f6f512005-03-10 23:59:00 +0000515
516 /* Go through and group lost structures into cliques. For each
517 Unreached block, push it onto the mark stack, and find all the
518 blocks linked to it. These are marked IndirectLeak, and their
519 size is added to the clique leader's indirect size. If one of
520 the found blocks was itself a clique leader (from a previous
521 pass), then the cliques are merged. */
522 for (i = 0; i < lc_n_shadows; i++) {
523 if (VG_DEBUG_CLIQUE)
524 VG_(printf)("cliques: %d at %p -> %s\n",
njn02977032005-05-17 04:00:11 +0000525 i, lc_shadows[i]->data, str_lossmode(lc_markstack[i].state));
sewardjb5f6f512005-03-10 23:59:00 +0000526 if (lc_markstack[i].state != Unreached)
527 continue;
528
sewardj76754cf2005-03-14 00:14:04 +0000529 tl_assert(lc_markstack_top == -1);
sewardjb5f6f512005-03-10 23:59:00 +0000530
531 if (VG_DEBUG_CLIQUE)
532 VG_(printf)("%d: gathering clique %p\n", i, lc_shadows[i]->data);
533
sewardj45f4e7c2005-09-27 19:20:21 +0000534 lc_markstack_push_WRK(lc_shadows[i]->data, i);
sewardjb5f6f512005-03-10 23:59:00 +0000535
536 lc_do_leakcheck(i);
537
sewardj76754cf2005-03-14 00:14:04 +0000538 tl_assert(lc_markstack_top == -1);
539 tl_assert(lc_markstack[i].state == IndirectLeak);
sewardjb5f6f512005-03-10 23:59:00 +0000540
541 lc_markstack[i].state = Unreached; /* Return to unreached state,
542 to indicate its a clique
543 leader */
544 }
545
546 /* Common up the lost blocks so we can print sensible error messages. */
547 n_lossrecords = 0;
548 errlist = NULL;
549 for (i = 0; i < lc_n_shadows; i++) {
550 ExeContext* where = lc_shadows[i]->where;
551
552 for (p = errlist; p != NULL; p = p->next) {
553 if (p->loss_mode == lc_markstack[i].state
554 && VG_(eq_ExeContext) ( MAC_(clo_leak_resolution),
555 p->allocated_at,
556 where) ) {
557 break;
558 }
559 }
560 if (p != NULL) {
561 p->num_blocks ++;
562 p->total_bytes += lc_shadows[i]->size;
563 p->indirect_bytes += lc_markstack[i].indirect;
564 } else {
565 n_lossrecords ++;
566 p = VG_(malloc)(sizeof(LossRecord));
567 p->loss_mode = lc_markstack[i].state;
568 p->allocated_at = where;
569 p->total_bytes = lc_shadows[i]->size;
570 p->indirect_bytes = lc_markstack[i].indirect;
571 p->num_blocks = 1;
572 p->next = errlist;
573 errlist = p;
574 }
575 }
576
577 /* Print out the commoned-up blocks and collect summary stats. */
578 for (i = 0; i < n_lossrecords; i++) {
579 Bool print_record;
580 LossRecord* p_min = NULL;
njn0fd92f42005-10-06 03:32:42 +0000581 SizeT n_min = ~(0x0L);
sewardjb5f6f512005-03-10 23:59:00 +0000582 for (p = errlist; p != NULL; p = p->next) {
583 if (p->num_blocks > 0 && p->total_bytes < n_min) {
584 n_min = p->total_bytes + p->indirect_bytes;
585 p_min = p;
586 }
587 }
sewardj76754cf2005-03-14 00:14:04 +0000588 tl_assert(p_min != NULL);
sewardjb5f6f512005-03-10 23:59:00 +0000589
590 /* Ok to have tst==NULL; it's only used if --gdb-attach=yes, and
591 we disallow that when --leak-check=yes.
592
njn02977032005-05-17 04:00:11 +0000593 Prints the error if not suppressed, unless it's reachable (Proper
594 or IndirectLeak) and --show-reachable=no */
sewardjb5f6f512005-03-10 23:59:00 +0000595
596 print_record = ( MAC_(clo_show_reachable) ||
njn02977032005-05-17 04:00:11 +0000597 Unreached == p_min->loss_mode ||
598 Interior == p_min->loss_mode );
599
600 // Nb: because VG_(unique_error) does all the error processing
601 // immediately, and doesn't save the error, leakExtra can be
602 // stack-allocated.
603 leak_extra.n_this_record = i+1;
604 leak_extra.n_total_records = n_lossrecords;
605 leak_extra.lossRecord = p_min;
sewardjb5f6f512005-03-10 23:59:00 +0000606 is_suppressed =
njn02977032005-05-17 04:00:11 +0000607 VG_(unique_error) ( tid, LeakErr, /*Addr*/0, /*s*/NULL,
608 /*extra*/&leak_extra,
609 /*where*/p_min->allocated_at, print_record,
sewardjb5f6f512005-03-10 23:59:00 +0000610 /*allow_GDB_attach*/False, /*count_error*/False );
611
612 if (is_suppressed) {
613 blocks_suppressed += p_min->num_blocks;
614 MAC_(bytes_suppressed) += p_min->total_bytes;
615
616 } else if (Unreached == p_min->loss_mode) {
617 blocks_leaked += p_min->num_blocks;
618 MAC_(bytes_leaked) += p_min->total_bytes;
619
620 } else if (IndirectLeak == p_min->loss_mode) {
621 blocks_indirect += p_min->num_blocks;
622 MAC_(bytes_indirect)+= p_min->total_bytes;
623
624 } else if (Interior == p_min->loss_mode) {
625 blocks_dubious += p_min->num_blocks;
626 MAC_(bytes_dubious) += p_min->total_bytes;
627
628 } else if (Proper == p_min->loss_mode) {
629 blocks_reachable += p_min->num_blocks;
630 MAC_(bytes_reachable) += p_min->total_bytes;
631
632 } else {
sewardj76754cf2005-03-14 00:14:04 +0000633 VG_(tool_panic)("generic_detect_memory_leaks: unknown loss mode");
sewardjb5f6f512005-03-10 23:59:00 +0000634 }
635 p_min->num_blocks = 0;
636 }
637}
638
639/* Compute a quick summary of the leak check. */
tom151a6392005-11-11 12:30:36 +0000640static void make_summary(void)
sewardjb5f6f512005-03-10 23:59:00 +0000641{
642 Int i;
643
644 for(i = 0; i < lc_n_shadows; i++) {
645 SizeT size = lc_shadows[i]->size;
646
647 switch(lc_markstack[i].state) {
648 case Unreached:
649 blocks_leaked++;
650 MAC_(bytes_leaked) += size;
651 break;
652
653 case Proper:
654 blocks_reachable++;
655 MAC_(bytes_reachable) += size;
656 break;
657
658 case Interior:
659 blocks_dubious++;
660 MAC_(bytes_dubious) += size;
661 break;
662
663 case IndirectLeak: /* shouldn't happen */
664 blocks_indirect++;
665 MAC_(bytes_indirect) += size;
666 break;
667 }
668 }
669}
670
njn43c799e2003-04-08 00:08:52 +0000671/* Top level entry point to leak detector. Call here, passing in
672 suitable address-validating functions (see comment at top of
njn695c16e2005-03-27 03:40:28 +0000673 scan_all_valid_memory above). All this is to avoid duplication
nethercote996901a2004-08-03 13:29:09 +0000674 of the leak-detection code for Memcheck and Addrcheck.
675 Also pass in a tool-specific function to extract the .where field
njn43c799e2003-04-08 00:08:52 +0000676 for allocated blocks, an indication of the resolution wanted for
677 distinguishing different allocation points, and whether or not
678 reachable blocks should be shown.
679*/
680void MAC_(do_detect_memory_leaks) (
njnb8dca862005-03-14 02:42:44 +0000681 ThreadId tid, LeakCheckMode mode,
sewardj05fe85e2005-04-27 22:46:36 +0000682 Bool (*is_within_valid_secondary) ( Addr ),
683 Bool (*is_valid_aligned_word) ( Addr )
njn43c799e2003-04-08 00:08:52 +0000684)
685{
njnb8dca862005-03-14 02:42:44 +0000686 Int i;
njn43c799e2003-04-08 00:08:52 +0000687
sewardj76754cf2005-03-14 00:14:04 +0000688 tl_assert(mode != LC_Off);
njn43c799e2003-04-08 00:08:52 +0000689
njn06072ec2003-09-30 15:35:13 +0000690 /* VG_(HT_to_array) allocates storage for shadows */
691 lc_shadows = (MAC_Chunk**)VG_(HT_to_array)( MAC_(malloc_list),
692 &lc_n_shadows );
693
694 /* Sort the array. */
695 VG_(ssort)((void*)lc_shadows, lc_n_shadows, sizeof(VgHashNode*), lc_compar);
696
697 /* Sanity check; assert that the blocks are now in order */
698 for (i = 0; i < lc_n_shadows-1; i++) {
sewardj76754cf2005-03-14 00:14:04 +0000699 tl_assert( lc_shadows[i]->data <= lc_shadows[i+1]->data);
njn06072ec2003-09-30 15:35:13 +0000700 }
njn3e884182003-04-15 13:03:23 +0000701
702 /* Sanity check -- make sure they don't overlap */
703 for (i = 0; i < lc_n_shadows-1; i++) {
sewardj76754cf2005-03-14 00:14:04 +0000704 tl_assert( lc_shadows[i]->data + lc_shadows[i]->size
sewardj7e9ed712005-12-18 02:37:50 +0000705 <= lc_shadows[i+1]->data );
njn3e884182003-04-15 13:03:23 +0000706 }
707
708 if (lc_n_shadows == 0) {
sewardj76754cf2005-03-14 00:14:04 +0000709 tl_assert(lc_shadows == NULL);
sewardj71bc3cb2005-05-19 00:25:45 +0000710 if (VG_(clo_verbosity) >= 1 && !VG_(clo_xml)) {
sewardj37d06f22003-09-17 21:48:26 +0000711 VG_(message)(Vg_UserMsg,
712 "No malloc'd blocks -- no leaks are possible.");
713 }
njn43c799e2003-04-08 00:08:52 +0000714 return;
715 }
716
sewardj71bc3cb2005-05-19 00:25:45 +0000717 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
nethercote0f19bce2003-12-02 10:17:44 +0000718 VG_(message)(Vg_UserMsg,
njn0fd92f42005-10-06 03:32:42 +0000719 "searching for pointers to %,d not-freed blocks.",
nethercote0f19bce2003-12-02 10:17:44 +0000720 lc_n_shadows );
njn43c799e2003-04-08 00:08:52 +0000721
njn3e884182003-04-15 13:03:23 +0000722 lc_min_mallocd_addr = lc_shadows[0]->data;
723 lc_max_mallocd_addr = lc_shadows[lc_n_shadows-1]->data
sewardjb5f6f512005-03-10 23:59:00 +0000724 + lc_shadows[lc_n_shadows-1]->size;
njn43c799e2003-04-08 00:08:52 +0000725
sewardjb5f6f512005-03-10 23:59:00 +0000726 lc_markstack = VG_(malloc)( lc_n_shadows * sizeof(*lc_markstack) );
727 for (i = 0; i < lc_n_shadows; i++) {
728 lc_markstack[i].next = -1;
729 lc_markstack[i].state = Unreached;
730 lc_markstack[i].indirect = 0;
731 }
732 lc_markstack_top = -1;
njn43c799e2003-04-08 00:08:52 +0000733
sewardj05fe85e2005-04-27 22:46:36 +0000734 lc_is_within_valid_secondary = is_within_valid_secondary;
735 lc_is_valid_aligned_word = is_valid_aligned_word;
sewardjb5f6f512005-03-10 23:59:00 +0000736
737 lc_scanned = 0;
738
sewardj45f4e7c2005-09-27 19:20:21 +0000739 /* Push roots onto the mark stack. Roots are:
740 - the integer registers of all threads
741 - all mappings belonging to the client, including stacks
742 - .. but excluding any client heap segments.
743 Client heap segments are excluded because we wish to differentiate
744 client heap blocks which are referenced only from inside the heap
745 from those outside. This facilitates the indirect vs direct loss
746 categorisation, which [if the users ever manage to understand it]
747 is really useful for detecting lost cycles.
748 */
749 { NSegment* seg;
750 Addr* seg_starts;
751 Int n_seg_starts;
752 seg_starts = get_seg_starts( &n_seg_starts );
753 tl_assert(seg_starts && n_seg_starts > 0);
754 /* VG_(am_show_nsegments)( 0,"leakcheck"); */
755 for (i = 0; i < n_seg_starts; i++) {
756 seg = VG_(am_find_nsegment)( seg_starts[i] );
757 tl_assert(seg);
758 if (seg->kind != SkFileC && seg->kind != SkAnonC)
759 continue;
760 if (!(seg->hasR && seg->hasW))
761 continue;
762 if (seg->isCH)
763 continue;
764 if (0)
765 VG_(printf)("ACCEPT %2d %p %p\n", i, seg->start, seg->end);
766 lc_scan_memory(seg->start, seg->end+1 - seg->start);
767 }
768 }
sewardjb5f6f512005-03-10 23:59:00 +0000769
770 /* Push registers onto mark stack */
njn6ace3ea2005-06-17 03:06:27 +0000771 VG_(apply_to_GP_regs)(lc_markstack_push);
sewardjb5f6f512005-03-10 23:59:00 +0000772
773 /* Keep walking the heap until everything is found */
774 lc_do_leakcheck(-1);
njn43c799e2003-04-08 00:08:52 +0000775
sewardj71bc3cb2005-05-19 00:25:45 +0000776 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
njn0fd92f42005-10-06 03:32:42 +0000777 VG_(message)(Vg_UserMsg, "checked %,lu bytes.", lc_scanned);
njn43c799e2003-04-08 00:08:52 +0000778
njne8b5c052003-07-22 22:03:58 +0000779 blocks_leaked = MAC_(bytes_leaked) = 0;
sewardjb5f6f512005-03-10 23:59:00 +0000780 blocks_indirect = MAC_(bytes_indirect) = 0;
njne8b5c052003-07-22 22:03:58 +0000781 blocks_dubious = MAC_(bytes_dubious) = 0;
782 blocks_reachable = MAC_(bytes_reachable) = 0;
783 blocks_suppressed = MAC_(bytes_suppressed) = 0;
njn43c799e2003-04-08 00:08:52 +0000784
sewardjb5f6f512005-03-10 23:59:00 +0000785 if (mode == LC_Full)
njnb8dca862005-03-14 02:42:44 +0000786 full_report(tid);
sewardjb5f6f512005-03-10 23:59:00 +0000787 else
788 make_summary();
njn43c799e2003-04-08 00:08:52 +0000789
sewardj71bc3cb2005-05-19 00:25:45 +0000790 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) {
nethercote0f19bce2003-12-02 10:17:44 +0000791 VG_(message)(Vg_UserMsg, "");
792 VG_(message)(Vg_UserMsg, "LEAK SUMMARY:");
njn0fd92f42005-10-06 03:32:42 +0000793 VG_(message)(Vg_UserMsg, " definitely lost: %,lu bytes in %,lu blocks.",
nethercote0f19bce2003-12-02 10:17:44 +0000794 MAC_(bytes_leaked), blocks_leaked );
sewardjb5f6f512005-03-10 23:59:00 +0000795 if (blocks_indirect > 0)
njn0fd92f42005-10-06 03:32:42 +0000796 VG_(message)(Vg_UserMsg, " indirectly lost: %,lu bytes in %,lu blocks.",
sewardjb5f6f512005-03-10 23:59:00 +0000797 MAC_(bytes_indirect), blocks_indirect );
njn0fd92f42005-10-06 03:32:42 +0000798 VG_(message)(Vg_UserMsg, " possibly lost: %,lu bytes in %,lu blocks.",
nethercote0f19bce2003-12-02 10:17:44 +0000799 MAC_(bytes_dubious), blocks_dubious );
njn0fd92f42005-10-06 03:32:42 +0000800 VG_(message)(Vg_UserMsg, " still reachable: %,lu bytes in %,lu blocks.",
nethercote0f19bce2003-12-02 10:17:44 +0000801 MAC_(bytes_reachable), blocks_reachable );
njn0fd92f42005-10-06 03:32:42 +0000802 VG_(message)(Vg_UserMsg, " suppressed: %,lu bytes in %,lu blocks.",
nethercote0f19bce2003-12-02 10:17:44 +0000803 MAC_(bytes_suppressed), blocks_suppressed );
njn6a329422005-03-12 20:38:13 +0000804 if (mode == LC_Summary && blocks_leaked > 0)
sewardjb5f6f512005-03-10 23:59:00 +0000805 VG_(message)(Vg_UserMsg,
806 "Use --leak-check=full to see details of leaked memory.");
807 else if (!MAC_(clo_show_reachable)) {
nethercote0f19bce2003-12-02 10:17:44 +0000808 VG_(message)(Vg_UserMsg,
809 "Reachable blocks (those to which a pointer was found) are not shown.");
810 VG_(message)(Vg_UserMsg,
811 "To see them, rerun with: --show-reachable=yes");
812 }
njn43c799e2003-04-08 00:08:52 +0000813 }
njn43c799e2003-04-08 00:08:52 +0000814
njn3e884182003-04-15 13:03:23 +0000815 VG_(free) ( lc_shadows );
sewardjb5f6f512005-03-10 23:59:00 +0000816 VG_(free) ( lc_markstack );
njn43c799e2003-04-08 00:08:52 +0000817}
818
819/*--------------------------------------------------------------------*/
820/*--- end mac_leakcheck.c ---*/
821/*--------------------------------------------------------------------*/
822