blob: 5a47ed7cfb3da3248f1290f4caf153d150b7beed [file] [log] [blame]
sewardjaf44c822007-11-25 14:01:38 +00001/*
2 This file is part of drd, a data race detector.
3
sewardj85642922008-01-14 11:54:56 +00004 Copyright (C) 2006-2008 Bart Van Assche
sewardjaf44c822007-11-25 14:01:38 +00005 bart.vanassche@gmail.com
6
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
41/*------------------------------------------------------------*/
barte8a274c2008-04-20 08:33:10 +000042/*--- Definitions ---*/
sewardjaf44c822007-11-25 14:01:38 +000043/*------------------------------------------------------------*/
44
45
46typedef struct _DRD_Chunk {
bart3772a982008-03-15 08:11:03 +000047 struct _DRD_Chunk* next;
48 Addr data; // ptr to actual block
49 SizeT size : (sizeof(UWord)*8)-2; //size requested; 30 or 62 bits
50 ExeContext* where; // where it was allocated
sewardjaf44c822007-11-25 14:01:38 +000051} DRD_Chunk;
52
53static StartUsingMem s_start_using_mem_callback;
54static StopUsingMem s_stop_using_mem_callback;
55/* Stats ... */
56static SizeT cmalloc_n_mallocs = 0;
57static SizeT cmalloc_n_frees = 0;
58static SizeT cmalloc_bs_mallocd = 0;
59
60
61/*------------------------------------------------------------*/
62/*--- Tracking malloc'd and free'd blocks ---*/
63/*------------------------------------------------------------*/
64
65/* Record malloc'd blocks. */
66static VgHashTable drd_malloc_list = NULL;
67
68
69/* Allocate its shadow chunk, put it on the appropriate list. */
70static
71DRD_Chunk* create_DRD_Chunk(ThreadId tid, Addr p, SizeT size)
72{
sewardj9c606bd2008-09-18 18:12:50 +000073 DRD_Chunk* mc = VG_(malloc)("drd.malloc_wrappers.cDC.1",
74 sizeof(DRD_Chunk));
bart3772a982008-03-15 08:11:03 +000075 mc->data = p;
76 mc->size = size;
77 mc->where = VG_(record_ExeContext)(tid, 0);
sewardjaf44c822007-11-25 14:01:38 +000078
bart3772a982008-03-15 08:11:03 +000079 return mc;
sewardjaf44c822007-11-25 14:01:38 +000080}
81
82/*------------------------------------------------------------*/
83/*--- client_malloc(), etc ---*/
84/*------------------------------------------------------------*/
85
86/* Allocate memory and note change in memory available */
87static
88__inline__
89void* drd_new_block(ThreadId tid,
90 SizeT size, SizeT align,
91 Bool is_zeroed)
92{
bart3772a982008-03-15 08:11:03 +000093 Addr p;
sewardjaf44c822007-11-25 14:01:38 +000094
bart3772a982008-03-15 08:11:03 +000095 cmalloc_n_mallocs ++;
sewardjaf44c822007-11-25 14:01:38 +000096
bart3772a982008-03-15 08:11:03 +000097 // Allocate and zero
98 p = (Addr)VG_(cli_malloc)(align, size);
99 if (!p) {
100 return NULL;
101 }
102 if (is_zeroed) VG_(memset)((void*)p, 0, size);
sewardj7cf4e6b2008-05-01 20:24:26 +0000103 s_start_using_mem_callback(p, p + size, 0/*ec_uniq*/);
sewardjaf44c822007-11-25 14:01:38 +0000104
bart3772a982008-03-15 08:11:03 +0000105 // Only update this stat if allocation succeeded.
106 cmalloc_bs_mallocd += size;
sewardjaf44c822007-11-25 14:01:38 +0000107
bart3772a982008-03-15 08:11:03 +0000108 VG_(HT_add_node)(drd_malloc_list, create_DRD_Chunk(tid, p, size));
sewardjaf44c822007-11-25 14:01:38 +0000109
bart3772a982008-03-15 08:11:03 +0000110 return (void*)p;
sewardjaf44c822007-11-25 14:01:38 +0000111}
112
113static
114void* drd_malloc(ThreadId tid, SizeT n)
115{
bart3772a982008-03-15 08:11:03 +0000116 return drd_new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000117}
118
119static
120void* drd_memalign(ThreadId tid, SizeT align, SizeT n)
121{
bart3772a982008-03-15 08:11:03 +0000122 return drd_new_block(tid, n, align, /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000123}
124
125static
126void* drd_calloc(ThreadId tid, SizeT nmemb, SizeT size1)
127{
bart3772a982008-03-15 08:11:03 +0000128 return drd_new_block(tid, nmemb*size1, VG_(clo_alignment),
129 /*is_zeroed*/True);
sewardjaf44c822007-11-25 14:01:38 +0000130}
131
132static
133__inline__
134void drd_handle_free(ThreadId tid, Addr p)
135{
bart3772a982008-03-15 08:11:03 +0000136 DRD_Chunk* mc;
sewardjaf44c822007-11-25 14:01:38 +0000137
bart3772a982008-03-15 08:11:03 +0000138 cmalloc_n_frees++;
sewardjaf44c822007-11-25 14:01:38 +0000139
bart3772a982008-03-15 08:11:03 +0000140 mc = VG_(HT_remove)(drd_malloc_list, (UWord)p);
141 if (mc == NULL)
142 {
143 tl_assert(0);
144 }
145 else
146 {
barte8a274c2008-04-20 08:33:10 +0000147 tl_assert(p == mc->data);
bart84595c02008-03-22 17:35:28 +0000148 if (mc->size > 0)
149 s_stop_using_mem_callback(mc->data, mc->size);
barte8a274c2008-04-20 08:33:10 +0000150 VG_(cli_free)((void*)p);
bart3772a982008-03-15 08:11:03 +0000151 VG_(free)(mc);
152 }
sewardjaf44c822007-11-25 14:01:38 +0000153}
154
155static
156void drd_free(ThreadId tid, void* p)
157{
bart3772a982008-03-15 08:11:03 +0000158 drd_handle_free(tid, (Addr)p);
sewardjaf44c822007-11-25 14:01:38 +0000159}
160
161static
162void* drd_realloc(ThreadId tid, void* p_old, SizeT new_size)
163{
bart3772a982008-03-15 08:11:03 +0000164 DRD_Chunk* mc;
165 void* p_new;
166 SizeT old_size;
sewardjaf44c822007-11-25 14:01:38 +0000167
bart3772a982008-03-15 08:11:03 +0000168 cmalloc_n_frees ++;
169 cmalloc_n_mallocs ++;
170 cmalloc_bs_mallocd += new_size;
sewardjaf44c822007-11-25 14:01:38 +0000171
bart3772a982008-03-15 08:11:03 +0000172 /* Remove the old block */
173 mc = VG_(HT_remove)(drd_malloc_list, (UWord)p_old);
174 if (mc == NULL) {
175 tl_assert(0);
176 return NULL;
177 }
sewardjaf44c822007-11-25 14:01:38 +0000178
bart3772a982008-03-15 08:11:03 +0000179 old_size = mc->size;
sewardjaf44c822007-11-25 14:01:38 +0000180
bart3772a982008-03-15 08:11:03 +0000181 if (old_size == new_size)
182 {
183 /* size unchanged */
184 mc->where = VG_(record_ExeContext)(tid, 0);
185 p_new = p_old;
sewardjaf44c822007-11-25 14:01:38 +0000186
bart3772a982008-03-15 08:11:03 +0000187 }
188 else if (old_size > new_size)
189 {
190 /* new size is smaller */
191 s_stop_using_mem_callback(mc->data + new_size, old_size);
192 mc->size = new_size;
193 mc->where = VG_(record_ExeContext)(tid, 0);
194 p_new = p_old;
sewardjaf44c822007-11-25 14:01:38 +0000195
bart3772a982008-03-15 08:11:03 +0000196 }
197 else
198 {
199 /* new size is bigger */
200 /* Get new memory */
201 const Addr a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
sewardjaf44c822007-11-25 14:01:38 +0000202
bart3772a982008-03-15 08:11:03 +0000203 if (a_new)
204 {
205 /* Copy from old to new */
206 VG_(memcpy)((void*)a_new, p_old, mc->size);
sewardjaf44c822007-11-25 14:01:38 +0000207
bart3772a982008-03-15 08:11:03 +0000208 /* Free old memory */
209 s_stop_using_mem_callback(mc->data, mc->size);
210 VG_(free)(mc);
sewardjaf44c822007-11-25 14:01:38 +0000211
bart3772a982008-03-15 08:11:03 +0000212 // Allocate a new chunk.
213 mc = create_DRD_Chunk(tid, a_new, new_size);
sewardj7cf4e6b2008-05-01 20:24:26 +0000214 s_start_using_mem_callback(a_new, a_new + new_size, 0/*ec_uniq*/);
bart3772a982008-03-15 08:11:03 +0000215 }
216 else
217 {
218 /* Allocation failed -- leave original block untouched. */
219 }
sewardjaf44c822007-11-25 14:01:38 +0000220
bart3772a982008-03-15 08:11:03 +0000221 p_new = (void*)a_new;
222 }
sewardjaf44c822007-11-25 14:01:38 +0000223
bart3772a982008-03-15 08:11:03 +0000224 // Now insert the new mc (with a possibly new 'data' field) into
225 // malloc_list. If this realloc() did not increase the memory size, we
226 // will have removed and then re-added mc unnecessarily. But that's ok
227 // because shrinking a block with realloc() is (presumably) much rarer
228 // than growing it, and this way simplifies the growing case.
229 VG_(HT_add_node)(drd_malloc_list, mc);
sewardjaf44c822007-11-25 14:01:38 +0000230
bart3772a982008-03-15 08:11:03 +0000231 return p_new;
sewardjaf44c822007-11-25 14:01:38 +0000232}
233
234static
235void* drd___builtin_new(ThreadId tid, SizeT n)
236{
bart3772a982008-03-15 08:11:03 +0000237 void* const result = drd_new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
238 //VG_(message)(Vg_DebugMsg, "__builtin_new(%d, %d) = %p", tid, n, result);
239 return result;
sewardjaf44c822007-11-25 14:01:38 +0000240}
241
242static
243void drd___builtin_delete(ThreadId tid, void* p)
244{
bart3772a982008-03-15 08:11:03 +0000245 //VG_(message)(Vg_DebugMsg, "__builtin_delete(%d, %p)", tid, p);
246 drd_handle_free(tid, (Addr)p);
sewardjaf44c822007-11-25 14:01:38 +0000247}
248
249static
250void* drd___builtin_vec_new(ThreadId tid, SizeT n)
251{
bart3772a982008-03-15 08:11:03 +0000252 return drd_new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000253}
254
255static
256void drd___builtin_vec_delete(ThreadId tid, void* p)
257{
bart3772a982008-03-15 08:11:03 +0000258 drd_handle_free(tid, (Addr)p);
sewardjaf44c822007-11-25 14:01:38 +0000259}
260
261void drd_register_malloc_wrappers(const StartUsingMem start_using_mem_callback,
262 const StopUsingMem stop_using_mem_callback)
263{
bart3772a982008-03-15 08:11:03 +0000264 tl_assert(drd_malloc_list == 0);
265 drd_malloc_list = VG_(HT_construct)("drd_malloc_list"); // a big prime
266 tl_assert(drd_malloc_list != 0);
267 tl_assert(stop_using_mem_callback);
sewardjaf44c822007-11-25 14:01:38 +0000268
bart3772a982008-03-15 08:11:03 +0000269 s_start_using_mem_callback = start_using_mem_callback;
270 s_stop_using_mem_callback = stop_using_mem_callback;
sewardjaf44c822007-11-25 14:01:38 +0000271
bart3772a982008-03-15 08:11:03 +0000272 VG_(needs_malloc_replacement)(drd_malloc,
273 drd___builtin_new,
274 drd___builtin_vec_new,
275 drd_memalign,
276 drd_calloc,
277 drd_free,
278 drd___builtin_delete,
279 drd___builtin_vec_delete,
280 drd_realloc,
281 0);
sewardjaf44c822007-11-25 14:01:38 +0000282}
283
284Bool drd_heap_addrinfo(Addr const a,
285 Addr* const data,
286 SizeT* const size,
287 ExeContext** const where)
288{
bart3772a982008-03-15 08:11:03 +0000289 DRD_Chunk* mc;
sewardjaf44c822007-11-25 14:01:38 +0000290
bart3772a982008-03-15 08:11:03 +0000291 tl_assert(data);
292 tl_assert(size);
293 tl_assert(where);
sewardjaf44c822007-11-25 14:01:38 +0000294
bart3772a982008-03-15 08:11:03 +0000295 VG_(HT_ResetIter)(drd_malloc_list);
296 while ((mc = VG_(HT_Next)(drd_malloc_list)))
297 {
298 if (mc->data <= a && a < mc->data + mc->size)
299 {
300 *data = mc->data;
301 *size = mc->size;
302 *where = mc->where;
303 return True;
304 }
305 }
306 return False;
sewardjaf44c822007-11-25 14:01:38 +0000307}
308
309/*------------------------------------------------------------*/
310/*--- Statistics printing ---*/
311/*------------------------------------------------------------*/
312
313void drd_print_malloc_stats(void)
314{
bart3772a982008-03-15 08:11:03 +0000315 DRD_Chunk* mc;
316 SizeT nblocks = 0;
317 SizeT nbytes = 0;
sewardjaf44c822007-11-25 14:01:38 +0000318
bart3772a982008-03-15 08:11:03 +0000319 if (VG_(clo_verbosity) == 0)
320 return;
321 if (VG_(clo_xml))
322 return;
sewardjaf44c822007-11-25 14:01:38 +0000323
bart3772a982008-03-15 08:11:03 +0000324 /* Count memory still in use. */
325 VG_(HT_ResetIter)(drd_malloc_list);
326 while ((mc = VG_(HT_Next)(drd_malloc_list)))
327 {
328 nblocks++;
329 nbytes += mc->size;
330 }
sewardjaf44c822007-11-25 14:01:38 +0000331
bart3772a982008-03-15 08:11:03 +0000332 VG_(message)(Vg_DebugMsg,
333 "malloc/free: in use at exit: %lu bytes in %lu blocks.",
334 nbytes, nblocks);
335 VG_(message)(Vg_DebugMsg,
336 "malloc/free: %lu allocs, %lu frees, %lu bytes allocated.",
337 cmalloc_n_mallocs,
338 cmalloc_n_frees, cmalloc_bs_mallocd);
339 if (VG_(clo_verbosity) > 1)
340 VG_(message)(Vg_DebugMsg, " ");
sewardjaf44c822007-11-25 14:01:38 +0000341}
342
343/*--------------------------------------------------------------------*/
344/*--- end ---*/
345/*--------------------------------------------------------------------*/