blob: bf8da849fb56e60c0808f26e0ecd73164ac6ee96 [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
bart246fbf22009-02-15 14:46:17 +000041/* Local type definitions. */
sewardjaf44c822007-11-25 14:01:38 +000042
43typedef struct _DRD_Chunk {
bart3772a982008-03-15 08:11:03 +000044 struct _DRD_Chunk* next;
45 Addr data; // ptr to actual block
46 SizeT size : (sizeof(UWord)*8)-2; //size requested; 30 or 62 bits
47 ExeContext* where; // where it was allocated
sewardjaf44c822007-11-25 14:01:38 +000048} DRD_Chunk;
49
bart246fbf22009-02-15 14:46:17 +000050
51/* Local variables. */
52
53static StartUsingMem DRD_(s_start_using_mem_callback);
54static StopUsingMem DRD_(s_stop_using_mem_callback);
sewardjaf44c822007-11-25 14:01:38 +000055/* Stats ... */
bart246fbf22009-02-15 14:46:17 +000056static SizeT DRD_(s_cmalloc_n_mallocs) = 0;
57static SizeT DRD_(s_cmalloc_n_frees) = 0;
58static SizeT DRD_(s_cmalloc_bs_mallocd) = 0;
59/* Record malloc'd blocks. */
60static VgHashTable DRD_(s_malloc_list) = NULL;
sewardjaf44c822007-11-25 14:01:38 +000061
62
63/*------------------------------------------------------------*/
64/*--- Tracking malloc'd and free'd blocks ---*/
65/*------------------------------------------------------------*/
66
bart246fbf22009-02-15 14:46:17 +000067/** Allocate its shadow chunk, put it on the appropriate list. */
68static DRD_Chunk* DRD_(create_chunk)(ThreadId tid, Addr p, SizeT size)
sewardjaf44c822007-11-25 14:01:38 +000069{
sewardj9c606bd2008-09-18 18:12:50 +000070 DRD_Chunk* mc = VG_(malloc)("drd.malloc_wrappers.cDC.1",
71 sizeof(DRD_Chunk));
bart3772a982008-03-15 08:11:03 +000072 mc->data = p;
73 mc->size = size;
74 mc->where = VG_(record_ExeContext)(tid, 0);
sewardjaf44c822007-11-25 14:01:38 +000075
bart3772a982008-03-15 08:11:03 +000076 return mc;
sewardjaf44c822007-11-25 14:01:38 +000077}
78
79/*------------------------------------------------------------*/
80/*--- client_malloc(), etc ---*/
81/*------------------------------------------------------------*/
82
83/* Allocate memory and note change in memory available */
84static
85__inline__
bart246fbf22009-02-15 14:46:17 +000086void* DRD_(new_block)(ThreadId tid,
87 SizeT size, SizeT align,
88 Bool is_zeroed)
sewardjaf44c822007-11-25 14:01:38 +000089{
bart3772a982008-03-15 08:11:03 +000090 Addr p;
sewardjaf44c822007-11-25 14:01:38 +000091
bart246fbf22009-02-15 14:46:17 +000092 DRD_(s_cmalloc_n_mallocs) ++;
sewardjaf44c822007-11-25 14:01:38 +000093
bart3772a982008-03-15 08:11:03 +000094 // Allocate and zero
95 p = (Addr)VG_(cli_malloc)(align, size);
96 if (!p) {
97 return NULL;
98 }
99 if (is_zeroed) VG_(memset)((void*)p, 0, size);
bart246fbf22009-02-15 14:46:17 +0000100 DRD_(s_start_using_mem_callback)(p, p + size, 0/*ec_uniq*/);
sewardjaf44c822007-11-25 14:01:38 +0000101
bart3772a982008-03-15 08:11:03 +0000102 // Only update this stat if allocation succeeded.
bart246fbf22009-02-15 14:46:17 +0000103 DRD_(s_cmalloc_bs_mallocd) += size;
sewardjaf44c822007-11-25 14:01:38 +0000104
bart246fbf22009-02-15 14:46:17 +0000105 VG_(HT_add_node)(DRD_(s_malloc_list), DRD_(create_chunk)(tid, p, size));
sewardjaf44c822007-11-25 14:01:38 +0000106
bart3772a982008-03-15 08:11:03 +0000107 return (void*)p;
sewardjaf44c822007-11-25 14:01:38 +0000108}
109
bart246fbf22009-02-15 14:46:17 +0000110static void* DRD_(malloc)(ThreadId tid, SizeT n)
sewardjaf44c822007-11-25 14:01:38 +0000111{
bart246fbf22009-02-15 14:46:17 +0000112 return DRD_(new_block)(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000113}
114
bart246fbf22009-02-15 14:46:17 +0000115static void* DRD_(memalign)(ThreadId tid, SizeT align, SizeT n)
sewardjaf44c822007-11-25 14:01:38 +0000116{
bart246fbf22009-02-15 14:46:17 +0000117 return DRD_(new_block)(tid, n, align, /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000118}
119
bart246fbf22009-02-15 14:46:17 +0000120static void* DRD_(calloc)(ThreadId tid, SizeT nmemb, SizeT size1)
sewardjaf44c822007-11-25 14:01:38 +0000121{
bart246fbf22009-02-15 14:46:17 +0000122 return DRD_(new_block)(tid, nmemb*size1, VG_(clo_alignment),
123 /*is_zeroed*/True);
sewardjaf44c822007-11-25 14:01:38 +0000124}
125
bart246fbf22009-02-15 14:46:17 +0000126static __inline__ void DRD_(handle_free)(ThreadId tid, Addr p)
sewardjaf44c822007-11-25 14:01:38 +0000127{
bart3772a982008-03-15 08:11:03 +0000128 DRD_Chunk* mc;
sewardjaf44c822007-11-25 14:01:38 +0000129
bart246fbf22009-02-15 14:46:17 +0000130 DRD_(s_cmalloc_n_frees)++;
sewardjaf44c822007-11-25 14:01:38 +0000131
bart246fbf22009-02-15 14:46:17 +0000132 mc = VG_(HT_remove)(DRD_(s_malloc_list), (UWord)p);
bart3772a982008-03-15 08:11:03 +0000133 if (mc == NULL)
134 {
135 tl_assert(0);
136 }
137 else
138 {
barte8a274c2008-04-20 08:33:10 +0000139 tl_assert(p == mc->data);
bart84595c02008-03-22 17:35:28 +0000140 if (mc->size > 0)
bart246fbf22009-02-15 14:46:17 +0000141 DRD_(s_stop_using_mem_callback)(mc->data, mc->size);
barte8a274c2008-04-20 08:33:10 +0000142 VG_(cli_free)((void*)p);
bart3772a982008-03-15 08:11:03 +0000143 VG_(free)(mc);
144 }
sewardjaf44c822007-11-25 14:01:38 +0000145}
146
bart246fbf22009-02-15 14:46:17 +0000147static void DRD_(free)(ThreadId tid, void* p)
sewardjaf44c822007-11-25 14:01:38 +0000148{
bart246fbf22009-02-15 14:46:17 +0000149 DRD_(handle_free)(tid, (Addr)p);
sewardjaf44c822007-11-25 14:01:38 +0000150}
151
bart246fbf22009-02-15 14:46:17 +0000152static void* DRD_(realloc)(ThreadId tid, void* p_old, SizeT new_size)
sewardjaf44c822007-11-25 14:01:38 +0000153{
bart3772a982008-03-15 08:11:03 +0000154 DRD_Chunk* mc;
155 void* p_new;
156 SizeT old_size;
sewardjaf44c822007-11-25 14:01:38 +0000157
bart246fbf22009-02-15 14:46:17 +0000158 DRD_(s_cmalloc_n_frees) ++;
159 DRD_(s_cmalloc_n_mallocs) ++;
160 DRD_(s_cmalloc_bs_mallocd) += new_size;
sewardjaf44c822007-11-25 14:01:38 +0000161
bart3772a982008-03-15 08:11:03 +0000162 /* Remove the old block */
bart246fbf22009-02-15 14:46:17 +0000163 mc = VG_(HT_remove)(DRD_(s_malloc_list), (UWord)p_old);
bart3772a982008-03-15 08:11:03 +0000164 if (mc == NULL) {
165 tl_assert(0);
166 return NULL;
167 }
sewardjaf44c822007-11-25 14:01:38 +0000168
bart3772a982008-03-15 08:11:03 +0000169 old_size = mc->size;
sewardjaf44c822007-11-25 14:01:38 +0000170
bart3772a982008-03-15 08:11:03 +0000171 if (old_size == new_size)
172 {
173 /* size unchanged */
174 mc->where = VG_(record_ExeContext)(tid, 0);
175 p_new = p_old;
sewardjaf44c822007-11-25 14:01:38 +0000176
bart3772a982008-03-15 08:11:03 +0000177 }
178 else if (old_size > new_size)
179 {
180 /* new size is smaller */
bart246fbf22009-02-15 14:46:17 +0000181 DRD_(s_stop_using_mem_callback)(mc->data + new_size, old_size);
bart3772a982008-03-15 08:11:03 +0000182 mc->size = new_size;
183 mc->where = VG_(record_ExeContext)(tid, 0);
184 p_new = p_old;
sewardjaf44c822007-11-25 14:01:38 +0000185
bart3772a982008-03-15 08:11:03 +0000186 }
187 else
188 {
189 /* new size is bigger */
190 /* Get new memory */
191 const Addr a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
sewardjaf44c822007-11-25 14:01:38 +0000192
bart3772a982008-03-15 08:11:03 +0000193 if (a_new)
194 {
195 /* Copy from old to new */
196 VG_(memcpy)((void*)a_new, p_old, mc->size);
sewardjaf44c822007-11-25 14:01:38 +0000197
bart3772a982008-03-15 08:11:03 +0000198 /* Free old memory */
bart246fbf22009-02-15 14:46:17 +0000199 DRD_(s_stop_using_mem_callback)(mc->data, mc->size);
bart3772a982008-03-15 08:11:03 +0000200 VG_(free)(mc);
sewardjaf44c822007-11-25 14:01:38 +0000201
bart3772a982008-03-15 08:11:03 +0000202 // Allocate a new chunk.
bart246fbf22009-02-15 14:46:17 +0000203 mc = DRD_(create_chunk)(tid, a_new, new_size);
204 DRD_(s_start_using_mem_callback)(a_new, a_new + new_size, 0/*ec_uniq*/);
bart3772a982008-03-15 08:11:03 +0000205 }
206 else
207 {
208 /* Allocation failed -- leave original block untouched. */
209 }
sewardjaf44c822007-11-25 14:01:38 +0000210
bart3772a982008-03-15 08:11:03 +0000211 p_new = (void*)a_new;
212 }
sewardjaf44c822007-11-25 14:01:38 +0000213
bart3772a982008-03-15 08:11:03 +0000214 // Now insert the new mc (with a possibly new 'data' field) into
215 // malloc_list. If this realloc() did not increase the memory size, we
216 // will have removed and then re-added mc unnecessarily. But that's ok
217 // because shrinking a block with realloc() is (presumably) much rarer
218 // than growing it, and this way simplifies the growing case.
bart246fbf22009-02-15 14:46:17 +0000219 VG_(HT_add_node)(DRD_(s_malloc_list), mc);
sewardjaf44c822007-11-25 14:01:38 +0000220
bart3772a982008-03-15 08:11:03 +0000221 return p_new;
sewardjaf44c822007-11-25 14:01:38 +0000222}
223
bart246fbf22009-02-15 14:46:17 +0000224static void* DRD_(__builtin_new)(ThreadId tid, SizeT n)
sewardjaf44c822007-11-25 14:01:38 +0000225{
bart246fbf22009-02-15 14:46:17 +0000226 void* const result = DRD_(new_block)(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
bart3772a982008-03-15 08:11:03 +0000227 //VG_(message)(Vg_DebugMsg, "__builtin_new(%d, %d) = %p", tid, n, result);
228 return result;
sewardjaf44c822007-11-25 14:01:38 +0000229}
230
bart246fbf22009-02-15 14:46:17 +0000231static void DRD_(__builtin_delete)(ThreadId tid, void* p)
sewardjaf44c822007-11-25 14:01:38 +0000232{
bart3772a982008-03-15 08:11:03 +0000233 //VG_(message)(Vg_DebugMsg, "__builtin_delete(%d, %p)", tid, p);
bart246fbf22009-02-15 14:46:17 +0000234 DRD_(handle_free)(tid, (Addr)p);
sewardjaf44c822007-11-25 14:01:38 +0000235}
236
bart246fbf22009-02-15 14:46:17 +0000237static void* DRD_(__builtin_vec_new)(ThreadId tid, SizeT n)
sewardjaf44c822007-11-25 14:01:38 +0000238{
bart246fbf22009-02-15 14:46:17 +0000239 return DRD_(new_block)(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
sewardjaf44c822007-11-25 14:01:38 +0000240}
241
bart246fbf22009-02-15 14:46:17 +0000242static void DRD_(__builtin_vec_delete)(ThreadId tid, void* p)
sewardjaf44c822007-11-25 14:01:38 +0000243{
bart246fbf22009-02-15 14:46:17 +0000244 DRD_(handle_free)(tid, (Addr)p);
sewardjaf44c822007-11-25 14:01:38 +0000245}
246
bart246fbf22009-02-15 14:46:17 +0000247void DRD_(register_malloc_wrappers)(const StartUsingMem start_callback,
248 const StopUsingMem stop_callback)
sewardjaf44c822007-11-25 14:01:38 +0000249{
bart246fbf22009-02-15 14:46:17 +0000250 tl_assert(DRD_(s_malloc_list) == 0);
251 DRD_(s_malloc_list) = VG_(HT_construct)("drd_malloc_list"); // a big prime
252 tl_assert(DRD_(s_malloc_list) != 0);
253 tl_assert(start_callback);
254 tl_assert(stop_callback);
sewardjaf44c822007-11-25 14:01:38 +0000255
bart246fbf22009-02-15 14:46:17 +0000256 DRD_(s_start_using_mem_callback) = start_callback;
257 DRD_(s_stop_using_mem_callback) = stop_callback;
sewardjaf44c822007-11-25 14:01:38 +0000258
bart246fbf22009-02-15 14:46:17 +0000259 VG_(needs_malloc_replacement)(DRD_(malloc),
260 DRD_(__builtin_new),
261 DRD_(__builtin_vec_new),
262 DRD_(memalign),
263 DRD_(calloc),
264 DRD_(free),
265 DRD_(__builtin_delete),
266 DRD_(__builtin_vec_delete),
267 DRD_(realloc),
bart3772a982008-03-15 08:11:03 +0000268 0);
sewardjaf44c822007-11-25 14:01:38 +0000269}
270
bart246fbf22009-02-15 14:46:17 +0000271Bool DRD_(heap_addrinfo)(Addr const a,
272 Addr* const data,
273 SizeT* const size,
274 ExeContext** const where)
sewardjaf44c822007-11-25 14:01:38 +0000275{
bart3772a982008-03-15 08:11:03 +0000276 DRD_Chunk* mc;
sewardjaf44c822007-11-25 14:01:38 +0000277
bart3772a982008-03-15 08:11:03 +0000278 tl_assert(data);
279 tl_assert(size);
280 tl_assert(where);
sewardjaf44c822007-11-25 14:01:38 +0000281
bart246fbf22009-02-15 14:46:17 +0000282 VG_(HT_ResetIter)(DRD_(s_malloc_list));
283 while ((mc = VG_(HT_Next)(DRD_(s_malloc_list))))
bart3772a982008-03-15 08:11:03 +0000284 {
285 if (mc->data <= a && a < mc->data + mc->size)
286 {
287 *data = mc->data;
288 *size = mc->size;
289 *where = mc->where;
290 return True;
291 }
292 }
293 return False;
sewardjaf44c822007-11-25 14:01:38 +0000294}
295
296/*------------------------------------------------------------*/
297/*--- Statistics printing ---*/
298/*------------------------------------------------------------*/
299
bart246fbf22009-02-15 14:46:17 +0000300void DRD_(print_malloc_stats)(void)
sewardjaf44c822007-11-25 14:01:38 +0000301{
bart3772a982008-03-15 08:11:03 +0000302 DRD_Chunk* mc;
303 SizeT nblocks = 0;
304 SizeT nbytes = 0;
sewardjaf44c822007-11-25 14:01:38 +0000305
bart3772a982008-03-15 08:11:03 +0000306 if (VG_(clo_verbosity) == 0)
307 return;
308 if (VG_(clo_xml))
309 return;
sewardjaf44c822007-11-25 14:01:38 +0000310
bart3772a982008-03-15 08:11:03 +0000311 /* Count memory still in use. */
bart246fbf22009-02-15 14:46:17 +0000312 VG_(HT_ResetIter)(DRD_(s_malloc_list));
313 while ((mc = VG_(HT_Next)(DRD_(s_malloc_list))))
bart3772a982008-03-15 08:11:03 +0000314 {
315 nblocks++;
316 nbytes += mc->size;
317 }
sewardjaf44c822007-11-25 14:01:38 +0000318
bart3772a982008-03-15 08:11:03 +0000319 VG_(message)(Vg_DebugMsg,
320 "malloc/free: in use at exit: %lu bytes in %lu blocks.",
321 nbytes, nblocks);
322 VG_(message)(Vg_DebugMsg,
323 "malloc/free: %lu allocs, %lu frees, %lu bytes allocated.",
bart246fbf22009-02-15 14:46:17 +0000324 DRD_(s_cmalloc_n_mallocs),
325 DRD_(s_cmalloc_n_frees), DRD_(s_cmalloc_bs_mallocd));
bart3772a982008-03-15 08:11:03 +0000326 if (VG_(clo_verbosity) > 1)
327 VG_(message)(Vg_DebugMsg, " ");
sewardjaf44c822007-11-25 14:01:38 +0000328}
329
330/*--------------------------------------------------------------------*/
331/*--- end ---*/
332/*--------------------------------------------------------------------*/