blob: 9585cd27e159c062237c210320af4cbb9a1ebf5f [file] [log] [blame]
sewardjaf44c822007-11-25 14:01:38 +00001/*
bart86562bd2009-02-16 19:43:56 +00002 This file is part of drd, a thread error detector.
sewardjaf44c822007-11-25 14:01:38 +00003
Elliott Hughesed398002017-06-21 14:41:24 -07004 Copyright (C) 2006-2017 Bart Van Assche <bvanassche@acm.org>.
sewardjaf44c822007-11-25 14:01:38 +00005
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307, USA.
20
21 The GNU General Public License is contained in the file COPYING.
22*/
23
24
25#include "drd_malloc_wrappers.h"
26#include "drd_thread.h"
27#include "pub_tool_basics.h"
28#include "pub_tool_execontext.h"
29#include "pub_tool_hashtable.h"
30#include "pub_tool_libcassert.h"
31#include "pub_tool_libcbase.h"
32#include "pub_tool_libcprint.h"
33#include "pub_tool_mallocfree.h"
34#include "pub_tool_options.h"
35#include "pub_tool_replacemalloc.h"
36#include "pub_tool_threadstate.h"
37#include "pub_tool_tooliface.h"
38
39
bart246fbf22009-02-15 14:46:17 +000040/* Local type definitions. */
sewardjaf44c822007-11-25 14:01:38 +000041
bart5fd28142009-06-10 19:24:20 +000042/**
43 * Node with per-allocation information that will be stored in a hash map.
44 * As specified in <pub_tool_hashtable.h>, the first member must be a pointer
45 * and the second member must be an UWord.
46 */
sewardjaf44c822007-11-25 14:01:38 +000047typedef struct _DRD_Chunk {
bartbedfd232009-03-26 19:07:15 +000048 struct _DRD_Chunk* next;
bart5fd28142009-06-10 19:24:20 +000049 UWord data; // pointer to actual block
50 SizeT size; // size requested
51 ExeContext* where; // where it was allocated
sewardjaf44c822007-11-25 14:01:38 +000052} DRD_Chunk;
53
bart246fbf22009-02-15 14:46:17 +000054
55/* Local variables. */
56
bartba0818d2009-05-01 12:21:39 +000057static StartUsingMem s_start_using_mem_callback;
58static StopUsingMem s_stop_using_mem_callback;
bart5fd28142009-06-10 19:24:20 +000059/* Statistics. */
bartba0818d2009-05-01 12:21:39 +000060static SizeT s_cmalloc_n_mallocs = 0;
61static SizeT s_cmalloc_n_frees = 0;
62static SizeT s_cmalloc_bs_mallocd = 0;
bart246fbf22009-02-15 14:46:17 +000063/* Record malloc'd blocks. */
florian09a4c792014-10-18 10:58:05 +000064static VgHashTable *s_malloc_list = NULL;
sewardjaf44c822007-11-25 14:01:38 +000065
66
bart5fd28142009-06-10 19:24:20 +000067/* Function definitions. */
sewardjaf44c822007-11-25 14:01:38 +000068
bart5fd28142009-06-10 19:24:20 +000069/** Allocate client memory memory and update the hash map. */
bartba0818d2009-05-01 12:21:39 +000070static void* new_block(ThreadId tid, SizeT size, SizeT align, Bool is_zeroed)
sewardjaf44c822007-11-25 14:01:38 +000071{
bart5fd28142009-06-10 19:24:20 +000072 void* p;
sewardjaf44c822007-11-25 14:01:38 +000073
bart5fd28142009-06-10 19:24:20 +000074 p = VG_(cli_malloc)(align, size);
75 if (!p)
bartbedfd232009-03-26 19:07:15 +000076 return NULL;
bart5fd28142009-06-10 19:24:20 +000077 if (is_zeroed)
78 VG_(memset)(p, 0, size);
sewardjaf44c822007-11-25 14:01:38 +000079
bart5fd28142009-06-10 19:24:20 +000080 DRD_(malloclike_block)(tid, (Addr)p, size);
sewardjaf44c822007-11-25 14:01:38 +000081
bart5fd28142009-06-10 19:24:20 +000082 return p;
sewardjaf44c822007-11-25 14:01:38 +000083}
84
bartba0818d2009-05-01 12:21:39 +000085/**
86 * Store information about a memory block that has been allocated by
bart5fd28142009-06-10 19:24:20 +000087 * malloc() or a malloc() replacement in the hash map.
bartba0818d2009-05-01 12:21:39 +000088 */
89void DRD_(malloclike_block)(const ThreadId tid, const Addr p, const SizeT size)
90{
bart5fd28142009-06-10 19:24:20 +000091 DRD_Chunk* mc;
92
bartba0818d2009-05-01 12:21:39 +000093 tl_assert(p);
94
bart5fd28142009-06-10 19:24:20 +000095 if (size > 0)
96 s_start_using_mem_callback(p, size, 0/*ec_uniq*/);
bartba0818d2009-05-01 12:21:39 +000097
bart5fd28142009-06-10 19:24:20 +000098 s_cmalloc_n_mallocs++;
bartba0818d2009-05-01 12:21:39 +000099 // Only update this stat if allocation succeeded.
100 s_cmalloc_bs_mallocd += size;
101
bart5fd28142009-06-10 19:24:20 +0000102 mc = VG_(malloc)("drd.malloc_wrappers.cDC.1", sizeof(DRD_Chunk));
103 mc->data = p;
104 mc->size = size;
105 mc->where = VG_(record_ExeContext)(tid, 0);
106 VG_(HT_add_node)(s_malloc_list, mc);
bartba0818d2009-05-01 12:21:39 +0000107}
108
bart5fd28142009-06-10 19:24:20 +0000109static void handle_free(ThreadId tid, void* p)
sewardjaf44c822007-11-25 14:01:38 +0000110{
bartfc08a532011-03-12 12:43:39 +0000111 Bool success;
sewardjaf44c822007-11-25 14:01:38 +0000112
bartfc08a532011-03-12 12:43:39 +0000113 tl_assert(p);
114 success = DRD_(freelike_block)(tid, (Addr)p, True);
115 tl_assert(success);
sewardjaf44c822007-11-25 14:01:38 +0000116}
117
bartba0818d2009-05-01 12:21:39 +0000118/**
119 * Remove the information that was stored by DRD_(malloclike_block)() about
120 * a memory block.
121 */
bartfc08a532011-03-12 12:43:39 +0000122Bool DRD_(freelike_block)(const ThreadId tid, const Addr p, const Bool dealloc)
sewardjaf44c822007-11-25 14:01:38 +0000123{
bartbedfd232009-03-26 19:07:15 +0000124 DRD_Chunk* mc;
sewardjaf44c822007-11-25 14:01:38 +0000125
bartba0818d2009-05-01 12:21:39 +0000126 tl_assert(p);
sewardjaf44c822007-11-25 14:01:38 +0000127
bartba0818d2009-05-01 12:21:39 +0000128 s_cmalloc_n_frees++;
129
bart639d0ad2011-03-12 14:26:01 +0000130 mc = VG_(HT_lookup)(s_malloc_list, (UWord)p);
bartba0818d2009-05-01 12:21:39 +0000131 if (mc)
bartbedfd232009-03-26 19:07:15 +0000132 {
133 tl_assert(p == mc->data);
134 if (mc->size > 0)
bartba0818d2009-05-01 12:21:39 +0000135 s_stop_using_mem_callback(mc->data, mc->size);
bart697bb6b2012-04-02 14:36:22 +0000136 if (dealloc)
137 VG_(cli_free)((void*)p);
bart639d0ad2011-03-12 14:26:01 +0000138 VG_(HT_remove)(s_malloc_list, (UWord)p);
bartbedfd232009-03-26 19:07:15 +0000139 VG_(free)(mc);
bartba0818d2009-05-01 12:21:39 +0000140 return True;
bartbedfd232009-03-26 19:07:15 +0000141 }
bartba0818d2009-05-01 12:21:39 +0000142 return False;
143}
144
bart5fd28142009-06-10 19:24:20 +0000145/** Wrapper for malloc(). */
146static void* drd_malloc(ThreadId tid, SizeT n)
bartba0818d2009-05-01 12:21:39 +0000147{
bart5fd28142009-06-10 19:24:20 +0000148 return new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000149}
150
bart5fd28142009-06-10 19:24:20 +0000151/** Wrapper for memalign(). */
152static void* drd_memalign(ThreadId tid, SizeT align, SizeT n)
sewardjaf44c822007-11-25 14:01:38 +0000153{
bart5fd28142009-06-10 19:24:20 +0000154 return new_block(tid, n, align, /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000155}
156
bart5fd28142009-06-10 19:24:20 +0000157/** Wrapper for calloc(). */
158static void* drd_calloc(ThreadId tid, SizeT nmemb, SizeT size1)
159{
160 return new_block(tid, nmemb*size1, VG_(clo_alignment),
161 /*is_zeroed*/True);
162}
163
164/** Wrapper for free(). */
165static void drd_free(ThreadId tid, void* p)
166{
167 handle_free(tid, p);
168}
169
170/**
171 * Wrapper for realloc(). Returns a pointer to the new block of memory, or
172 * NULL if no new block could not be allocated. Notes:
173 * - realloc(NULL, size) has the same effect as malloc(size).
174 * - realloc(p, 0) has the same effect as free(p).
175 * - success is not guaranteed even if the requested size is smaller than the
176 * allocated size.
177*/
178static void* drd_realloc(ThreadId tid, void* p_old, SizeT new_size)
sewardjaf44c822007-11-25 14:01:38 +0000179{
bartbedfd232009-03-26 19:07:15 +0000180 DRD_Chunk* mc;
bart5fd28142009-06-10 19:24:20 +0000181 void* p_new;
182 SizeT old_size;
sewardjaf44c822007-11-25 14:01:38 +0000183
bart5fd28142009-06-10 19:24:20 +0000184 if (! p_old)
185 return drd_malloc(tid, new_size);
186
187 if (new_size == 0)
188 {
189 drd_free(tid, p_old);
190 return NULL;
191 }
192
193 s_cmalloc_n_mallocs++;
194 s_cmalloc_n_frees++;
bartba0818d2009-05-01 12:21:39 +0000195 s_cmalloc_bs_mallocd += new_size;
sewardjaf44c822007-11-25 14:01:38 +0000196
bart5fd28142009-06-10 19:24:20 +0000197 mc = VG_(HT_lookup)(s_malloc_list, (UWord)p_old);
198 if (mc == NULL)
199 {
bartbedfd232009-03-26 19:07:15 +0000200 tl_assert(0);
201 return NULL;
202 }
sewardjaf44c822007-11-25 14:01:38 +0000203
bartbedfd232009-03-26 19:07:15 +0000204 old_size = mc->size;
sewardjaf44c822007-11-25 14:01:38 +0000205
bartbedfd232009-03-26 19:07:15 +0000206 if (old_size == new_size)
207 {
208 /* size unchanged */
209 mc->where = VG_(record_ExeContext)(tid, 0);
210 p_new = p_old;
bartbedfd232009-03-26 19:07:15 +0000211 }
bart5fd28142009-06-10 19:24:20 +0000212 else if (new_size < old_size)
bartbedfd232009-03-26 19:07:15 +0000213 {
bart5fd28142009-06-10 19:24:20 +0000214 /* new size is smaller but nonzero */
bart5b61bda2009-06-09 11:12:07 +0000215 s_stop_using_mem_callback(mc->data + new_size, old_size - new_size);
bartbedfd232009-03-26 19:07:15 +0000216 mc->size = new_size;
217 mc->where = VG_(record_ExeContext)(tid, 0);
218 p_new = p_old;
bartbedfd232009-03-26 19:07:15 +0000219 }
220 else
221 {
222 /* new size is bigger */
bart5fd28142009-06-10 19:24:20 +0000223 p_new = VG_(cli_malloc)(VG_(clo_alignment), new_size);
sewardjaf44c822007-11-25 14:01:38 +0000224
bart5fd28142009-06-10 19:24:20 +0000225 if (p_new)
bartbedfd232009-03-26 19:07:15 +0000226 {
bart5fd28142009-06-10 19:24:20 +0000227 /* Copy from old to new. */
228 VG_(memcpy)(p_new, p_old, mc->size);
bart31b983d2010-02-21 14:52:59 +0000229
bart5fd28142009-06-10 19:24:20 +0000230 /* Free old memory. */
bart83e7eb62009-07-25 13:28:24 +0000231 if (mc->size > 0)
232 s_stop_using_mem_callback(mc->data, mc->size);
barte49a5882012-04-02 15:46:51 +0000233 VG_(cli_free)(p_old);
bart5fd28142009-06-10 19:24:20 +0000234 VG_(HT_remove)(s_malloc_list, (UWord)p_old);
sewardjaf44c822007-11-25 14:01:38 +0000235
bart5fd28142009-06-10 19:24:20 +0000236 /* Update state information. */
237 mc->data = (Addr)p_new;
238 mc->size = new_size;
239 mc->where = VG_(record_ExeContext)(tid, 0);
240 VG_(HT_add_node)(s_malloc_list, mc);
241 s_start_using_mem_callback((Addr)p_new, new_size, 0/*ec_uniq*/);
bartbedfd232009-03-26 19:07:15 +0000242 }
243 else
244 {
245 /* Allocation failed -- leave original block untouched. */
246 }
bart31b983d2010-02-21 14:52:59 +0000247 }
sewardjaf44c822007-11-25 14:01:38 +0000248
bartbedfd232009-03-26 19:07:15 +0000249 return p_new;
sewardjaf44c822007-11-25 14:01:38 +0000250}
251
bart5fd28142009-06-10 19:24:20 +0000252/** Wrapper for __builtin_new(). */
253static void* drd___builtin_new(ThreadId tid, SizeT n)
sewardjaf44c822007-11-25 14:01:38 +0000254{
bartba0818d2009-05-01 12:21:39 +0000255 return new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000256}
257
bart5fd28142009-06-10 19:24:20 +0000258/** Wrapper for __builtin_delete(). */
259static void drd___builtin_delete(ThreadId tid, void* p)
sewardjaf44c822007-11-25 14:01:38 +0000260{
bart5fd28142009-06-10 19:24:20 +0000261 handle_free(tid, p);
sewardjaf44c822007-11-25 14:01:38 +0000262}
263
bart5fd28142009-06-10 19:24:20 +0000264/** Wrapper for __builtin_vec_new(). */
265static void* drd___builtin_vec_new(ThreadId tid, SizeT n)
njn8b140de2009-02-17 04:31:18 +0000266{
bart5fd28142009-06-10 19:24:20 +0000267 return new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
268}
njn8b140de2009-02-17 04:31:18 +0000269
bart5fd28142009-06-10 19:24:20 +0000270/** Wrapper for __builtin_vec_delete(). */
271static void drd___builtin_vec_delete(ThreadId tid, void* p)
272{
273 handle_free(tid, p);
274}
275
276/**
277 * Wrapper for malloc_usable_size() / malloc_size(). This function takes
278 * a pointer to a block allocated by `malloc' and returns the amount of space
279 * that is available in the block. This may or may not be more than the size
280 * requested from `malloc', due to alignment or minimum size constraints.
281 */
282static SizeT drd_malloc_usable_size(ThreadId tid, void* p)
283{
284 DRD_Chunk* mc;
285
286 mc = VG_(HT_lookup)(s_malloc_list, (UWord)p);
287
288 return mc ? mc->size : 0;
njn8b140de2009-02-17 04:31:18 +0000289}
290
bart246fbf22009-02-15 14:46:17 +0000291void DRD_(register_malloc_wrappers)(const StartUsingMem start_callback,
292 const StopUsingMem stop_callback)
sewardjaf44c822007-11-25 14:01:38 +0000293{
bartba0818d2009-05-01 12:21:39 +0000294 tl_assert(s_malloc_list == 0);
bart5fd28142009-06-10 19:24:20 +0000295 s_malloc_list = VG_(HT_construct)("drd_malloc_list");
bartbedfd232009-03-26 19:07:15 +0000296 tl_assert(start_callback);
297 tl_assert(stop_callback);
sewardjaf44c822007-11-25 14:01:38 +0000298
bartba0818d2009-05-01 12:21:39 +0000299 s_start_using_mem_callback = start_callback;
300 s_stop_using_mem_callback = stop_callback;
sewardjaf44c822007-11-25 14:01:38 +0000301
bart5fd28142009-06-10 19:24:20 +0000302 VG_(needs_malloc_replacement)(drd_malloc,
303 drd___builtin_new,
304 drd___builtin_vec_new,
305 drd_memalign,
306 drd_calloc,
307 drd_free,
308 drd___builtin_delete,
309 drd___builtin_vec_delete,
310 drd_realloc,
311 drd_malloc_usable_size,
bartbedfd232009-03-26 19:07:15 +0000312 0);
sewardjaf44c822007-11-25 14:01:38 +0000313}
314
bart246fbf22009-02-15 14:46:17 +0000315Bool DRD_(heap_addrinfo)(Addr const a,
316 Addr* const data,
317 SizeT* const size,
318 ExeContext** const where)
sewardjaf44c822007-11-25 14:01:38 +0000319{
bartbedfd232009-03-26 19:07:15 +0000320 DRD_Chunk* mc;
sewardjaf44c822007-11-25 14:01:38 +0000321
bartbedfd232009-03-26 19:07:15 +0000322 tl_assert(data);
323 tl_assert(size);
324 tl_assert(where);
sewardjaf44c822007-11-25 14:01:38 +0000325
bartba0818d2009-05-01 12:21:39 +0000326 VG_(HT_ResetIter)(s_malloc_list);
327 while ((mc = VG_(HT_Next)(s_malloc_list)))
bartbedfd232009-03-26 19:07:15 +0000328 {
329 if (mc->data <= a && a < mc->data + mc->size)
330 {
331 *data = mc->data;
332 *size = mc->size;
333 *where = mc->where;
334 return True;
335 }
336 }
337 return False;
sewardjaf44c822007-11-25 14:01:38 +0000338}
339
340/*------------------------------------------------------------*/
341/*--- Statistics printing ---*/
342/*------------------------------------------------------------*/
343
bart246fbf22009-02-15 14:46:17 +0000344void DRD_(print_malloc_stats)(void)
sewardjaf44c822007-11-25 14:01:38 +0000345{
bartbedfd232009-03-26 19:07:15 +0000346 DRD_Chunk* mc;
347 SizeT nblocks = 0;
348 SizeT nbytes = 0;
bart31b983d2010-02-21 14:52:59 +0000349
bartbedfd232009-03-26 19:07:15 +0000350 if (VG_(clo_verbosity) == 0)
351 return;
352 if (VG_(clo_xml))
353 return;
sewardjaf44c822007-11-25 14:01:38 +0000354
bartbedfd232009-03-26 19:07:15 +0000355 /* Count memory still in use. */
bartba0818d2009-05-01 12:21:39 +0000356 VG_(HT_ResetIter)(s_malloc_list);
357 while ((mc = VG_(HT_Next)(s_malloc_list)))
bartbedfd232009-03-26 19:07:15 +0000358 {
359 nblocks++;
360 nbytes += mc->size;
361 }
sewardjaf44c822007-11-25 14:01:38 +0000362
bart31b983d2010-02-21 14:52:59 +0000363 VG_(message)(Vg_DebugMsg,
sewardj1e29ebc2009-07-15 14:49:17 +0000364 "malloc/free: in use at exit: %lu bytes in %lu blocks.\n",
bartbedfd232009-03-26 19:07:15 +0000365 nbytes, nblocks);
bart31b983d2010-02-21 14:52:59 +0000366 VG_(message)(Vg_DebugMsg,
sewardj1e29ebc2009-07-15 14:49:17 +0000367 "malloc/free: %lu allocs, %lu frees, %lu bytes allocated.\n",
bartba0818d2009-05-01 12:21:39 +0000368 s_cmalloc_n_mallocs,
369 s_cmalloc_n_frees, s_cmalloc_bs_mallocd);
bartbedfd232009-03-26 19:07:15 +0000370 if (VG_(clo_verbosity) > 1)
sewardj1e29ebc2009-07-15 14:49:17 +0000371 VG_(message)(Vg_DebugMsg, " \n");
sewardjaf44c822007-11-25 14:01:38 +0000372}
373
374/*--------------------------------------------------------------------*/
375/*--- end ---*/
376/*--------------------------------------------------------------------*/