blob: 086f82f70e32b41bd292aeec7e5fae6975c4b587 [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
bart86562bd2009-02-16 19:43:56 +00004 Copyright (C) 2006-2009 Bart Van Assche <bart.vanassche@gmail.com>.
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
42typedef struct _DRD_Chunk {
bart3772a982008-03-15 08:11:03 +000043 struct _DRD_Chunk* next;
44 Addr data; // ptr to actual block
45 SizeT size : (sizeof(UWord)*8)-2; //size requested; 30 or 62 bits
46 ExeContext* where; // where it was allocated
sewardjaf44c822007-11-25 14:01:38 +000047} DRD_Chunk;
48
bart246fbf22009-02-15 14:46:17 +000049
50/* Local variables. */
51
52static StartUsingMem DRD_(s_start_using_mem_callback);
53static StopUsingMem DRD_(s_stop_using_mem_callback);
sewardjaf44c822007-11-25 14:01:38 +000054/* Stats ... */
bart246fbf22009-02-15 14:46:17 +000055static SizeT DRD_(s_cmalloc_n_mallocs) = 0;
56static SizeT DRD_(s_cmalloc_n_frees) = 0;
57static SizeT DRD_(s_cmalloc_bs_mallocd) = 0;
58/* Record malloc'd blocks. */
59static VgHashTable DRD_(s_malloc_list) = NULL;
sewardjaf44c822007-11-25 14:01:38 +000060
61
62/*------------------------------------------------------------*/
63/*--- Tracking malloc'd and free'd blocks ---*/
64/*------------------------------------------------------------*/
65
bart246fbf22009-02-15 14:46:17 +000066/** Allocate its shadow chunk, put it on the appropriate list. */
67static DRD_Chunk* DRD_(create_chunk)(ThreadId tid, Addr p, SizeT size)
sewardjaf44c822007-11-25 14:01:38 +000068{
sewardj9c606bd2008-09-18 18:12:50 +000069 DRD_Chunk* mc = VG_(malloc)("drd.malloc_wrappers.cDC.1",
70 sizeof(DRD_Chunk));
bart3772a982008-03-15 08:11:03 +000071 mc->data = p;
72 mc->size = size;
73 mc->where = VG_(record_ExeContext)(tid, 0);
sewardjaf44c822007-11-25 14:01:38 +000074
bart3772a982008-03-15 08:11:03 +000075 return mc;
sewardjaf44c822007-11-25 14:01:38 +000076}
77
78/*------------------------------------------------------------*/
79/*--- client_malloc(), etc ---*/
80/*------------------------------------------------------------*/
81
82/* Allocate memory and note change in memory available */
83static
84__inline__
bart246fbf22009-02-15 14:46:17 +000085void* DRD_(new_block)(ThreadId tid,
86 SizeT size, SizeT align,
87 Bool is_zeroed)
sewardjaf44c822007-11-25 14:01:38 +000088{
bart3772a982008-03-15 08:11:03 +000089 Addr p;
sewardjaf44c822007-11-25 14:01:38 +000090
bart246fbf22009-02-15 14:46:17 +000091 DRD_(s_cmalloc_n_mallocs) ++;
sewardjaf44c822007-11-25 14:01:38 +000092
bart3772a982008-03-15 08:11:03 +000093 // Allocate and zero
94 p = (Addr)VG_(cli_malloc)(align, size);
95 if (!p) {
96 return NULL;
97 }
98 if (is_zeroed) VG_(memset)((void*)p, 0, size);
bart246fbf22009-02-15 14:46:17 +000099 DRD_(s_start_using_mem_callback)(p, p + size, 0/*ec_uniq*/);
sewardjaf44c822007-11-25 14:01:38 +0000100
bart3772a982008-03-15 08:11:03 +0000101 // Only update this stat if allocation succeeded.
bart246fbf22009-02-15 14:46:17 +0000102 DRD_(s_cmalloc_bs_mallocd) += size;
sewardjaf44c822007-11-25 14:01:38 +0000103
bart246fbf22009-02-15 14:46:17 +0000104 VG_(HT_add_node)(DRD_(s_malloc_list), DRD_(create_chunk)(tid, p, size));
sewardjaf44c822007-11-25 14:01:38 +0000105
bart3772a982008-03-15 08:11:03 +0000106 return (void*)p;
sewardjaf44c822007-11-25 14:01:38 +0000107}
108
bart246fbf22009-02-15 14:46:17 +0000109static void* DRD_(malloc)(ThreadId tid, SizeT n)
sewardjaf44c822007-11-25 14:01:38 +0000110{
bart246fbf22009-02-15 14:46:17 +0000111 return DRD_(new_block)(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000112}
113
bart246fbf22009-02-15 14:46:17 +0000114static void* DRD_(memalign)(ThreadId tid, SizeT align, SizeT n)
sewardjaf44c822007-11-25 14:01:38 +0000115{
bart246fbf22009-02-15 14:46:17 +0000116 return DRD_(new_block)(tid, n, align, /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000117}
118
bart246fbf22009-02-15 14:46:17 +0000119static void* DRD_(calloc)(ThreadId tid, SizeT nmemb, SizeT size1)
sewardjaf44c822007-11-25 14:01:38 +0000120{
bart246fbf22009-02-15 14:46:17 +0000121 return DRD_(new_block)(tid, nmemb*size1, VG_(clo_alignment),
122 /*is_zeroed*/True);
sewardjaf44c822007-11-25 14:01:38 +0000123}
124
bart246fbf22009-02-15 14:46:17 +0000125static __inline__ void DRD_(handle_free)(ThreadId tid, Addr p)
sewardjaf44c822007-11-25 14:01:38 +0000126{
bart3772a982008-03-15 08:11:03 +0000127 DRD_Chunk* mc;
sewardjaf44c822007-11-25 14:01:38 +0000128
bart246fbf22009-02-15 14:46:17 +0000129 DRD_(s_cmalloc_n_frees)++;
sewardjaf44c822007-11-25 14:01:38 +0000130
bart246fbf22009-02-15 14:46:17 +0000131 mc = VG_(HT_remove)(DRD_(s_malloc_list), (UWord)p);
bart3772a982008-03-15 08:11:03 +0000132 if (mc == NULL)
133 {
134 tl_assert(0);
135 }
136 else
137 {
barte8a274c2008-04-20 08:33:10 +0000138 tl_assert(p == mc->data);
bart84595c02008-03-22 17:35:28 +0000139 if (mc->size > 0)
bart246fbf22009-02-15 14:46:17 +0000140 DRD_(s_stop_using_mem_callback)(mc->data, mc->size);
barte8a274c2008-04-20 08:33:10 +0000141 VG_(cli_free)((void*)p);
bart3772a982008-03-15 08:11:03 +0000142 VG_(free)(mc);
143 }
sewardjaf44c822007-11-25 14:01:38 +0000144}
145
bart246fbf22009-02-15 14:46:17 +0000146static void DRD_(free)(ThreadId tid, void* p)
sewardjaf44c822007-11-25 14:01:38 +0000147{
bart246fbf22009-02-15 14:46:17 +0000148 DRD_(handle_free)(tid, (Addr)p);
sewardjaf44c822007-11-25 14:01:38 +0000149}
150
bart246fbf22009-02-15 14:46:17 +0000151static void* DRD_(realloc)(ThreadId tid, void* p_old, SizeT new_size)
sewardjaf44c822007-11-25 14:01:38 +0000152{
bart3772a982008-03-15 08:11:03 +0000153 DRD_Chunk* mc;
154 void* p_new;
155 SizeT old_size;
sewardjaf44c822007-11-25 14:01:38 +0000156
bart246fbf22009-02-15 14:46:17 +0000157 DRD_(s_cmalloc_n_frees) ++;
158 DRD_(s_cmalloc_n_mallocs) ++;
159 DRD_(s_cmalloc_bs_mallocd) += new_size;
sewardjaf44c822007-11-25 14:01:38 +0000160
bart3772a982008-03-15 08:11:03 +0000161 /* Remove the old block */
bart246fbf22009-02-15 14:46:17 +0000162 mc = VG_(HT_remove)(DRD_(s_malloc_list), (UWord)p_old);
bart3772a982008-03-15 08:11:03 +0000163 if (mc == NULL) {
164 tl_assert(0);
165 return NULL;
166 }
sewardjaf44c822007-11-25 14:01:38 +0000167
bart3772a982008-03-15 08:11:03 +0000168 old_size = mc->size;
sewardjaf44c822007-11-25 14:01:38 +0000169
bart3772a982008-03-15 08:11:03 +0000170 if (old_size == new_size)
171 {
172 /* size unchanged */
173 mc->where = VG_(record_ExeContext)(tid, 0);
174 p_new = p_old;
sewardjaf44c822007-11-25 14:01:38 +0000175
bart3772a982008-03-15 08:11:03 +0000176 }
177 else if (old_size > new_size)
178 {
179 /* new size is smaller */
bart246fbf22009-02-15 14:46:17 +0000180 DRD_(s_stop_using_mem_callback)(mc->data + new_size, old_size);
bart3772a982008-03-15 08:11:03 +0000181 mc->size = new_size;
182 mc->where = VG_(record_ExeContext)(tid, 0);
183 p_new = p_old;
sewardjaf44c822007-11-25 14:01:38 +0000184
bart3772a982008-03-15 08:11:03 +0000185 }
186 else
187 {
188 /* new size is bigger */
189 /* Get new memory */
190 const Addr a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
sewardjaf44c822007-11-25 14:01:38 +0000191
bart3772a982008-03-15 08:11:03 +0000192 if (a_new)
193 {
194 /* Copy from old to new */
195 VG_(memcpy)((void*)a_new, p_old, mc->size);
sewardjaf44c822007-11-25 14:01:38 +0000196
bart3772a982008-03-15 08:11:03 +0000197 /* Free old memory */
bart246fbf22009-02-15 14:46:17 +0000198 DRD_(s_stop_using_mem_callback)(mc->data, mc->size);
bart3772a982008-03-15 08:11:03 +0000199 VG_(free)(mc);
sewardjaf44c822007-11-25 14:01:38 +0000200
bart3772a982008-03-15 08:11:03 +0000201 // Allocate a new chunk.
bart246fbf22009-02-15 14:46:17 +0000202 mc = DRD_(create_chunk)(tid, a_new, new_size);
203 DRD_(s_start_using_mem_callback)(a_new, a_new + new_size, 0/*ec_uniq*/);
bart3772a982008-03-15 08:11:03 +0000204 }
205 else
206 {
207 /* Allocation failed -- leave original block untouched. */
208 }
sewardjaf44c822007-11-25 14:01:38 +0000209
bart3772a982008-03-15 08:11:03 +0000210 p_new = (void*)a_new;
211 }
sewardjaf44c822007-11-25 14:01:38 +0000212
bart3772a982008-03-15 08:11:03 +0000213 // Now insert the new mc (with a possibly new 'data' field) into
214 // malloc_list. If this realloc() did not increase the memory size, we
215 // will have removed and then re-added mc unnecessarily. But that's ok
216 // because shrinking a block with realloc() is (presumably) much rarer
217 // than growing it, and this way simplifies the growing case.
bart246fbf22009-02-15 14:46:17 +0000218 VG_(HT_add_node)(DRD_(s_malloc_list), mc);
sewardjaf44c822007-11-25 14:01:38 +0000219
bart3772a982008-03-15 08:11:03 +0000220 return p_new;
sewardjaf44c822007-11-25 14:01:38 +0000221}
222
bart246fbf22009-02-15 14:46:17 +0000223static void* DRD_(__builtin_new)(ThreadId tid, SizeT n)
sewardjaf44c822007-11-25 14:01:38 +0000224{
bart246fbf22009-02-15 14:46:17 +0000225 void* const result = DRD_(new_block)(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
bart3772a982008-03-15 08:11:03 +0000226 //VG_(message)(Vg_DebugMsg, "__builtin_new(%d, %d) = %p", tid, n, result);
227 return result;
sewardjaf44c822007-11-25 14:01:38 +0000228}
229
bart246fbf22009-02-15 14:46:17 +0000230static void DRD_(__builtin_delete)(ThreadId tid, void* p)
sewardjaf44c822007-11-25 14:01:38 +0000231{
bart3772a982008-03-15 08:11:03 +0000232 //VG_(message)(Vg_DebugMsg, "__builtin_delete(%d, %p)", tid, p);
bart246fbf22009-02-15 14:46:17 +0000233 DRD_(handle_free)(tid, (Addr)p);
sewardjaf44c822007-11-25 14:01:38 +0000234}
235
bart246fbf22009-02-15 14:46:17 +0000236static void* DRD_(__builtin_vec_new)(ThreadId tid, SizeT n)
sewardjaf44c822007-11-25 14:01:38 +0000237{
bart246fbf22009-02-15 14:46:17 +0000238 return DRD_(new_block)(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000239}
240
bart246fbf22009-02-15 14:46:17 +0000241static void DRD_(__builtin_vec_delete)(ThreadId tid, void* p)
sewardjaf44c822007-11-25 14:01:38 +0000242{
bart246fbf22009-02-15 14:46:17 +0000243 DRD_(handle_free)(tid, (Addr)p);
sewardjaf44c822007-11-25 14:01:38 +0000244}
245
njn8b140de2009-02-17 04:31:18 +0000246static SizeT DRD_(malloc_usable_size) ( ThreadId tid, void* p )
247{
248 DRD_Chunk *mc = VG_(HT_lookup)( DRD_(s_malloc_list), (UWord)p );
249
250 // There may be slop, but pretend there isn't because only the asked-for
251 // area will have been shadowed properly.
252 return ( mc ? mc->size : 0 );
253}
254
bart246fbf22009-02-15 14:46:17 +0000255void DRD_(register_malloc_wrappers)(const StartUsingMem start_callback,
256 const StopUsingMem stop_callback)
sewardjaf44c822007-11-25 14:01:38 +0000257{
bart246fbf22009-02-15 14:46:17 +0000258 tl_assert(DRD_(s_malloc_list) == 0);
259 DRD_(s_malloc_list) = VG_(HT_construct)("drd_malloc_list"); // a big prime
260 tl_assert(DRD_(s_malloc_list) != 0);
261 tl_assert(start_callback);
262 tl_assert(stop_callback);
sewardjaf44c822007-11-25 14:01:38 +0000263
bart246fbf22009-02-15 14:46:17 +0000264 DRD_(s_start_using_mem_callback) = start_callback;
265 DRD_(s_stop_using_mem_callback) = stop_callback;
sewardjaf44c822007-11-25 14:01:38 +0000266
bart246fbf22009-02-15 14:46:17 +0000267 VG_(needs_malloc_replacement)(DRD_(malloc),
268 DRD_(__builtin_new),
269 DRD_(__builtin_vec_new),
270 DRD_(memalign),
271 DRD_(calloc),
272 DRD_(free),
273 DRD_(__builtin_delete),
274 DRD_(__builtin_vec_delete),
275 DRD_(realloc),
njn8b140de2009-02-17 04:31:18 +0000276 DRD_(malloc_usable_size),
bart3772a982008-03-15 08:11:03 +0000277 0);
sewardjaf44c822007-11-25 14:01:38 +0000278}
279
bart246fbf22009-02-15 14:46:17 +0000280Bool DRD_(heap_addrinfo)(Addr const a,
281 Addr* const data,
282 SizeT* const size,
283 ExeContext** const where)
sewardjaf44c822007-11-25 14:01:38 +0000284{
bart3772a982008-03-15 08:11:03 +0000285 DRD_Chunk* mc;
sewardjaf44c822007-11-25 14:01:38 +0000286
bart3772a982008-03-15 08:11:03 +0000287 tl_assert(data);
288 tl_assert(size);
289 tl_assert(where);
sewardjaf44c822007-11-25 14:01:38 +0000290
bart246fbf22009-02-15 14:46:17 +0000291 VG_(HT_ResetIter)(DRD_(s_malloc_list));
292 while ((mc = VG_(HT_Next)(DRD_(s_malloc_list))))
bart3772a982008-03-15 08:11:03 +0000293 {
294 if (mc->data <= a && a < mc->data + mc->size)
295 {
296 *data = mc->data;
297 *size = mc->size;
298 *where = mc->where;
299 return True;
300 }
301 }
302 return False;
sewardjaf44c822007-11-25 14:01:38 +0000303}
304
305/*------------------------------------------------------------*/
306/*--- Statistics printing ---*/
307/*------------------------------------------------------------*/
308
bart246fbf22009-02-15 14:46:17 +0000309void DRD_(print_malloc_stats)(void)
sewardjaf44c822007-11-25 14:01:38 +0000310{
bart3772a982008-03-15 08:11:03 +0000311 DRD_Chunk* mc;
312 SizeT nblocks = 0;
313 SizeT nbytes = 0;
sewardjaf44c822007-11-25 14:01:38 +0000314
bart3772a982008-03-15 08:11:03 +0000315 if (VG_(clo_verbosity) == 0)
316 return;
317 if (VG_(clo_xml))
318 return;
sewardjaf44c822007-11-25 14:01:38 +0000319
bart3772a982008-03-15 08:11:03 +0000320 /* Count memory still in use. */
bart246fbf22009-02-15 14:46:17 +0000321 VG_(HT_ResetIter)(DRD_(s_malloc_list));
322 while ((mc = VG_(HT_Next)(DRD_(s_malloc_list))))
bart3772a982008-03-15 08:11:03 +0000323 {
324 nblocks++;
325 nbytes += mc->size;
326 }
sewardjaf44c822007-11-25 14:01:38 +0000327
bart3772a982008-03-15 08:11:03 +0000328 VG_(message)(Vg_DebugMsg,
329 "malloc/free: in use at exit: %lu bytes in %lu blocks.",
330 nbytes, nblocks);
331 VG_(message)(Vg_DebugMsg,
332 "malloc/free: %lu allocs, %lu frees, %lu bytes allocated.",
bart246fbf22009-02-15 14:46:17 +0000333 DRD_(s_cmalloc_n_mallocs),
334 DRD_(s_cmalloc_n_frees), DRD_(s_cmalloc_bs_mallocd));
bart3772a982008-03-15 08:11:03 +0000335 if (VG_(clo_verbosity) > 1)
336 VG_(message)(Vg_DebugMsg, " ");
sewardjaf44c822007-11-25 14:01:38 +0000337}
338
339/*--------------------------------------------------------------------*/
340/*--- end ---*/
341/*--------------------------------------------------------------------*/