blob: b2d06cdaa521363782422c104012804136690f34 [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/*------------------------------------------------------------*/
42/*--- Defns ---*/
43/*------------------------------------------------------------*/
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{
bart3772a982008-03-15 08:11:03 +000073 DRD_Chunk* mc = VG_(malloc)(sizeof(DRD_Chunk));
74 mc->data = p;
75 mc->size = size;
76 mc->where = VG_(record_ExeContext)(tid, 0);
sewardjaf44c822007-11-25 14:01:38 +000077
bart3772a982008-03-15 08:11:03 +000078 return mc;
sewardjaf44c822007-11-25 14:01:38 +000079}
80
81/*------------------------------------------------------------*/
82/*--- client_malloc(), etc ---*/
83/*------------------------------------------------------------*/
84
85/* Allocate memory and note change in memory available */
86static
87__inline__
88void* drd_new_block(ThreadId tid,
89 SizeT size, SizeT align,
90 Bool is_zeroed)
91{
bart3772a982008-03-15 08:11:03 +000092 Addr p;
sewardjaf44c822007-11-25 14:01:38 +000093
bart3772a982008-03-15 08:11:03 +000094 cmalloc_n_mallocs ++;
sewardjaf44c822007-11-25 14:01:38 +000095
bart3772a982008-03-15 08:11:03 +000096 // Allocate and zero
97 p = (Addr)VG_(cli_malloc)(align, size);
98 if (!p) {
99 return NULL;
100 }
101 if (is_zeroed) VG_(memset)((void*)p, 0, size);
102 s_start_using_mem_callback(p, p + size);
sewardjaf44c822007-11-25 14:01:38 +0000103
bart3772a982008-03-15 08:11:03 +0000104 // Only update this stat if allocation succeeded.
105 cmalloc_bs_mallocd += size;
sewardjaf44c822007-11-25 14:01:38 +0000106
bart3772a982008-03-15 08:11:03 +0000107 VG_(HT_add_node)(drd_malloc_list, create_DRD_Chunk(tid, p, size));
sewardjaf44c822007-11-25 14:01:38 +0000108
bart3772a982008-03-15 08:11:03 +0000109 return (void*)p;
sewardjaf44c822007-11-25 14:01:38 +0000110}
111
112static
113void* drd_malloc(ThreadId tid, SizeT n)
114{
bart3772a982008-03-15 08:11:03 +0000115 return drd_new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000116}
117
118static
119void* drd_memalign(ThreadId tid, SizeT align, SizeT n)
120{
bart3772a982008-03-15 08:11:03 +0000121 return drd_new_block(tid, n, align, /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000122}
123
124static
125void* drd_calloc(ThreadId tid, SizeT nmemb, SizeT size1)
126{
bart3772a982008-03-15 08:11:03 +0000127 return drd_new_block(tid, nmemb*size1, VG_(clo_alignment),
128 /*is_zeroed*/True);
sewardjaf44c822007-11-25 14:01:38 +0000129}
130
131static
132__inline__
133void drd_handle_free(ThreadId tid, Addr p)
134{
bart3772a982008-03-15 08:11:03 +0000135 DRD_Chunk* mc;
sewardjaf44c822007-11-25 14:01:38 +0000136
bart3772a982008-03-15 08:11:03 +0000137 cmalloc_n_frees++;
sewardjaf44c822007-11-25 14:01:38 +0000138
bart3772a982008-03-15 08:11:03 +0000139 mc = VG_(HT_remove)(drd_malloc_list, (UWord)p);
140 if (mc == NULL)
141 {
142 tl_assert(0);
143 }
144 else
145 {
146 s_stop_using_mem_callback(mc->data, mc->size);
147 VG_(free)(mc);
148 }
sewardjaf44c822007-11-25 14:01:38 +0000149}
150
151static
152void drd_free(ThreadId tid, void* p)
153{
bart3772a982008-03-15 08:11:03 +0000154 drd_handle_free(tid, (Addr)p);
sewardjaf44c822007-11-25 14:01:38 +0000155}
156
157static
158void* drd_realloc(ThreadId tid, void* p_old, SizeT new_size)
159{
bart3772a982008-03-15 08:11:03 +0000160 DRD_Chunk* mc;
161 void* p_new;
162 SizeT old_size;
sewardjaf44c822007-11-25 14:01:38 +0000163
bart3772a982008-03-15 08:11:03 +0000164 cmalloc_n_frees ++;
165 cmalloc_n_mallocs ++;
166 cmalloc_bs_mallocd += new_size;
sewardjaf44c822007-11-25 14:01:38 +0000167
bart3772a982008-03-15 08:11:03 +0000168 /* Remove the old block */
169 mc = VG_(HT_remove)(drd_malloc_list, (UWord)p_old);
170 if (mc == NULL) {
171 tl_assert(0);
172 return NULL;
173 }
sewardjaf44c822007-11-25 14:01:38 +0000174
bart3772a982008-03-15 08:11:03 +0000175 old_size = mc->size;
sewardjaf44c822007-11-25 14:01:38 +0000176
bart3772a982008-03-15 08:11:03 +0000177 if (old_size == new_size)
178 {
179 /* size unchanged */
180 mc->where = VG_(record_ExeContext)(tid, 0);
181 p_new = p_old;
sewardjaf44c822007-11-25 14:01:38 +0000182
bart3772a982008-03-15 08:11:03 +0000183 }
184 else if (old_size > new_size)
185 {
186 /* new size is smaller */
187 s_stop_using_mem_callback(mc->data + new_size, old_size);
188 mc->size = new_size;
189 mc->where = VG_(record_ExeContext)(tid, 0);
190 p_new = p_old;
sewardjaf44c822007-11-25 14:01:38 +0000191
bart3772a982008-03-15 08:11:03 +0000192 }
193 else
194 {
195 /* new size is bigger */
196 /* Get new memory */
197 const Addr a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
sewardjaf44c822007-11-25 14:01:38 +0000198
bart3772a982008-03-15 08:11:03 +0000199 if (a_new)
200 {
201 /* Copy from old to new */
202 VG_(memcpy)((void*)a_new, p_old, mc->size);
sewardjaf44c822007-11-25 14:01:38 +0000203
bart3772a982008-03-15 08:11:03 +0000204 /* Free old memory */
205 s_stop_using_mem_callback(mc->data, mc->size);
206 VG_(free)(mc);
sewardjaf44c822007-11-25 14:01:38 +0000207
bart3772a982008-03-15 08:11:03 +0000208 // Allocate a new chunk.
209 mc = create_DRD_Chunk(tid, a_new, new_size);
210 s_start_using_mem_callback(a_new, a_new + new_size);
211 }
212 else
213 {
214 /* Allocation failed -- leave original block untouched. */
215 }
sewardjaf44c822007-11-25 14:01:38 +0000216
bart3772a982008-03-15 08:11:03 +0000217 p_new = (void*)a_new;
218 }
sewardjaf44c822007-11-25 14:01:38 +0000219
bart3772a982008-03-15 08:11:03 +0000220 // Now insert the new mc (with a possibly new 'data' field) into
221 // malloc_list. If this realloc() did not increase the memory size, we
222 // will have removed and then re-added mc unnecessarily. But that's ok
223 // because shrinking a block with realloc() is (presumably) much rarer
224 // than growing it, and this way simplifies the growing case.
225 VG_(HT_add_node)(drd_malloc_list, mc);
sewardjaf44c822007-11-25 14:01:38 +0000226
bart3772a982008-03-15 08:11:03 +0000227 return p_new;
sewardjaf44c822007-11-25 14:01:38 +0000228}
229
230static
231void* drd___builtin_new(ThreadId tid, SizeT n)
232{
bart3772a982008-03-15 08:11:03 +0000233 void* const result = drd_new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
234 //VG_(message)(Vg_DebugMsg, "__builtin_new(%d, %d) = %p", tid, n, result);
235 return result;
sewardjaf44c822007-11-25 14:01:38 +0000236}
237
238static
239void drd___builtin_delete(ThreadId tid, void* p)
240{
bart3772a982008-03-15 08:11:03 +0000241 //VG_(message)(Vg_DebugMsg, "__builtin_delete(%d, %p)", tid, p);
242 drd_handle_free(tid, (Addr)p);
sewardjaf44c822007-11-25 14:01:38 +0000243}
244
245static
246void* drd___builtin_vec_new(ThreadId tid, SizeT n)
247{
bart3772a982008-03-15 08:11:03 +0000248 return drd_new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000249}
250
251static
252void drd___builtin_vec_delete(ThreadId tid, void* p)
253{
bart3772a982008-03-15 08:11:03 +0000254 drd_handle_free(tid, (Addr)p);
sewardjaf44c822007-11-25 14:01:38 +0000255}
256
257void drd_register_malloc_wrappers(const StartUsingMem start_using_mem_callback,
258 const StopUsingMem stop_using_mem_callback)
259{
bart3772a982008-03-15 08:11:03 +0000260 tl_assert(drd_malloc_list == 0);
261 drd_malloc_list = VG_(HT_construct)("drd_malloc_list"); // a big prime
262 tl_assert(drd_malloc_list != 0);
263 tl_assert(stop_using_mem_callback);
sewardjaf44c822007-11-25 14:01:38 +0000264
bart3772a982008-03-15 08:11:03 +0000265 s_start_using_mem_callback = start_using_mem_callback;
266 s_stop_using_mem_callback = stop_using_mem_callback;
sewardjaf44c822007-11-25 14:01:38 +0000267
bart3772a982008-03-15 08:11:03 +0000268 VG_(needs_malloc_replacement)(drd_malloc,
269 drd___builtin_new,
270 drd___builtin_vec_new,
271 drd_memalign,
272 drd_calloc,
273 drd_free,
274 drd___builtin_delete,
275 drd___builtin_vec_delete,
276 drd_realloc,
277 0);
sewardjaf44c822007-11-25 14:01:38 +0000278}
279
280Bool drd_heap_addrinfo(Addr const a,
281 Addr* const data,
282 SizeT* const size,
283 ExeContext** const where)
284{
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
bart3772a982008-03-15 08:11:03 +0000291 VG_(HT_ResetIter)(drd_malloc_list);
292 while ((mc = VG_(HT_Next)(drd_malloc_list)))
293 {
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
309void drd_print_malloc_stats(void)
310{
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. */
321 VG_(HT_ResetIter)(drd_malloc_list);
322 while ((mc = VG_(HT_Next)(drd_malloc_list)))
323 {
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.",
333 cmalloc_n_mallocs,
334 cmalloc_n_frees, cmalloc_bs_mallocd);
335 if (VG_(clo_verbosity) > 1)
336 VG_(message)(Vg_DebugMsg, " ");
sewardjaf44c822007-11-25 14:01:38 +0000337}
338
339/*--------------------------------------------------------------------*/
340/*--- end ---*/
341/*--------------------------------------------------------------------*/