blob: ff0381aea8195aa9b7502221b1e94697b62e32b9 [file] [log] [blame]
bartbedfd232009-03-26 19:07:15 +00001/* -*- mode: C; c-basic-offset: 3; -*- */
sewardjaf44c822007-11-25 14:01:38 +00002/*
bart86562bd2009-02-16 19:43:56 +00003 This file is part of drd, a thread error detector.
sewardjaf44c822007-11-25 14:01:38 +00004
bart86562bd2009-02-16 19:43:56 +00005 Copyright (C) 2006-2009 Bart Van Assche <bart.vanassche@gmail.com>.
sewardjaf44c822007-11-25 14:01:38 +00006
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307, USA.
21
22 The GNU General Public License is contained in the file COPYING.
23*/
24
25
26#include "drd_malloc_wrappers.h"
27#include "drd_thread.h"
28#include "pub_tool_basics.h"
29#include "pub_tool_execontext.h"
30#include "pub_tool_hashtable.h"
31#include "pub_tool_libcassert.h"
32#include "pub_tool_libcbase.h"
33#include "pub_tool_libcprint.h"
34#include "pub_tool_mallocfree.h"
35#include "pub_tool_options.h"
36#include "pub_tool_replacemalloc.h"
37#include "pub_tool_threadstate.h"
38#include "pub_tool_tooliface.h"
39
40
bart246fbf22009-02-15 14:46:17 +000041/* Local type definitions. */
sewardjaf44c822007-11-25 14:01:38 +000042
43typedef struct _DRD_Chunk {
bartbedfd232009-03-26 19:07:15 +000044 struct _DRD_Chunk* next;
45 Addr data; // ptr to actual block
46 SizeT size : (sizeof(UWord)*8)-2; //size requested; 30 or 62 bits
47 ExeContext* where; // where it was allocated
sewardjaf44c822007-11-25 14:01:38 +000048} DRD_Chunk;
49
bart246fbf22009-02-15 14:46:17 +000050
51/* Local variables. */
52
bartba0818d2009-05-01 12:21:39 +000053static StartUsingMem s_start_using_mem_callback;
54static StopUsingMem s_stop_using_mem_callback;
sewardjaf44c822007-11-25 14:01:38 +000055/* Stats ... */
bartba0818d2009-05-01 12:21:39 +000056static SizeT s_cmalloc_n_mallocs = 0;
57static SizeT s_cmalloc_n_frees = 0;
58static SizeT s_cmalloc_bs_mallocd = 0;
bart246fbf22009-02-15 14:46:17 +000059/* Record malloc'd blocks. */
bartba0818d2009-05-01 12:21:39 +000060static VgHashTable s_malloc_list = NULL;
sewardjaf44c822007-11-25 14:01:38 +000061
62
63/*------------------------------------------------------------*/
64/*--- Tracking malloc'd and free'd blocks ---*/
65/*------------------------------------------------------------*/
66
bart246fbf22009-02-15 14:46:17 +000067/** Allocate its shadow chunk, put it on the appropriate list. */
bartba0818d2009-05-01 12:21:39 +000068static DRD_Chunk* create_chunk(ThreadId tid, Addr p, SizeT size)
sewardjaf44c822007-11-25 14:01:38 +000069{
bartbedfd232009-03-26 19:07:15 +000070 DRD_Chunk* mc = VG_(malloc)("drd.malloc_wrappers.cDC.1",
71 sizeof(DRD_Chunk));
72 mc->data = p;
73 mc->size = size;
74 mc->where = VG_(record_ExeContext)(tid, 0);
sewardjaf44c822007-11-25 14:01:38 +000075
bartbedfd232009-03-26 19:07:15 +000076 return mc;
sewardjaf44c822007-11-25 14:01:38 +000077}
78
79/*------------------------------------------------------------*/
80/*--- client_malloc(), etc ---*/
81/*------------------------------------------------------------*/
82
83/* Allocate memory and note change in memory available */
bartba0818d2009-05-01 12:21:39 +000084static void* new_block(ThreadId tid, SizeT size, SizeT align, Bool is_zeroed)
sewardjaf44c822007-11-25 14:01:38 +000085{
bartbedfd232009-03-26 19:07:15 +000086 Addr p;
sewardjaf44c822007-11-25 14:01:38 +000087
bartba0818d2009-05-01 12:21:39 +000088 s_cmalloc_n_mallocs ++;
sewardjaf44c822007-11-25 14:01:38 +000089
bartbedfd232009-03-26 19:07:15 +000090 // Allocate and zero
91 p = (Addr)VG_(cli_malloc)(align, size);
92 if (!p) {
93 return NULL;
94 }
95 if (is_zeroed) VG_(memset)((void*)p, 0, size);
sewardjaf44c822007-11-25 14:01:38 +000096
bartba0818d2009-05-01 12:21:39 +000097 DRD_(malloclike_block)(tid, p, size);
sewardjaf44c822007-11-25 14:01:38 +000098
bartbedfd232009-03-26 19:07:15 +000099 return (void*)p;
sewardjaf44c822007-11-25 14:01:38 +0000100}
101
bartba0818d2009-05-01 12:21:39 +0000102/**
103 * Store information about a memory block that has been allocated by
104 * malloc() or a malloc() replacement.
105 */
106void DRD_(malloclike_block)(const ThreadId tid, const Addr p, const SizeT size)
107{
108 tl_assert(p);
109
110 s_start_using_mem_callback(p, p + size, 0/*ec_uniq*/);
111
112 // Only update this stat if allocation succeeded.
113 s_cmalloc_bs_mallocd += size;
114
115 VG_(HT_add_node)(s_malloc_list, create_chunk(tid, p, size));
116}
117
bart246fbf22009-02-15 14:46:17 +0000118static void* DRD_(malloc)(ThreadId tid, SizeT n)
sewardjaf44c822007-11-25 14:01:38 +0000119{
bartba0818d2009-05-01 12:21:39 +0000120 return new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000121}
122
bart246fbf22009-02-15 14:46:17 +0000123static void* DRD_(memalign)(ThreadId tid, SizeT align, SizeT n)
sewardjaf44c822007-11-25 14:01:38 +0000124{
bartba0818d2009-05-01 12:21:39 +0000125 return new_block(tid, n, align, /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000126}
127
bart246fbf22009-02-15 14:46:17 +0000128static void* DRD_(calloc)(ThreadId tid, SizeT nmemb, SizeT size1)
sewardjaf44c822007-11-25 14:01:38 +0000129{
bartba0818d2009-05-01 12:21:39 +0000130 return new_block(tid, nmemb*size1, VG_(clo_alignment),
bartbedfd232009-03-26 19:07:15 +0000131 /*is_zeroed*/True);
sewardjaf44c822007-11-25 14:01:38 +0000132}
133
bartba0818d2009-05-01 12:21:39 +0000134/**
135 * Remove the information that was stored by DRD_(malloclike_block)() about
136 * a memory block.
137 */
138Bool DRD_(freelike_block)(const ThreadId tid, const Addr p)
sewardjaf44c822007-11-25 14:01:38 +0000139{
bartbedfd232009-03-26 19:07:15 +0000140 DRD_Chunk* mc;
sewardjaf44c822007-11-25 14:01:38 +0000141
bartba0818d2009-05-01 12:21:39 +0000142 tl_assert(p);
sewardjaf44c822007-11-25 14:01:38 +0000143
bartba0818d2009-05-01 12:21:39 +0000144 s_cmalloc_n_frees++;
145
146 mc = VG_(HT_remove)(s_malloc_list, (UWord)p);
147 if (mc)
bartbedfd232009-03-26 19:07:15 +0000148 {
149 tl_assert(p == mc->data);
150 if (mc->size > 0)
bartba0818d2009-05-01 12:21:39 +0000151 s_stop_using_mem_callback(mc->data, mc->size);
bartbedfd232009-03-26 19:07:15 +0000152 VG_(free)(mc);
bartba0818d2009-05-01 12:21:39 +0000153 return True;
bartbedfd232009-03-26 19:07:15 +0000154 }
bartba0818d2009-05-01 12:21:39 +0000155 return False;
156}
157
158static void handle_free(ThreadId tid, Addr p)
159{
160 if (DRD_(freelike_block)(tid, p))
161 VG_(cli_free)((void*)p);
162 else
163 tl_assert(False);
sewardjaf44c822007-11-25 14:01:38 +0000164}
165
bart246fbf22009-02-15 14:46:17 +0000166static void DRD_(free)(ThreadId tid, void* p)
sewardjaf44c822007-11-25 14:01:38 +0000167{
bartba0818d2009-05-01 12:21:39 +0000168 handle_free(tid, (Addr)p);
sewardjaf44c822007-11-25 14:01:38 +0000169}
170
bart246fbf22009-02-15 14:46:17 +0000171static void* DRD_(realloc)(ThreadId tid, void* p_old, SizeT new_size)
sewardjaf44c822007-11-25 14:01:38 +0000172{
bartbedfd232009-03-26 19:07:15 +0000173 DRD_Chunk* mc;
174 void* p_new;
175 SizeT old_size;
sewardjaf44c822007-11-25 14:01:38 +0000176
bartba0818d2009-05-01 12:21:39 +0000177 s_cmalloc_n_frees ++;
178 s_cmalloc_n_mallocs ++;
179 s_cmalloc_bs_mallocd += new_size;
sewardjaf44c822007-11-25 14:01:38 +0000180
bartbedfd232009-03-26 19:07:15 +0000181 /* Remove the old block */
bartba0818d2009-05-01 12:21:39 +0000182 mc = VG_(HT_remove)(s_malloc_list, (UWord)p_old);
bartbedfd232009-03-26 19:07:15 +0000183 if (mc == NULL) {
184 tl_assert(0);
185 return NULL;
186 }
sewardjaf44c822007-11-25 14:01:38 +0000187
bartbedfd232009-03-26 19:07:15 +0000188 old_size = mc->size;
sewardjaf44c822007-11-25 14:01:38 +0000189
bartbedfd232009-03-26 19:07:15 +0000190 if (old_size == new_size)
191 {
192 /* size unchanged */
193 mc->where = VG_(record_ExeContext)(tid, 0);
194 p_new = p_old;
sewardjaf44c822007-11-25 14:01:38 +0000195
bartbedfd232009-03-26 19:07:15 +0000196 }
197 else if (old_size > new_size)
198 {
199 /* new size is smaller */
bartba0818d2009-05-01 12:21:39 +0000200 s_stop_using_mem_callback(mc->data + new_size, old_size);
bartbedfd232009-03-26 19:07:15 +0000201 mc->size = new_size;
202 mc->where = VG_(record_ExeContext)(tid, 0);
203 p_new = p_old;
sewardjaf44c822007-11-25 14:01:38 +0000204
bartbedfd232009-03-26 19:07:15 +0000205 }
206 else
207 {
208 /* new size is bigger */
209 /* Get new memory */
210 const Addr a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
sewardjaf44c822007-11-25 14:01:38 +0000211
bartbedfd232009-03-26 19:07:15 +0000212 if (a_new)
213 {
214 /* Copy from old to new */
215 VG_(memcpy)((void*)a_new, p_old, mc->size);
sewardjaf44c822007-11-25 14:01:38 +0000216
bartbedfd232009-03-26 19:07:15 +0000217 /* Free old memory */
bartba0818d2009-05-01 12:21:39 +0000218 s_stop_using_mem_callback(mc->data, mc->size);
bartbedfd232009-03-26 19:07:15 +0000219 VG_(free)(mc);
sewardjaf44c822007-11-25 14:01:38 +0000220
bartbedfd232009-03-26 19:07:15 +0000221 // Allocate a new chunk.
bartba0818d2009-05-01 12:21:39 +0000222 mc = create_chunk(tid, a_new, new_size);
223 s_start_using_mem_callback(a_new, a_new + new_size,
bartbedfd232009-03-26 19:07:15 +0000224 0/*ec_uniq*/);
225 }
226 else
227 {
228 /* Allocation failed -- leave original block untouched. */
229 }
sewardjaf44c822007-11-25 14:01:38 +0000230
bartbedfd232009-03-26 19:07:15 +0000231 p_new = (void*)a_new;
232 }
sewardjaf44c822007-11-25 14:01:38 +0000233
bartbedfd232009-03-26 19:07:15 +0000234 // Now insert the new mc (with a possibly new 'data' field) into
235 // malloc_list. If this realloc() did not increase the memory size, we
236 // will have removed and then re-added mc unnecessarily. But that's ok
237 // because shrinking a block with realloc() is (presumably) much rarer
238 // than growing it, and this way simplifies the growing case.
bartba0818d2009-05-01 12:21:39 +0000239 VG_(HT_add_node)(s_malloc_list, mc);
sewardjaf44c822007-11-25 14:01:38 +0000240
bartbedfd232009-03-26 19:07:15 +0000241 return p_new;
sewardjaf44c822007-11-25 14:01:38 +0000242}
243
bart246fbf22009-02-15 14:46:17 +0000244static void* DRD_(__builtin_new)(ThreadId tid, SizeT n)
sewardjaf44c822007-11-25 14:01:38 +0000245{
bartba0818d2009-05-01 12:21:39 +0000246 void* const result = new_block(tid, n, VG_(clo_alignment),
bartbedfd232009-03-26 19:07:15 +0000247 /*is_zeroed*/False);
248 //VG_(message)(Vg_DebugMsg, "__builtin_new(%d, %d) = %p", tid, n, result);
249 return result;
sewardjaf44c822007-11-25 14:01:38 +0000250}
251
bart246fbf22009-02-15 14:46:17 +0000252static void DRD_(__builtin_delete)(ThreadId tid, void* p)
sewardjaf44c822007-11-25 14:01:38 +0000253{
bartbedfd232009-03-26 19:07:15 +0000254 //VG_(message)(Vg_DebugMsg, "__builtin_delete(%d, %p)", tid, p);
bartba0818d2009-05-01 12:21:39 +0000255 handle_free(tid, (Addr)p);
sewardjaf44c822007-11-25 14:01:38 +0000256}
257
bart246fbf22009-02-15 14:46:17 +0000258static void* DRD_(__builtin_vec_new)(ThreadId tid, SizeT n)
sewardjaf44c822007-11-25 14:01:38 +0000259{
bartba0818d2009-05-01 12:21:39 +0000260 return new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000261}
262
bart246fbf22009-02-15 14:46:17 +0000263static void DRD_(__builtin_vec_delete)(ThreadId tid, void* p)
sewardjaf44c822007-11-25 14:01:38 +0000264{
bartba0818d2009-05-01 12:21:39 +0000265 handle_free(tid, (Addr)p);
sewardjaf44c822007-11-25 14:01:38 +0000266}
267
njn8b140de2009-02-17 04:31:18 +0000268static SizeT DRD_(malloc_usable_size) ( ThreadId tid, void* p )
269{
bartba0818d2009-05-01 12:21:39 +0000270 DRD_Chunk *mc = VG_(HT_lookup)( s_malloc_list, (UWord)p );
njn8b140de2009-02-17 04:31:18 +0000271
272 // There may be slop, but pretend there isn't because only the asked-for
273 // area will have been shadowed properly.
274 return ( mc ? mc->size : 0 );
275}
276
bart246fbf22009-02-15 14:46:17 +0000277void DRD_(register_malloc_wrappers)(const StartUsingMem start_callback,
278 const StopUsingMem stop_callback)
sewardjaf44c822007-11-25 14:01:38 +0000279{
bartba0818d2009-05-01 12:21:39 +0000280 tl_assert(s_malloc_list == 0);
281 s_malloc_list = VG_(HT_construct)("drd_malloc_list"); // a big prime
282 tl_assert(s_malloc_list != 0);
bartbedfd232009-03-26 19:07:15 +0000283 tl_assert(start_callback);
284 tl_assert(stop_callback);
sewardjaf44c822007-11-25 14:01:38 +0000285
bartba0818d2009-05-01 12:21:39 +0000286 s_start_using_mem_callback = start_callback;
287 s_stop_using_mem_callback = stop_callback;
sewardjaf44c822007-11-25 14:01:38 +0000288
bartbedfd232009-03-26 19:07:15 +0000289 VG_(needs_malloc_replacement)(DRD_(malloc),
290 DRD_(__builtin_new),
291 DRD_(__builtin_vec_new),
292 DRD_(memalign),
293 DRD_(calloc),
294 DRD_(free),
295 DRD_(__builtin_delete),
296 DRD_(__builtin_vec_delete),
297 DRD_(realloc),
298 DRD_(malloc_usable_size),
299 0);
sewardjaf44c822007-11-25 14:01:38 +0000300}
301
bart246fbf22009-02-15 14:46:17 +0000302Bool DRD_(heap_addrinfo)(Addr const a,
303 Addr* const data,
304 SizeT* const size,
305 ExeContext** const where)
sewardjaf44c822007-11-25 14:01:38 +0000306{
bartbedfd232009-03-26 19:07:15 +0000307 DRD_Chunk* mc;
sewardjaf44c822007-11-25 14:01:38 +0000308
bartbedfd232009-03-26 19:07:15 +0000309 tl_assert(data);
310 tl_assert(size);
311 tl_assert(where);
sewardjaf44c822007-11-25 14:01:38 +0000312
bartba0818d2009-05-01 12:21:39 +0000313 VG_(HT_ResetIter)(s_malloc_list);
314 while ((mc = VG_(HT_Next)(s_malloc_list)))
bartbedfd232009-03-26 19:07:15 +0000315 {
316 if (mc->data <= a && a < mc->data + mc->size)
317 {
318 *data = mc->data;
319 *size = mc->size;
320 *where = mc->where;
321 return True;
322 }
323 }
324 return False;
sewardjaf44c822007-11-25 14:01:38 +0000325}
326
327/*------------------------------------------------------------*/
328/*--- Statistics printing ---*/
329/*------------------------------------------------------------*/
330
bart246fbf22009-02-15 14:46:17 +0000331void DRD_(print_malloc_stats)(void)
sewardjaf44c822007-11-25 14:01:38 +0000332{
bartbedfd232009-03-26 19:07:15 +0000333 DRD_Chunk* mc;
334 SizeT nblocks = 0;
335 SizeT nbytes = 0;
sewardjaf44c822007-11-25 14:01:38 +0000336
bartbedfd232009-03-26 19:07:15 +0000337 if (VG_(clo_verbosity) == 0)
338 return;
339 if (VG_(clo_xml))
340 return;
sewardjaf44c822007-11-25 14:01:38 +0000341
bartbedfd232009-03-26 19:07:15 +0000342 /* Count memory still in use. */
bartba0818d2009-05-01 12:21:39 +0000343 VG_(HT_ResetIter)(s_malloc_list);
344 while ((mc = VG_(HT_Next)(s_malloc_list)))
bartbedfd232009-03-26 19:07:15 +0000345 {
346 nblocks++;
347 nbytes += mc->size;
348 }
sewardjaf44c822007-11-25 14:01:38 +0000349
bartbedfd232009-03-26 19:07:15 +0000350 VG_(message)(Vg_DebugMsg,
351 "malloc/free: in use at exit: %lu bytes in %lu blocks.",
352 nbytes, nblocks);
353 VG_(message)(Vg_DebugMsg,
354 "malloc/free: %lu allocs, %lu frees, %lu bytes allocated.",
bartba0818d2009-05-01 12:21:39 +0000355 s_cmalloc_n_mallocs,
356 s_cmalloc_n_frees, s_cmalloc_bs_mallocd);
bartbedfd232009-03-26 19:07:15 +0000357 if (VG_(clo_verbosity) > 1)
358 VG_(message)(Vg_DebugMsg, " ");
sewardjaf44c822007-11-25 14:01:38 +0000359}
360
361/*--------------------------------------------------------------------*/
362/*--- end ---*/
363/*--------------------------------------------------------------------*/