blob: 7747dad92ecd8dc65503b01c4c0fa6eb774f5c5c [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"
njn73c51342005-06-18 15:18:15 +000045#include "pub_tool_signals.h"
njn43c799e2003-04-08 00:08:52 +000046
njnc7561b92005-06-19 01:24:32 +000047#include "mac_shared.h"
48
49#include <setjmp.h> // For jmp_buf
50
51
njn43c799e2003-04-08 00:08:52 +000052/* Define to debug the memory-leak-detector. */
sewardjb5f6f512005-03-10 23:59:00 +000053#define VG_DEBUG_LEAKCHECK 0
54#define VG_DEBUG_CLIQUE 0
55
njn43c799e2003-04-08 00:08:52 +000056/*------------------------------------------------------------*/
57/*--- Low-level address-space scanning, for the leak ---*/
58/*--- detector. ---*/
59/*------------------------------------------------------------*/
60
61static
62jmp_buf memscan_jmpbuf;
63
64
65static
njn695c16e2005-03-27 03:40:28 +000066void scan_all_valid_memory_catcher ( Int sigNo, Addr addr )
njn43c799e2003-04-08 00:08:52 +000067{
sewardjb5f6f512005-03-10 23:59:00 +000068 if (0)
69 VG_(printf)("OUCH! sig=%d addr=%p\n", sigNo, addr);
70 if (sigNo == VKI_SIGSEGV || sigNo == VKI_SIGBUS)
71 __builtin_longjmp(memscan_jmpbuf, 1);
njn43c799e2003-04-08 00:08:52 +000072}
73
sewardj45f4e7c2005-09-27 19:20:21 +000074
75/* TODO: GIVE THIS A PROPER HOME
76 TODO: MERGE THIS WITH DUPLICATE IN m_main.c
77 Extract from aspacem a vector of the current segment start
78 addresses. The vector is dynamically allocated and should be freed
79 by the caller when done. REQUIRES m_mallocfree to be running.
80 Writes the number of addresses required into *n_acquired. */
81
82static Addr* get_seg_starts ( /*OUT*/Int* n_acquired )
83{
84 Addr* starts;
sewardjae986ca2005-10-12 12:53:20 +000085 Int n_starts, r = 0;
sewardj45f4e7c2005-09-27 19:20:21 +000086
87 n_starts = 1;
88 while (True) {
89 starts = VG_(malloc)( n_starts * sizeof(Addr) );
90 if (starts == NULL)
91 break;
92 r = VG_(am_get_segment_starts)( starts, n_starts );
93 if (r >= 0)
94 break;
95 VG_(free)(starts);
96 n_starts *= 2;
97 }
98
99 if (starts == NULL) {
100 *n_acquired = 0;
101 return NULL;
102 }
103
104 *n_acquired = r;
105 return starts;
106}
107
108
njn43c799e2003-04-08 00:08:52 +0000109/*------------------------------------------------------------*/
110/*--- Detecting leaked (unreachable) malloc'd blocks. ---*/
111/*------------------------------------------------------------*/
112
113/* A block is either
114 -- Proper-ly reached; a pointer to its start has been found
115 -- Interior-ly reached; only an interior pointer to it has been found
116 -- Unreached; so far, no pointers to any part of it have been found.
sewardjb5f6f512005-03-10 23:59:00 +0000117 -- IndirectLeak; leaked, but referred to by another leaked block
njn43c799e2003-04-08 00:08:52 +0000118*/
sewardj45f4e7c2005-09-27 19:20:21 +0000119typedef
120 enum {
sewardj75d8eb92005-12-18 02:48:40 +0000121 Unreached =0,
122 IndirectLeak =1,
123 Interior =2,
124 Proper =3
sewardj45f4e7c2005-09-27 19:20:21 +0000125 }
126 Reachedness;
sewardjb5f6f512005-03-10 23:59:00 +0000127
128/* An entry in the mark stack */
sewardj45f4e7c2005-09-27 19:20:21 +0000129typedef
130 struct {
131 Int next:30; /* Index of next in mark stack */
132 UInt state:2; /* Reachedness */
133 SizeT indirect; /* if Unreached, how much is unreachable from here */
134 }
135 MarkStack;
njn43c799e2003-04-08 00:08:52 +0000136
137/* A block record, used for generating err msgs. */
138typedef
139 struct _LossRecord {
140 struct _LossRecord* next;
141 /* Where these lost blocks were allocated. */
142 ExeContext* allocated_at;
143 /* Their reachability. */
144 Reachedness loss_mode;
145 /* Number of blocks and total # bytes involved. */
njn0fd92f42005-10-06 03:32:42 +0000146 SizeT total_bytes;
147 SizeT indirect_bytes;
njn43c799e2003-04-08 00:08:52 +0000148 UInt num_blocks;
149 }
150 LossRecord;
151
njn02977032005-05-17 04:00:11 +0000152/* The 'extra' struct for leak errors. */
sewardj45f4e7c2005-09-27 19:20:21 +0000153typedef
154 struct {
155 UInt n_this_record;
156 UInt n_total_records;
157 LossRecord* lossRecord;
158 }
159 LeakExtra;
njn43c799e2003-04-08 00:08:52 +0000160
161/* Find the i such that ptr points at or inside the block described by
162 shadows[i]. Return -1 if none found. This assumes that shadows[]
163 has been sorted on the ->data field. */
164
sewardjb5f6f512005-03-10 23:59:00 +0000165#if VG_DEBUG_LEAKCHECK
njn43c799e2003-04-08 00:08:52 +0000166/* Used to sanity-check the fast binary-search mechanism. */
167static
njn3e884182003-04-15 13:03:23 +0000168Int find_shadow_for_OLD ( Addr ptr,
169 MAC_Chunk** shadows,
170 Int n_shadows )
njn43c799e2003-04-08 00:08:52 +0000171
172{
173 Int i;
174 Addr a_lo, a_hi;
tom16ade0d2005-07-18 09:41:57 +0000175 PROF_EVENT(70, "find_shadow_for_OLD");
njn43c799e2003-04-08 00:08:52 +0000176 for (i = 0; i < n_shadows; i++) {
tom16ade0d2005-07-18 09:41:57 +0000177 PROF_EVENT(71, "find_shadow_for_OLD(loop)");
njn43c799e2003-04-08 00:08:52 +0000178 a_lo = shadows[i]->data;
sewardjb5f6f512005-03-10 23:59:00 +0000179 a_hi = ((Addr)shadows[i]->data) + shadows[i]->size;
njn43c799e2003-04-08 00:08:52 +0000180 if (a_lo <= ptr && ptr <= a_hi)
181 return i;
182 }
183 return -1;
184}
185#endif
186
187
188static
njn3e884182003-04-15 13:03:23 +0000189Int find_shadow_for ( Addr ptr,
190 MAC_Chunk** shadows,
191 Int n_shadows )
njn43c799e2003-04-08 00:08:52 +0000192{
193 Addr a_mid_lo, a_mid_hi;
194 Int lo, mid, hi, retVal;
195 /* VG_(printf)("find shadow for %p = ", ptr); */
196 retVal = -1;
197 lo = 0;
198 hi = n_shadows-1;
199 while (True) {
njn3e884182003-04-15 13:03:23 +0000200 /* invariant: current unsearched space is from lo to hi, inclusive. */
njn43c799e2003-04-08 00:08:52 +0000201 if (lo > hi) break; /* not found */
202
203 mid = (lo + hi) / 2;
njn3e884182003-04-15 13:03:23 +0000204 a_mid_lo = shadows[mid]->data;
sewardjb5f6f512005-03-10 23:59:00 +0000205 a_mid_hi = shadows[mid]->data + shadows[mid]->size;
njn43c799e2003-04-08 00:08:52 +0000206
207 if (ptr < a_mid_lo) {
208 hi = mid-1;
209 continue;
210 }
211 if (ptr > a_mid_hi) {
212 lo = mid+1;
213 continue;
214 }
sewardj76754cf2005-03-14 00:14:04 +0000215 tl_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
njn43c799e2003-04-08 00:08:52 +0000216 retVal = mid;
217 break;
218 }
219
sewardjb5f6f512005-03-10 23:59:00 +0000220# if VG_DEBUG_LEAKCHECK
sewardj76754cf2005-03-14 00:14:04 +0000221 tl_assert(retVal == find_shadow_for_OLD ( ptr, shadows, n_shadows ));
njn43c799e2003-04-08 00:08:52 +0000222# endif
223 /* VG_(printf)("%d\n", retVal); */
224 return retVal;
225}
226
227/* Globals, for the following callback used by VG_(detect_memory_leaks). */
njn3e884182003-04-15 13:03:23 +0000228static MAC_Chunk** lc_shadows;
229static Int lc_n_shadows;
sewardjb5f6f512005-03-10 23:59:00 +0000230static MarkStack* lc_markstack;
231static Int lc_markstack_top;
njn3e884182003-04-15 13:03:23 +0000232static Addr lc_min_mallocd_addr;
233static Addr lc_max_mallocd_addr;
sewardjb5f6f512005-03-10 23:59:00 +0000234static SizeT lc_scanned;
njn43c799e2003-04-08 00:08:52 +0000235
sewardj05fe85e2005-04-27 22:46:36 +0000236static Bool (*lc_is_within_valid_secondary) (Addr addr);
237static Bool (*lc_is_valid_aligned_word) (Addr addr);
sewardjb5f6f512005-03-10 23:59:00 +0000238
sewardj71bc3cb2005-05-19 00:25:45 +0000239static const HChar* str_lossmode ( Reachedness lossmode )
njn43c799e2003-04-08 00:08:52 +0000240{
sewardj71bc3cb2005-05-19 00:25:45 +0000241 const HChar *loss = "?";
242 switch (lossmode) {
243 case Unreached: loss = "definitely lost"; break;
244 case IndirectLeak: loss = "indirectly lost"; break;
245 case Interior: loss = "possibly lost"; break;
246 case Proper: loss = "still reachable"; break;
njn43c799e2003-04-08 00:08:52 +0000247 }
sewardjb5f6f512005-03-10 23:59:00 +0000248 return loss;
njn43c799e2003-04-08 00:08:52 +0000249}
250
sewardj71bc3cb2005-05-19 00:25:45 +0000251static const HChar* xml_kind ( Reachedness lossmode )
252{
253 const HChar *loss = "?";
254 switch (lossmode) {
255 case Unreached: loss = "Leak_DefinitelyLost"; break;
256 case IndirectLeak: loss = "Leak_IndirectlyLost"; break;
257 case Interior: loss = "Leak_PossiblyLost"; break;
258 case Proper: loss = "Leak_StillReachable"; break;
259 }
260 return loss;
261}
262
263
njn43c799e2003-04-08 00:08:52 +0000264/* Used for printing leak errors, avoids exposing the LossRecord type (which
265 comes in as void*, requiring a cast. */
njn02977032005-05-17 04:00:11 +0000266void MAC_(pp_LeakError)(void* vextra)
njn43c799e2003-04-08 00:08:52 +0000267{
sewardj71bc3cb2005-05-19 00:25:45 +0000268 HChar* xpre = VG_(clo_xml) ? " <what>" : "";
269 HChar* xpost = VG_(clo_xml) ? "</what>" : "";
270
njn02977032005-05-17 04:00:11 +0000271 LeakExtra* extra = (LeakExtra*)vextra;
272 LossRecord* l = extra->lossRecord;
273 const Char *loss = str_lossmode(l->loss_mode);
njn43c799e2003-04-08 00:08:52 +0000274
sewardj71bc3cb2005-05-19 00:25:45 +0000275 if (VG_(clo_xml)) {
sewardj97f7e0c2005-07-19 15:00:25 +0000276 VG_(message)(Vg_UserMsg, " <kind>%t</kind>", xml_kind(l->loss_mode));
sewardj71bc3cb2005-05-19 00:25:45 +0000277 } else {
278 VG_(message)(Vg_UserMsg, "");
279 }
280
sewardjb5f6f512005-03-10 23:59:00 +0000281 if (l->indirect_bytes) {
282 VG_(message)(Vg_UserMsg,
njn0fd92f42005-10-06 03:32:42 +0000283 "%s%,lu (%,lu direct, %,lu indirect) bytes in %,u blocks"
284 " are %s in loss record %,u of %,u%s",
sewardj71bc3cb2005-05-19 00:25:45 +0000285 xpre,
286 l->total_bytes + l->indirect_bytes,
287 l->total_bytes, l->indirect_bytes, l->num_blocks,
288 loss, extra->n_this_record, extra->n_total_records,
289 xpost
290 );
291 if (VG_(clo_xml)) {
njn0fd92f42005-10-06 03:32:42 +0000292 // Nb: don't put commas in these XML numbers
293 VG_(message)(Vg_UserMsg, " <leakedbytes>%lu</leakedbytes>",
sewardj71bc3cb2005-05-19 00:25:45 +0000294 l->total_bytes + l->indirect_bytes);
njn0fd92f42005-10-06 03:32:42 +0000295 VG_(message)(Vg_UserMsg, " <leakedblocks>%u</leakedblocks>",
sewardj71bc3cb2005-05-19 00:25:45 +0000296 l->num_blocks);
297 }
sewardjb5f6f512005-03-10 23:59:00 +0000298 } else {
sewardj71bc3cb2005-05-19 00:25:45 +0000299 VG_(message)(
300 Vg_UserMsg,
njn0fd92f42005-10-06 03:32:42 +0000301 "%s%,lu bytes in %,u blocks are %s in loss record %,u of %,u%s",
sewardj71bc3cb2005-05-19 00:25:45 +0000302 xpre,
303 l->total_bytes, l->num_blocks,
304 loss, extra->n_this_record, extra->n_total_records,
305 xpost
306 );
307 if (VG_(clo_xml)) {
308 VG_(message)(Vg_UserMsg, " <leakedbytes>%d</leakedbytes>",
309 l->total_bytes);
310 VG_(message)(Vg_UserMsg, " <leakedblocks>%d</leakedblocks>",
311 l->num_blocks);
312 }
sewardjb5f6f512005-03-10 23:59:00 +0000313 }
njn43c799e2003-04-08 00:08:52 +0000314 VG_(pp_ExeContext)(l->allocated_at);
315}
316
njn0fd92f42005-10-06 03:32:42 +0000317SizeT MAC_(bytes_leaked) = 0;
318SizeT MAC_(bytes_indirect) = 0;
319SizeT MAC_(bytes_dubious) = 0;
320SizeT MAC_(bytes_reachable) = 0;
321SizeT MAC_(bytes_suppressed) = 0;
njn47363ab2003-04-21 13:24:40 +0000322
njn06072ec2003-09-30 15:35:13 +0000323static Int lc_compar(void* n1, void* n2)
324{
325 MAC_Chunk* mc1 = *(MAC_Chunk**)n1;
326 MAC_Chunk* mc2 = *(MAC_Chunk**)n2;
327 return (mc1->data < mc2->data ? -1 : 1);
328}
329
sewardjb5f6f512005-03-10 23:59:00 +0000330/* If ptr is pointing to a heap-allocated block which hasn't been seen
331 before, push it onto the mark stack. Clique is the index of the
332 clique leader; -1 if none. */
sewardj45f4e7c2005-09-27 19:20:21 +0000333static void lc_markstack_push_WRK(Addr ptr, Int clique)
sewardjb5f6f512005-03-10 23:59:00 +0000334{
335 Int sh_no;
336
sewardj45f4e7c2005-09-27 19:20:21 +0000337 /* quick filter */
338 if (!VG_(am_is_valid_for_client)(ptr, 1, VKI_PROT_NONE))
sewardjb5f6f512005-03-10 23:59:00 +0000339 return;
340
341 sh_no = find_shadow_for(ptr, lc_shadows, lc_n_shadows);
342
343 if (VG_DEBUG_LEAKCHECK)
344 VG_(printf)("ptr=%p -> block %d\n", ptr, sh_no);
345
346 if (sh_no == -1)
347 return;
348
sewardj76754cf2005-03-14 00:14:04 +0000349 tl_assert(sh_no >= 0 && sh_no < lc_n_shadows);
350 tl_assert(ptr <= lc_shadows[sh_no]->data + lc_shadows[sh_no]->size);
sewardjb5f6f512005-03-10 23:59:00 +0000351
352 if (lc_markstack[sh_no].state == Unreached) {
353 if (0)
354 VG_(printf)("pushing %p-%p\n", lc_shadows[sh_no]->data,
355 lc_shadows[sh_no]->data + lc_shadows[sh_no]->size);
356
sewardj76754cf2005-03-14 00:14:04 +0000357 tl_assert(lc_markstack[sh_no].next == -1);
sewardjb5f6f512005-03-10 23:59:00 +0000358 lc_markstack[sh_no].next = lc_markstack_top;
359 lc_markstack_top = sh_no;
360 }
361
sewardj45f4e7c2005-09-27 19:20:21 +0000362 tl_assert(clique >= -1 && clique < lc_n_shadows);
363
sewardjb5f6f512005-03-10 23:59:00 +0000364 if (clique != -1) {
365 if (0)
366 VG_(printf)("mopup: %d: %p is %d\n",
367 sh_no, lc_shadows[sh_no]->data, lc_markstack[sh_no].state);
368
369 /* An unmarked block - add it to the clique. Add its size to
370 the clique-leader's indirect size. If the new block was
371 itself a clique leader, it isn't any more, so add its
372 indirect to the new clique leader.
373
374 If this block *is* the clique leader, it means this is a
375 cyclic structure, so none of this applies. */
376 if (lc_markstack[sh_no].state == Unreached) {
377 lc_markstack[sh_no].state = IndirectLeak;
378
379 if (sh_no != clique) {
380 if (VG_DEBUG_CLIQUE) {
381 if (lc_markstack[sh_no].indirect)
382 VG_(printf)(" clique %d joining clique %d adding %d+%d bytes\n",
383 sh_no, clique,
384 lc_shadows[sh_no]->size, lc_markstack[sh_no].indirect);
385 else
386 VG_(printf)(" %d joining %d adding %d\n",
387 sh_no, clique, lc_shadows[sh_no]->size);
388 }
389
390 lc_markstack[clique].indirect += lc_shadows[sh_no]->size;
391 lc_markstack[clique].indirect += lc_markstack[sh_no].indirect;
392 lc_markstack[sh_no].indirect = 0; /* shouldn't matter */
393 }
394 }
395 } else if (ptr == lc_shadows[sh_no]->data) {
396 lc_markstack[sh_no].state = Proper;
397 } else {
398 if (lc_markstack[sh_no].state == Unreached)
399 lc_markstack[sh_no].state = Interior;
400 }
401}
402
403static void lc_markstack_push(Addr ptr)
404{
sewardj45f4e7c2005-09-27 19:20:21 +0000405 lc_markstack_push_WRK(ptr, -1);
sewardjb5f6f512005-03-10 23:59:00 +0000406}
407
408/* Return the top of the mark stack, if any. */
409static Int lc_markstack_pop(void)
410{
411 Int ret = lc_markstack_top;
412
413 if (ret != -1) {
414 lc_markstack_top = lc_markstack[ret].next;
415 lc_markstack[ret].next = -1;
416 }
417
418 return ret;
419}
420
sewardj45d94cc2005-04-20 14:44:11 +0000421
sewardjb5f6f512005-03-10 23:59:00 +0000422/* Scan a block of memory between [start, start+len). This range may
423 be bogus, inaccessable, or otherwise strange; we deal with it.
424
425 If clique != -1, it means we're gathering leaked memory into
426 cliques, and clique is the index of the current clique leader. */
sewardj45f4e7c2005-09-27 19:20:21 +0000427static void lc_scan_memory_WRK(Addr start, SizeT len, Int clique)
sewardjb5f6f512005-03-10 23:59:00 +0000428{
njn13bfd852005-06-02 03:52:53 +0000429 Addr ptr = VG_ROUNDUP(start, sizeof(Addr));
430 Addr end = VG_ROUNDDN(start+len, sizeof(Addr));
sewardjb5f6f512005-03-10 23:59:00 +0000431 vki_sigset_t sigmask;
432
433 if (VG_DEBUG_LEAKCHECK)
tom16ade0d2005-07-18 09:41:57 +0000434 VG_(printf)("scan %p-%p\n", start, start+len);
sewardjb5f6f512005-03-10 23:59:00 +0000435 VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &sigmask);
njn695c16e2005-03-27 03:40:28 +0000436 VG_(set_fault_catcher)(scan_all_valid_memory_catcher);
sewardjb5f6f512005-03-10 23:59:00 +0000437
sewardj45f4e7c2005-09-27 19:20:21 +0000438 // lc_scanned += end-ptr;
sewardjb5f6f512005-03-10 23:59:00 +0000439
sewardj45f4e7c2005-09-27 19:20:21 +0000440 if (!VG_(am_is_valid_for_client)(ptr, sizeof(Addr), VKI_PROT_READ))
njn13bfd852005-06-02 03:52:53 +0000441 ptr = VG_PGROUNDUP(ptr+1); /* first page bad */
sewardjb5f6f512005-03-10 23:59:00 +0000442
sewardj05fe85e2005-04-27 22:46:36 +0000443 while (ptr < end) {
sewardjb5f6f512005-03-10 23:59:00 +0000444 Addr addr;
445
446 /* Skip invalid chunks */
sewardj05fe85e2005-04-27 22:46:36 +0000447 if (!(*lc_is_within_valid_secondary)(ptr)) {
njn13bfd852005-06-02 03:52:53 +0000448 ptr = VG_ROUNDUP(ptr+1, SECONDARY_SIZE);
sewardjb5f6f512005-03-10 23:59:00 +0000449 continue;
450 }
451
452 /* Look to see if this page seems reasonble */
453 if ((ptr % VKI_PAGE_SIZE) == 0) {
sewardj45f4e7c2005-09-27 19:20:21 +0000454 if (!VG_(am_is_valid_for_client)(ptr, sizeof(Addr), VKI_PROT_READ))
sewardjb5f6f512005-03-10 23:59:00 +0000455 ptr += VKI_PAGE_SIZE; /* bad page - skip it */
456 }
457
458 if (__builtin_setjmp(memscan_jmpbuf) == 0) {
sewardj05fe85e2005-04-27 22:46:36 +0000459 if ((*lc_is_valid_aligned_word)(ptr)) {
sewardj45f4e7c2005-09-27 19:20:21 +0000460 lc_scanned += sizeof(Addr);
sewardjb5f6f512005-03-10 23:59:00 +0000461 addr = *(Addr *)ptr;
sewardj45f4e7c2005-09-27 19:20:21 +0000462 lc_markstack_push_WRK(addr, clique);
sewardjb5f6f512005-03-10 23:59:00 +0000463 } else if (0 && VG_DEBUG_LEAKCHECK)
464 VG_(printf)("%p not valid\n", ptr);
465 ptr += sizeof(Addr);
466 } else {
467 /* We need to restore the signal mask, because we were
468 longjmped out of a signal handler. */
469 VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL);
470
njn13bfd852005-06-02 03:52:53 +0000471 ptr = VG_PGROUNDUP(ptr+1); /* bad page - skip it */
sewardjb5f6f512005-03-10 23:59:00 +0000472 }
473 }
474
475 VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL);
476 VG_(set_fault_catcher)(NULL);
477}
478
sewardj45d94cc2005-04-20 14:44:11 +0000479
sewardjb5f6f512005-03-10 23:59:00 +0000480static void lc_scan_memory(Addr start, SizeT len)
481{
sewardj45f4e7c2005-09-27 19:20:21 +0000482 lc_scan_memory_WRK(start, len, -1);
sewardjb5f6f512005-03-10 23:59:00 +0000483}
484
485/* Process the mark stack until empty. If mopup is true, then we're
486 actually gathering leaked blocks, so they should be marked
487 IndirectLeak. */
488static void lc_do_leakcheck(Int clique)
489{
490 Int top;
491
492 while((top = lc_markstack_pop()) != -1) {
sewardj76754cf2005-03-14 00:14:04 +0000493 tl_assert(top >= 0 && top < lc_n_shadows);
494 tl_assert(lc_markstack[top].state != Unreached);
sewardjb5f6f512005-03-10 23:59:00 +0000495
sewardj45f4e7c2005-09-27 19:20:21 +0000496 lc_scan_memory_WRK(lc_shadows[top]->data, lc_shadows[top]->size, clique);
sewardjb5f6f512005-03-10 23:59:00 +0000497 }
498}
499
njn0fd92f42005-10-06 03:32:42 +0000500static SizeT blocks_leaked;
501static SizeT blocks_indirect;
502static SizeT blocks_dubious;
503static SizeT blocks_reachable;
504static SizeT blocks_suppressed;
sewardjb5f6f512005-03-10 23:59:00 +0000505
njnb8dca862005-03-14 02:42:44 +0000506static void full_report(ThreadId tid)
sewardjb5f6f512005-03-10 23:59:00 +0000507{
508 Int i;
509 Int n_lossrecords;
510 LossRecord* errlist;
511 LossRecord* p;
512 Bool is_suppressed;
njn02977032005-05-17 04:00:11 +0000513 LeakExtra leak_extra;
sewardjb5f6f512005-03-10 23:59:00 +0000514
515 /* Go through and group lost structures into cliques. For each
516 Unreached block, push it onto the mark stack, and find all the
517 blocks linked to it. These are marked IndirectLeak, and their
518 size is added to the clique leader's indirect size. If one of
519 the found blocks was itself a clique leader (from a previous
520 pass), then the cliques are merged. */
521 for (i = 0; i < lc_n_shadows; i++) {
522 if (VG_DEBUG_CLIQUE)
523 VG_(printf)("cliques: %d at %p -> %s\n",
njn02977032005-05-17 04:00:11 +0000524 i, lc_shadows[i]->data, str_lossmode(lc_markstack[i].state));
sewardjb5f6f512005-03-10 23:59:00 +0000525 if (lc_markstack[i].state != Unreached)
526 continue;
527
sewardj76754cf2005-03-14 00:14:04 +0000528 tl_assert(lc_markstack_top == -1);
sewardjb5f6f512005-03-10 23:59:00 +0000529
530 if (VG_DEBUG_CLIQUE)
531 VG_(printf)("%d: gathering clique %p\n", i, lc_shadows[i]->data);
532
sewardj45f4e7c2005-09-27 19:20:21 +0000533 lc_markstack_push_WRK(lc_shadows[i]->data, i);
sewardjb5f6f512005-03-10 23:59:00 +0000534
535 lc_do_leakcheck(i);
536
sewardj76754cf2005-03-14 00:14:04 +0000537 tl_assert(lc_markstack_top == -1);
sewardj75d8eb92005-12-18 02:48:40 +0000538 tl_assert(lc_markstack[i].state == IndirectLeak
539 /* jrs 20051218: Ashley Pittman supplied a
540 custom-allocator test program which causes the ==
541 IndirectLeak condition to fail - it causes .state
542 to be Unreached. Since I have no idea how this
543 clique stuff works and no time to figure it out,
544 just allow that condition too. This could well be
545 a completely bogus fix. It doesn't seem unsafe
546 given that in any case the .state field is
547 immediately overwritten by the next statement. */
548 || lc_markstack[i].state == Unreached);
sewardjb5f6f512005-03-10 23:59:00 +0000549
550 lc_markstack[i].state = Unreached; /* Return to unreached state,
551 to indicate its a clique
552 leader */
553 }
554
555 /* Common up the lost blocks so we can print sensible error messages. */
556 n_lossrecords = 0;
557 errlist = NULL;
558 for (i = 0; i < lc_n_shadows; i++) {
559 ExeContext* where = lc_shadows[i]->where;
560
561 for (p = errlist; p != NULL; p = p->next) {
562 if (p->loss_mode == lc_markstack[i].state
563 && VG_(eq_ExeContext) ( MAC_(clo_leak_resolution),
564 p->allocated_at,
565 where) ) {
566 break;
567 }
568 }
569 if (p != NULL) {
570 p->num_blocks ++;
571 p->total_bytes += lc_shadows[i]->size;
572 p->indirect_bytes += lc_markstack[i].indirect;
573 } else {
574 n_lossrecords ++;
575 p = VG_(malloc)(sizeof(LossRecord));
576 p->loss_mode = lc_markstack[i].state;
577 p->allocated_at = where;
578 p->total_bytes = lc_shadows[i]->size;
579 p->indirect_bytes = lc_markstack[i].indirect;
580 p->num_blocks = 1;
581 p->next = errlist;
582 errlist = p;
583 }
584 }
585
586 /* Print out the commoned-up blocks and collect summary stats. */
587 for (i = 0; i < n_lossrecords; i++) {
588 Bool print_record;
589 LossRecord* p_min = NULL;
njn0fd92f42005-10-06 03:32:42 +0000590 SizeT n_min = ~(0x0L);
sewardjb5f6f512005-03-10 23:59:00 +0000591 for (p = errlist; p != NULL; p = p->next) {
592 if (p->num_blocks > 0 && p->total_bytes < n_min) {
593 n_min = p->total_bytes + p->indirect_bytes;
594 p_min = p;
595 }
596 }
sewardj76754cf2005-03-14 00:14:04 +0000597 tl_assert(p_min != NULL);
sewardjb5f6f512005-03-10 23:59:00 +0000598
599 /* Ok to have tst==NULL; it's only used if --gdb-attach=yes, and
600 we disallow that when --leak-check=yes.
601
njn02977032005-05-17 04:00:11 +0000602 Prints the error if not suppressed, unless it's reachable (Proper
603 or IndirectLeak) and --show-reachable=no */
sewardjb5f6f512005-03-10 23:59:00 +0000604
605 print_record = ( MAC_(clo_show_reachable) ||
njn02977032005-05-17 04:00:11 +0000606 Unreached == p_min->loss_mode ||
607 Interior == p_min->loss_mode );
608
609 // Nb: because VG_(unique_error) does all the error processing
610 // immediately, and doesn't save the error, leakExtra can be
611 // stack-allocated.
612 leak_extra.n_this_record = i+1;
613 leak_extra.n_total_records = n_lossrecords;
614 leak_extra.lossRecord = p_min;
sewardjb5f6f512005-03-10 23:59:00 +0000615 is_suppressed =
njn02977032005-05-17 04:00:11 +0000616 VG_(unique_error) ( tid, LeakErr, /*Addr*/0, /*s*/NULL,
617 /*extra*/&leak_extra,
618 /*where*/p_min->allocated_at, print_record,
sewardjb5f6f512005-03-10 23:59:00 +0000619 /*allow_GDB_attach*/False, /*count_error*/False );
620
621 if (is_suppressed) {
622 blocks_suppressed += p_min->num_blocks;
623 MAC_(bytes_suppressed) += p_min->total_bytes;
624
625 } else if (Unreached == p_min->loss_mode) {
626 blocks_leaked += p_min->num_blocks;
627 MAC_(bytes_leaked) += p_min->total_bytes;
628
629 } else if (IndirectLeak == p_min->loss_mode) {
630 blocks_indirect += p_min->num_blocks;
631 MAC_(bytes_indirect)+= p_min->total_bytes;
632
633 } else if (Interior == p_min->loss_mode) {
634 blocks_dubious += p_min->num_blocks;
635 MAC_(bytes_dubious) += p_min->total_bytes;
636
637 } else if (Proper == p_min->loss_mode) {
638 blocks_reachable += p_min->num_blocks;
639 MAC_(bytes_reachable) += p_min->total_bytes;
640
641 } else {
sewardj76754cf2005-03-14 00:14:04 +0000642 VG_(tool_panic)("generic_detect_memory_leaks: unknown loss mode");
sewardjb5f6f512005-03-10 23:59:00 +0000643 }
644 p_min->num_blocks = 0;
645 }
646}
647
648/* Compute a quick summary of the leak check. */
tom151a6392005-11-11 12:30:36 +0000649static void make_summary(void)
sewardjb5f6f512005-03-10 23:59:00 +0000650{
651 Int i;
652
653 for(i = 0; i < lc_n_shadows; i++) {
654 SizeT size = lc_shadows[i]->size;
655
656 switch(lc_markstack[i].state) {
657 case Unreached:
658 blocks_leaked++;
659 MAC_(bytes_leaked) += size;
660 break;
661
662 case Proper:
663 blocks_reachable++;
664 MAC_(bytes_reachable) += size;
665 break;
666
667 case Interior:
668 blocks_dubious++;
669 MAC_(bytes_dubious) += size;
670 break;
671
672 case IndirectLeak: /* shouldn't happen */
673 blocks_indirect++;
674 MAC_(bytes_indirect) += size;
675 break;
676 }
677 }
678}
679
njn43c799e2003-04-08 00:08:52 +0000680/* Top level entry point to leak detector. Call here, passing in
681 suitable address-validating functions (see comment at top of
njn695c16e2005-03-27 03:40:28 +0000682 scan_all_valid_memory above). All this is to avoid duplication
nethercote996901a2004-08-03 13:29:09 +0000683 of the leak-detection code for Memcheck and Addrcheck.
684 Also pass in a tool-specific function to extract the .where field
njn43c799e2003-04-08 00:08:52 +0000685 for allocated blocks, an indication of the resolution wanted for
686 distinguishing different allocation points, and whether or not
687 reachable blocks should be shown.
688*/
689void MAC_(do_detect_memory_leaks) (
njnb8dca862005-03-14 02:42:44 +0000690 ThreadId tid, LeakCheckMode mode,
sewardj05fe85e2005-04-27 22:46:36 +0000691 Bool (*is_within_valid_secondary) ( Addr ),
692 Bool (*is_valid_aligned_word) ( Addr )
njn43c799e2003-04-08 00:08:52 +0000693)
694{
njnb8dca862005-03-14 02:42:44 +0000695 Int i;
njn43c799e2003-04-08 00:08:52 +0000696
sewardj76754cf2005-03-14 00:14:04 +0000697 tl_assert(mode != LC_Off);
njn43c799e2003-04-08 00:08:52 +0000698
njn06072ec2003-09-30 15:35:13 +0000699 /* VG_(HT_to_array) allocates storage for shadows */
700 lc_shadows = (MAC_Chunk**)VG_(HT_to_array)( MAC_(malloc_list),
701 &lc_n_shadows );
702
703 /* Sort the array. */
704 VG_(ssort)((void*)lc_shadows, lc_n_shadows, sizeof(VgHashNode*), lc_compar);
705
706 /* Sanity check; assert that the blocks are now in order */
707 for (i = 0; i < lc_n_shadows-1; i++) {
sewardj76754cf2005-03-14 00:14:04 +0000708 tl_assert( lc_shadows[i]->data <= lc_shadows[i+1]->data);
njn06072ec2003-09-30 15:35:13 +0000709 }
njn3e884182003-04-15 13:03:23 +0000710
711 /* Sanity check -- make sure they don't overlap */
712 for (i = 0; i < lc_n_shadows-1; i++) {
sewardj76754cf2005-03-14 00:14:04 +0000713 tl_assert( lc_shadows[i]->data + lc_shadows[i]->size
sewardj7e9ed712005-12-18 02:37:50 +0000714 <= lc_shadows[i+1]->data );
njn3e884182003-04-15 13:03:23 +0000715 }
716
717 if (lc_n_shadows == 0) {
sewardj76754cf2005-03-14 00:14:04 +0000718 tl_assert(lc_shadows == NULL);
sewardj71bc3cb2005-05-19 00:25:45 +0000719 if (VG_(clo_verbosity) >= 1 && !VG_(clo_xml)) {
sewardj37d06f22003-09-17 21:48:26 +0000720 VG_(message)(Vg_UserMsg,
njn6b239582005-12-19 19:33:36 +0000721 "All heap blocks were freed -- no leaks are possible.");
sewardj37d06f22003-09-17 21:48:26 +0000722 }
njn43c799e2003-04-08 00:08:52 +0000723 return;
724 }
725
sewardj71bc3cb2005-05-19 00:25:45 +0000726 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
nethercote0f19bce2003-12-02 10:17:44 +0000727 VG_(message)(Vg_UserMsg,
njn0fd92f42005-10-06 03:32:42 +0000728 "searching for pointers to %,d not-freed blocks.",
nethercote0f19bce2003-12-02 10:17:44 +0000729 lc_n_shadows );
njn43c799e2003-04-08 00:08:52 +0000730
njn3e884182003-04-15 13:03:23 +0000731 lc_min_mallocd_addr = lc_shadows[0]->data;
732 lc_max_mallocd_addr = lc_shadows[lc_n_shadows-1]->data
sewardjb5f6f512005-03-10 23:59:00 +0000733 + lc_shadows[lc_n_shadows-1]->size;
njn43c799e2003-04-08 00:08:52 +0000734
sewardjb5f6f512005-03-10 23:59:00 +0000735 lc_markstack = VG_(malloc)( lc_n_shadows * sizeof(*lc_markstack) );
736 for (i = 0; i < lc_n_shadows; i++) {
737 lc_markstack[i].next = -1;
738 lc_markstack[i].state = Unreached;
739 lc_markstack[i].indirect = 0;
740 }
741 lc_markstack_top = -1;
njn43c799e2003-04-08 00:08:52 +0000742
sewardj05fe85e2005-04-27 22:46:36 +0000743 lc_is_within_valid_secondary = is_within_valid_secondary;
744 lc_is_valid_aligned_word = is_valid_aligned_word;
sewardjb5f6f512005-03-10 23:59:00 +0000745
746 lc_scanned = 0;
747
sewardj45f4e7c2005-09-27 19:20:21 +0000748 /* Push roots onto the mark stack. Roots are:
749 - the integer registers of all threads
750 - all mappings belonging to the client, including stacks
751 - .. but excluding any client heap segments.
752 Client heap segments are excluded because we wish to differentiate
753 client heap blocks which are referenced only from inside the heap
754 from those outside. This facilitates the indirect vs direct loss
755 categorisation, which [if the users ever manage to understand it]
756 is really useful for detecting lost cycles.
757 */
758 { NSegment* seg;
759 Addr* seg_starts;
760 Int n_seg_starts;
761 seg_starts = get_seg_starts( &n_seg_starts );
762 tl_assert(seg_starts && n_seg_starts > 0);
763 /* VG_(am_show_nsegments)( 0,"leakcheck"); */
764 for (i = 0; i < n_seg_starts; i++) {
765 seg = VG_(am_find_nsegment)( seg_starts[i] );
766 tl_assert(seg);
767 if (seg->kind != SkFileC && seg->kind != SkAnonC)
768 continue;
769 if (!(seg->hasR && seg->hasW))
770 continue;
771 if (seg->isCH)
772 continue;
773 if (0)
774 VG_(printf)("ACCEPT %2d %p %p\n", i, seg->start, seg->end);
775 lc_scan_memory(seg->start, seg->end+1 - seg->start);
776 }
777 }
sewardjb5f6f512005-03-10 23:59:00 +0000778
779 /* Push registers onto mark stack */
njn6ace3ea2005-06-17 03:06:27 +0000780 VG_(apply_to_GP_regs)(lc_markstack_push);
sewardjb5f6f512005-03-10 23:59:00 +0000781
782 /* Keep walking the heap until everything is found */
783 lc_do_leakcheck(-1);
njn43c799e2003-04-08 00:08:52 +0000784
sewardj71bc3cb2005-05-19 00:25:45 +0000785 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml))
njn0fd92f42005-10-06 03:32:42 +0000786 VG_(message)(Vg_UserMsg, "checked %,lu bytes.", lc_scanned);
njn43c799e2003-04-08 00:08:52 +0000787
njne8b5c052003-07-22 22:03:58 +0000788 blocks_leaked = MAC_(bytes_leaked) = 0;
sewardjb5f6f512005-03-10 23:59:00 +0000789 blocks_indirect = MAC_(bytes_indirect) = 0;
njne8b5c052003-07-22 22:03:58 +0000790 blocks_dubious = MAC_(bytes_dubious) = 0;
791 blocks_reachable = MAC_(bytes_reachable) = 0;
792 blocks_suppressed = MAC_(bytes_suppressed) = 0;
njn43c799e2003-04-08 00:08:52 +0000793
sewardjb5f6f512005-03-10 23:59:00 +0000794 if (mode == LC_Full)
njnb8dca862005-03-14 02:42:44 +0000795 full_report(tid);
sewardjb5f6f512005-03-10 23:59:00 +0000796 else
797 make_summary();
njn43c799e2003-04-08 00:08:52 +0000798
sewardj71bc3cb2005-05-19 00:25:45 +0000799 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) {
nethercote0f19bce2003-12-02 10:17:44 +0000800 VG_(message)(Vg_UserMsg, "");
801 VG_(message)(Vg_UserMsg, "LEAK SUMMARY:");
njn0fd92f42005-10-06 03:32:42 +0000802 VG_(message)(Vg_UserMsg, " definitely lost: %,lu bytes in %,lu blocks.",
nethercote0f19bce2003-12-02 10:17:44 +0000803 MAC_(bytes_leaked), blocks_leaked );
sewardjb5f6f512005-03-10 23:59:00 +0000804 if (blocks_indirect > 0)
njn0fd92f42005-10-06 03:32:42 +0000805 VG_(message)(Vg_UserMsg, " indirectly lost: %,lu bytes in %,lu blocks.",
sewardjb5f6f512005-03-10 23:59:00 +0000806 MAC_(bytes_indirect), blocks_indirect );
njn0fd92f42005-10-06 03:32:42 +0000807 VG_(message)(Vg_UserMsg, " possibly lost: %,lu bytes in %,lu blocks.",
nethercote0f19bce2003-12-02 10:17:44 +0000808 MAC_(bytes_dubious), blocks_dubious );
njn0fd92f42005-10-06 03:32:42 +0000809 VG_(message)(Vg_UserMsg, " still reachable: %,lu bytes in %,lu blocks.",
nethercote0f19bce2003-12-02 10:17:44 +0000810 MAC_(bytes_reachable), blocks_reachable );
njn0fd92f42005-10-06 03:32:42 +0000811 VG_(message)(Vg_UserMsg, " suppressed: %,lu bytes in %,lu blocks.",
nethercote0f19bce2003-12-02 10:17:44 +0000812 MAC_(bytes_suppressed), blocks_suppressed );
njn6a329422005-03-12 20:38:13 +0000813 if (mode == LC_Summary && blocks_leaked > 0)
sewardjb5f6f512005-03-10 23:59:00 +0000814 VG_(message)(Vg_UserMsg,
815 "Use --leak-check=full to see details of leaked memory.");
816 else if (!MAC_(clo_show_reachable)) {
nethercote0f19bce2003-12-02 10:17:44 +0000817 VG_(message)(Vg_UserMsg,
818 "Reachable blocks (those to which a pointer was found) are not shown.");
819 VG_(message)(Vg_UserMsg,
820 "To see them, rerun with: --show-reachable=yes");
821 }
njn43c799e2003-04-08 00:08:52 +0000822 }
njn43c799e2003-04-08 00:08:52 +0000823
njn3e884182003-04-15 13:03:23 +0000824 VG_(free) ( lc_shadows );
sewardjb5f6f512005-03-10 23:59:00 +0000825 VG_(free) ( lc_markstack );
njn43c799e2003-04-08 00:08:52 +0000826}
827
828/*--------------------------------------------------------------------*/
829/*--- end mac_leakcheck.c ---*/
830/*--------------------------------------------------------------------*/
831