blob: 1e6e26759447f5ab243bda2c66981e7aab2259d5 [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
bart876cafd2010-10-10 18:07:31 +00005 Copyright (C) 2006-2010 Bart Van Assche <bvanassche@acm.org>.
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
bart5fd28142009-06-10 19:24:20 +000043/**
44 * Node with per-allocation information that will be stored in a hash map.
45 * As specified in <pub_tool_hashtable.h>, the first member must be a pointer
46 * and the second member must be an UWord.
47 */
sewardjaf44c822007-11-25 14:01:38 +000048typedef struct _DRD_Chunk {
bartbedfd232009-03-26 19:07:15 +000049 struct _DRD_Chunk* next;
bart5fd28142009-06-10 19:24:20 +000050 UWord data; // pointer to actual block
51 SizeT size; // size requested
52 ExeContext* where; // where it was allocated
sewardjaf44c822007-11-25 14:01:38 +000053} DRD_Chunk;
54
bart246fbf22009-02-15 14:46:17 +000055
56/* Local variables. */
57
bartba0818d2009-05-01 12:21:39 +000058static StartUsingMem s_start_using_mem_callback;
59static StopUsingMem s_stop_using_mem_callback;
bart5fd28142009-06-10 19:24:20 +000060/* Statistics. */
bartba0818d2009-05-01 12:21:39 +000061static SizeT s_cmalloc_n_mallocs = 0;
62static SizeT s_cmalloc_n_frees = 0;
63static SizeT s_cmalloc_bs_mallocd = 0;
bart246fbf22009-02-15 14:46:17 +000064/* Record malloc'd blocks. */
bartba0818d2009-05-01 12:21:39 +000065static VgHashTable s_malloc_list = NULL;
sewardjaf44c822007-11-25 14:01:38 +000066
67
bart5fd28142009-06-10 19:24:20 +000068/* Function definitions. */
sewardjaf44c822007-11-25 14:01:38 +000069
bart5fd28142009-06-10 19:24:20 +000070/** Allocate client memory memory and update the hash map. */
bartba0818d2009-05-01 12:21:39 +000071static void* new_block(ThreadId tid, SizeT size, SizeT align, Bool is_zeroed)
sewardjaf44c822007-11-25 14:01:38 +000072{
bart5fd28142009-06-10 19:24:20 +000073 void* p;
sewardjaf44c822007-11-25 14:01:38 +000074
bart5fd28142009-06-10 19:24:20 +000075 p = VG_(cli_malloc)(align, size);
76 if (!p)
bartbedfd232009-03-26 19:07:15 +000077 return NULL;
bart5fd28142009-06-10 19:24:20 +000078 if (is_zeroed)
79 VG_(memset)(p, 0, size);
sewardjaf44c822007-11-25 14:01:38 +000080
bart5fd28142009-06-10 19:24:20 +000081 DRD_(malloclike_block)(tid, (Addr)p, size);
sewardjaf44c822007-11-25 14:01:38 +000082
bart5fd28142009-06-10 19:24:20 +000083 return p;
sewardjaf44c822007-11-25 14:01:38 +000084}
85
bartba0818d2009-05-01 12:21:39 +000086/**
87 * Store information about a memory block that has been allocated by
bart5fd28142009-06-10 19:24:20 +000088 * malloc() or a malloc() replacement in the hash map.
bartba0818d2009-05-01 12:21:39 +000089 */
90void DRD_(malloclike_block)(const ThreadId tid, const Addr p, const SizeT size)
91{
bart5fd28142009-06-10 19:24:20 +000092 DRD_Chunk* mc;
93
bartba0818d2009-05-01 12:21:39 +000094 tl_assert(p);
95
bart5fd28142009-06-10 19:24:20 +000096 if (size > 0)
97 s_start_using_mem_callback(p, size, 0/*ec_uniq*/);
bartba0818d2009-05-01 12:21:39 +000098
bart5fd28142009-06-10 19:24:20 +000099 s_cmalloc_n_mallocs++;
bartba0818d2009-05-01 12:21:39 +0000100 // Only update this stat if allocation succeeded.
101 s_cmalloc_bs_mallocd += size;
102
bart5fd28142009-06-10 19:24:20 +0000103 mc = VG_(malloc)("drd.malloc_wrappers.cDC.1", sizeof(DRD_Chunk));
104 mc->data = p;
105 mc->size = size;
106 mc->where = VG_(record_ExeContext)(tid, 0);
107 VG_(HT_add_node)(s_malloc_list, mc);
bartba0818d2009-05-01 12:21:39 +0000108}
109
bart5fd28142009-06-10 19:24:20 +0000110static void handle_free(ThreadId tid, void* p)
sewardjaf44c822007-11-25 14:01:38 +0000111{
bartfc08a532011-03-12 12:43:39 +0000112 Bool success;
sewardjaf44c822007-11-25 14:01:38 +0000113
bartfc08a532011-03-12 12:43:39 +0000114 tl_assert(p);
115 success = DRD_(freelike_block)(tid, (Addr)p, True);
116 tl_assert(success);
sewardjaf44c822007-11-25 14:01:38 +0000117}
118
bartba0818d2009-05-01 12:21:39 +0000119/**
120 * Remove the information that was stored by DRD_(malloclike_block)() about
121 * a memory block.
122 */
bartfc08a532011-03-12 12:43:39 +0000123Bool DRD_(freelike_block)(const ThreadId tid, const Addr p, const Bool dealloc)
sewardjaf44c822007-11-25 14:01:38 +0000124{
bartbedfd232009-03-26 19:07:15 +0000125 DRD_Chunk* mc;
sewardjaf44c822007-11-25 14:01:38 +0000126
bartba0818d2009-05-01 12:21:39 +0000127 tl_assert(p);
sewardjaf44c822007-11-25 14:01:38 +0000128
bartba0818d2009-05-01 12:21:39 +0000129 s_cmalloc_n_frees++;
130
bart639d0ad2011-03-12 14:26:01 +0000131 mc = VG_(HT_lookup)(s_malloc_list, (UWord)p);
bartba0818d2009-05-01 12:21:39 +0000132 if (mc)
bartbedfd232009-03-26 19:07:15 +0000133 {
134 tl_assert(p == mc->data);
bartfc08a532011-03-12 12:43:39 +0000135 if (dealloc)
136 VG_(cli_free)((void*)p);
bartbedfd232009-03-26 19:07:15 +0000137 if (mc->size > 0)
bartba0818d2009-05-01 12:21:39 +0000138 s_stop_using_mem_callback(mc->data, mc->size);
bart639d0ad2011-03-12 14:26:01 +0000139 VG_(HT_remove)(s_malloc_list, (UWord)p);
bartbedfd232009-03-26 19:07:15 +0000140 VG_(free)(mc);
bartba0818d2009-05-01 12:21:39 +0000141 return True;
bartbedfd232009-03-26 19:07:15 +0000142 }
bartba0818d2009-05-01 12:21:39 +0000143 return False;
144}
145
bart5fd28142009-06-10 19:24:20 +0000146/** Wrapper for malloc(). */
147static void* drd_malloc(ThreadId tid, SizeT n)
bartba0818d2009-05-01 12:21:39 +0000148{
bart5fd28142009-06-10 19:24:20 +0000149 return new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000150}
151
bart5fd28142009-06-10 19:24:20 +0000152/** Wrapper for memalign(). */
153static void* drd_memalign(ThreadId tid, SizeT align, SizeT n)
sewardjaf44c822007-11-25 14:01:38 +0000154{
bart5fd28142009-06-10 19:24:20 +0000155 return new_block(tid, n, align, /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000156}
157
bart5fd28142009-06-10 19:24:20 +0000158/** Wrapper for calloc(). */
159static void* drd_calloc(ThreadId tid, SizeT nmemb, SizeT size1)
160{
161 return new_block(tid, nmemb*size1, VG_(clo_alignment),
162 /*is_zeroed*/True);
163}
164
165/** Wrapper for free(). */
166static void drd_free(ThreadId tid, void* p)
167{
168 handle_free(tid, p);
169}
170
171/**
172 * Wrapper for realloc(). Returns a pointer to the new block of memory, or
173 * NULL if no new block could not be allocated. Notes:
174 * - realloc(NULL, size) has the same effect as malloc(size).
175 * - realloc(p, 0) has the same effect as free(p).
176 * - success is not guaranteed even if the requested size is smaller than the
177 * allocated size.
178*/
179static void* drd_realloc(ThreadId tid, void* p_old, SizeT new_size)
sewardjaf44c822007-11-25 14:01:38 +0000180{
bartbedfd232009-03-26 19:07:15 +0000181 DRD_Chunk* mc;
bart5fd28142009-06-10 19:24:20 +0000182 void* p_new;
183 SizeT old_size;
sewardjaf44c822007-11-25 14:01:38 +0000184
bart5fd28142009-06-10 19:24:20 +0000185 if (! p_old)
186 return drd_malloc(tid, new_size);
187
188 if (new_size == 0)
189 {
190 drd_free(tid, p_old);
191 return NULL;
192 }
193
194 s_cmalloc_n_mallocs++;
195 s_cmalloc_n_frees++;
bartba0818d2009-05-01 12:21:39 +0000196 s_cmalloc_bs_mallocd += new_size;
sewardjaf44c822007-11-25 14:01:38 +0000197
bart5fd28142009-06-10 19:24:20 +0000198 mc = VG_(HT_lookup)(s_malloc_list, (UWord)p_old);
199 if (mc == NULL)
200 {
bartbedfd232009-03-26 19:07:15 +0000201 tl_assert(0);
202 return NULL;
203 }
sewardjaf44c822007-11-25 14:01:38 +0000204
bartbedfd232009-03-26 19:07:15 +0000205 old_size = mc->size;
sewardjaf44c822007-11-25 14:01:38 +0000206
bartbedfd232009-03-26 19:07:15 +0000207 if (old_size == new_size)
208 {
209 /* size unchanged */
210 mc->where = VG_(record_ExeContext)(tid, 0);
211 p_new = p_old;
bartbedfd232009-03-26 19:07:15 +0000212 }
bart5fd28142009-06-10 19:24:20 +0000213 else if (new_size < old_size)
bartbedfd232009-03-26 19:07:15 +0000214 {
bart5fd28142009-06-10 19:24:20 +0000215 /* new size is smaller but nonzero */
bart5b61bda2009-06-09 11:12:07 +0000216 s_stop_using_mem_callback(mc->data + new_size, old_size - new_size);
bartbedfd232009-03-26 19:07:15 +0000217 mc->size = new_size;
218 mc->where = VG_(record_ExeContext)(tid, 0);
219 p_new = p_old;
bartbedfd232009-03-26 19:07:15 +0000220 }
221 else
222 {
223 /* new size is bigger */
bart5fd28142009-06-10 19:24:20 +0000224 p_new = VG_(cli_malloc)(VG_(clo_alignment), new_size);
sewardjaf44c822007-11-25 14:01:38 +0000225
bart5fd28142009-06-10 19:24:20 +0000226 if (p_new)
bartbedfd232009-03-26 19:07:15 +0000227 {
bart5fd28142009-06-10 19:24:20 +0000228 /* Copy from old to new. */
229 VG_(memcpy)(p_new, p_old, mc->size);
bart31b983d2010-02-21 14:52:59 +0000230
bart5fd28142009-06-10 19:24:20 +0000231 /* Free old memory. */
232 VG_(cli_free)(p_old);
bart83e7eb62009-07-25 13:28:24 +0000233 if (mc->size > 0)
234 s_stop_using_mem_callback(mc->data, mc->size);
bart5fd28142009-06-10 19:24:20 +0000235 VG_(HT_remove)(s_malloc_list, (UWord)p_old);
sewardjaf44c822007-11-25 14:01:38 +0000236
bart5fd28142009-06-10 19:24:20 +0000237 /* Update state information. */
238 mc->data = (Addr)p_new;
239 mc->size = new_size;
240 mc->where = VG_(record_ExeContext)(tid, 0);
241 VG_(HT_add_node)(s_malloc_list, mc);
242 s_start_using_mem_callback((Addr)p_new, new_size, 0/*ec_uniq*/);
bartbedfd232009-03-26 19:07:15 +0000243 }
244 else
245 {
246 /* Allocation failed -- leave original block untouched. */
247 }
bart31b983d2010-02-21 14:52:59 +0000248 }
sewardjaf44c822007-11-25 14:01:38 +0000249
bartbedfd232009-03-26 19:07:15 +0000250 return p_new;
sewardjaf44c822007-11-25 14:01:38 +0000251}
252
bart5fd28142009-06-10 19:24:20 +0000253/** Wrapper for __builtin_new(). */
254static void* drd___builtin_new(ThreadId tid, SizeT n)
sewardjaf44c822007-11-25 14:01:38 +0000255{
bartba0818d2009-05-01 12:21:39 +0000256 return new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000257}
258
bart5fd28142009-06-10 19:24:20 +0000259/** Wrapper for __builtin_delete(). */
260static void drd___builtin_delete(ThreadId tid, void* p)
sewardjaf44c822007-11-25 14:01:38 +0000261{
bart5fd28142009-06-10 19:24:20 +0000262 handle_free(tid, p);
sewardjaf44c822007-11-25 14:01:38 +0000263}
264
bart5fd28142009-06-10 19:24:20 +0000265/** Wrapper for __builtin_vec_new(). */
266static void* drd___builtin_vec_new(ThreadId tid, SizeT n)
njn8b140de2009-02-17 04:31:18 +0000267{
bart5fd28142009-06-10 19:24:20 +0000268 return new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
269}
njn8b140de2009-02-17 04:31:18 +0000270
bart5fd28142009-06-10 19:24:20 +0000271/** Wrapper for __builtin_vec_delete(). */
272static void drd___builtin_vec_delete(ThreadId tid, void* p)
273{
274 handle_free(tid, p);
275}
276
277/**
278 * Wrapper for malloc_usable_size() / malloc_size(). This function takes
279 * a pointer to a block allocated by `malloc' and returns the amount of space
280 * that is available in the block. This may or may not be more than the size
281 * requested from `malloc', due to alignment or minimum size constraints.
282 */
283static SizeT drd_malloc_usable_size(ThreadId tid, void* p)
284{
285 DRD_Chunk* mc;
286
287 mc = VG_(HT_lookup)(s_malloc_list, (UWord)p);
288
289 return mc ? mc->size : 0;
njn8b140de2009-02-17 04:31:18 +0000290}
291
bart246fbf22009-02-15 14:46:17 +0000292void DRD_(register_malloc_wrappers)(const StartUsingMem start_callback,
293 const StopUsingMem stop_callback)
sewardjaf44c822007-11-25 14:01:38 +0000294{
bartba0818d2009-05-01 12:21:39 +0000295 tl_assert(s_malloc_list == 0);
bart5fd28142009-06-10 19:24:20 +0000296 s_malloc_list = VG_(HT_construct)("drd_malloc_list");
297 tl_assert(s_malloc_list);
bartbedfd232009-03-26 19:07:15 +0000298 tl_assert(start_callback);
299 tl_assert(stop_callback);
sewardjaf44c822007-11-25 14:01:38 +0000300
bartba0818d2009-05-01 12:21:39 +0000301 s_start_using_mem_callback = start_callback;
302 s_stop_using_mem_callback = stop_callback;
sewardjaf44c822007-11-25 14:01:38 +0000303
bart5fd28142009-06-10 19:24:20 +0000304 VG_(needs_malloc_replacement)(drd_malloc,
305 drd___builtin_new,
306 drd___builtin_vec_new,
307 drd_memalign,
308 drd_calloc,
309 drd_free,
310 drd___builtin_delete,
311 drd___builtin_vec_delete,
312 drd_realloc,
313 drd_malloc_usable_size,
bartbedfd232009-03-26 19:07:15 +0000314 0);
sewardjaf44c822007-11-25 14:01:38 +0000315}
316
bart246fbf22009-02-15 14:46:17 +0000317Bool DRD_(heap_addrinfo)(Addr const a,
318 Addr* const data,
319 SizeT* const size,
320 ExeContext** const where)
sewardjaf44c822007-11-25 14:01:38 +0000321{
bartbedfd232009-03-26 19:07:15 +0000322 DRD_Chunk* mc;
sewardjaf44c822007-11-25 14:01:38 +0000323
bartbedfd232009-03-26 19:07:15 +0000324 tl_assert(data);
325 tl_assert(size);
326 tl_assert(where);
sewardjaf44c822007-11-25 14:01:38 +0000327
bartba0818d2009-05-01 12:21:39 +0000328 VG_(HT_ResetIter)(s_malloc_list);
329 while ((mc = VG_(HT_Next)(s_malloc_list)))
bartbedfd232009-03-26 19:07:15 +0000330 {
331 if (mc->data <= a && a < mc->data + mc->size)
332 {
333 *data = mc->data;
334 *size = mc->size;
335 *where = mc->where;
336 return True;
337 }
338 }
339 return False;
sewardjaf44c822007-11-25 14:01:38 +0000340}
341
342/*------------------------------------------------------------*/
343/*--- Statistics printing ---*/
344/*------------------------------------------------------------*/
345
bart246fbf22009-02-15 14:46:17 +0000346void DRD_(print_malloc_stats)(void)
sewardjaf44c822007-11-25 14:01:38 +0000347{
bartbedfd232009-03-26 19:07:15 +0000348 DRD_Chunk* mc;
349 SizeT nblocks = 0;
350 SizeT nbytes = 0;
bart31b983d2010-02-21 14:52:59 +0000351
bartbedfd232009-03-26 19:07:15 +0000352 if (VG_(clo_verbosity) == 0)
353 return;
354 if (VG_(clo_xml))
355 return;
sewardjaf44c822007-11-25 14:01:38 +0000356
bartbedfd232009-03-26 19:07:15 +0000357 /* Count memory still in use. */
bartba0818d2009-05-01 12:21:39 +0000358 VG_(HT_ResetIter)(s_malloc_list);
359 while ((mc = VG_(HT_Next)(s_malloc_list)))
bartbedfd232009-03-26 19:07:15 +0000360 {
361 nblocks++;
362 nbytes += mc->size;
363 }
sewardjaf44c822007-11-25 14:01:38 +0000364
bart31b983d2010-02-21 14:52:59 +0000365 VG_(message)(Vg_DebugMsg,
sewardj1e29ebc2009-07-15 14:49:17 +0000366 "malloc/free: in use at exit: %lu bytes in %lu blocks.\n",
bartbedfd232009-03-26 19:07:15 +0000367 nbytes, nblocks);
bart31b983d2010-02-21 14:52:59 +0000368 VG_(message)(Vg_DebugMsg,
sewardj1e29ebc2009-07-15 14:49:17 +0000369 "malloc/free: %lu allocs, %lu frees, %lu bytes allocated.\n",
bartba0818d2009-05-01 12:21:39 +0000370 s_cmalloc_n_mallocs,
371 s_cmalloc_n_frees, s_cmalloc_bs_mallocd);
bartbedfd232009-03-26 19:07:15 +0000372 if (VG_(clo_verbosity) > 1)
sewardj1e29ebc2009-07-15 14:49:17 +0000373 VG_(message)(Vg_DebugMsg, " \n");
sewardjaf44c822007-11-25 14:01:38 +0000374}
375
376/*--------------------------------------------------------------------*/
377/*--- end ---*/
378/*--------------------------------------------------------------------*/