2 * Copyright 1997 Marcus Meissner
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/debug.h"
24 #include "wine/heap.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(olemalloc
);
28 static const IMallocVtbl allocator_vtbl
;
32 IMalloc IMalloc_iface
;
34 DWORD spyed_allocations
;
35 BOOL spy_release_pending
; /* CoRevokeMallocSpy called with spyed allocations left */
40 static struct allocator allocator
= { .IMalloc_iface
.lpVtbl
= &allocator_vtbl
};
42 static CRITICAL_SECTION allocspy_cs
;
43 static CRITICAL_SECTION_DEBUG allocspy_cs_debug
=
46 { &allocspy_cs_debug
.ProcessLocksList
, &allocspy_cs_debug
.ProcessLocksList
},
47 0, 0, { (DWORD_PTR
)(__FILE__
": allocspy_cs") }
49 static CRITICAL_SECTION allocspy_cs
= { &allocspy_cs_debug
, -1, 0, 0, 0, 0 };
51 static BOOL
mallocspy_grow(DWORD length
)
55 if (!allocator
.blocks
) blocks
= LocalAlloc(LMEM_ZEROINIT
, length
* sizeof(void *));
56 else blocks
= LocalReAlloc(allocator
.blocks
, length
* sizeof(void *), LMEM_ZEROINIT
| LMEM_MOVEABLE
);
59 allocator
.blocks
= blocks
;
60 allocator
.blocks_length
= length
;
63 return blocks
!= NULL
;
66 static void mallocspy_add_mem(void *mem
)
70 if (!mem
|| (!allocator
.blocks_length
&& !mallocspy_grow(0x1000)))
73 /* Find a free location */
74 current
= allocator
.blocks
;
78 if (current
>= allocator
.blocks
+ allocator
.blocks_length
)
80 DWORD old_length
= allocator
.blocks_length
;
81 if (!mallocspy_grow(allocator
.blocks_length
+ 0x1000))
83 current
= allocator
.blocks
+ old_length
;
88 allocator
.spyed_allocations
++;
91 static void** mallocspy_is_allocation_spyed(const void *mem
)
93 void **current
= allocator
.blocks
;
95 while (*current
!= mem
)
98 if (current
>= allocator
.blocks
+ allocator
.blocks_length
)
105 static BOOL
mallocspy_remove_spyed_memory(const void *mem
)
109 if (!allocator
.blocks_length
)
112 if (!(current
= mallocspy_is_allocation_spyed(mem
)))
115 allocator
.spyed_allocations
--;
120 static HRESULT WINAPI
allocator_QueryInterface(IMalloc
*iface
, REFIID riid
, void **obj
)
122 TRACE("%s, %p.\n", debugstr_guid(riid
), obj
);
124 if (IsEqualIID(&IID_IUnknown
, riid
) || IsEqualIID(&IID_IMalloc
, riid
))
126 *obj
= &allocator
.IMalloc_iface
;
130 return E_NOINTERFACE
;
133 static ULONG WINAPI
allocator_AddRef(IMalloc
*iface
)
138 static ULONG WINAPI
allocator_Release(IMalloc
*iface
)
143 static void * WINAPI
allocator_Alloc(IMalloc
*iface
, SIZE_T cb
)
151 SIZE_T preAllocResult
;
153 EnterCriticalSection(&allocspy_cs
);
154 preAllocResult
= IMallocSpy_PreAlloc(allocator
.spy
, cb
);
155 if (cb
&& !preAllocResult
)
157 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
158 TRACE("returning null\n");
159 LeaveCriticalSection(&allocspy_cs
);
164 addr
= HeapAlloc(GetProcessHeap(), 0, cb
);
168 addr
= IMallocSpy_PostAlloc(allocator
.spy
, addr
);
169 mallocspy_add_mem(addr
);
170 LeaveCriticalSection(&allocspy_cs
);
177 static void * WINAPI
allocator_Realloc(IMalloc
*iface
, void *pv
, SIZE_T cb
)
181 TRACE("%p, %ld.\n",pv
,cb
);
188 EnterCriticalSection(&allocspy_cs
);
189 spyed
= mallocspy_remove_spyed_memory(pv
);
190 cb
= IMallocSpy_PreRealloc(allocator
.spy
, pv
, cb
, &real_mem
, spyed
);
192 /* check if can release the spy */
193 if (allocator
.spy_release_pending
&& !allocator
.spyed_allocations
)
195 IMallocSpy_Release(allocator
.spy
);
196 allocator
.spy_release_pending
= FALSE
;
197 allocator
.spy
= NULL
;
198 LeaveCriticalSection(&allocspy_cs
);
203 /* PreRealloc can force Realloc to fail */
205 LeaveCriticalSection(&allocspy_cs
);
212 if (!pv
) addr
= HeapAlloc(GetProcessHeap(), 0, cb
);
213 else if (cb
) addr
= HeapReAlloc(GetProcessHeap(), 0, pv
, cb
);
216 HeapFree(GetProcessHeap(), 0, pv
);
222 addr
= IMallocSpy_PostRealloc(allocator
.spy
, addr
, TRUE
);
223 mallocspy_add_mem(addr
);
224 LeaveCriticalSection(&allocspy_cs
);
227 TRACE("%p.\n", addr
);
231 static void WINAPI
allocator_Free(IMalloc
*iface
, void *mem
)
233 BOOL spyed_block
= FALSE
, spy_active
= FALSE
;
242 EnterCriticalSection(&allocspy_cs
);
243 spyed_block
= mallocspy_remove_spyed_memory(mem
);
245 mem
= IMallocSpy_PreFree(allocator
.spy
, mem
, spyed_block
);
248 HeapFree(GetProcessHeap(), 0, mem
);
252 IMallocSpy_PostFree(allocator
.spy
, spyed_block
);
254 /* check if can release the spy */
255 if (allocator
.spy_release_pending
&& !allocator
.spyed_allocations
)
257 IMallocSpy_Release(allocator
.spy
);
258 allocator
.spy_release_pending
= FALSE
;
259 allocator
.spy
= NULL
;
262 LeaveCriticalSection(&allocspy_cs
);
266 /******************************************************************************
269 * win95: size allocated (4 byte boundaries)
270 * win2k: size originally requested !!! (allocated on 8 byte boundaries)
272 static SIZE_T WINAPI
allocator_GetSize(IMalloc
*iface
, void *mem
)
274 BOOL spyed_block
= FALSE
, spy_active
= FALSE
;
284 EnterCriticalSection(&allocspy_cs
);
285 spyed_block
= !!mallocspy_is_allocation_spyed(mem
);
287 mem
= IMallocSpy_PreGetSize(allocator
.spy
, mem
, spyed_block
);
290 size
= HeapSize(GetProcessHeap(), 0, mem
);
294 size
= IMallocSpy_PostGetSize(allocator
.spy
, size
, spyed_block
);
295 LeaveCriticalSection(&allocspy_cs
);
301 static INT WINAPI
allocator_DidAlloc(IMalloc
*iface
, void *mem
)
303 BOOL spyed_block
= FALSE
, spy_active
= FALSE
;
313 EnterCriticalSection(&allocspy_cs
);
314 spyed_block
= !!mallocspy_is_allocation_spyed(mem
);
316 mem
= IMallocSpy_PreDidAlloc(allocator
.spy
, mem
, spyed_block
);
319 did_alloc
= HeapValidate(GetProcessHeap(), 0, mem
);
323 did_alloc
= IMallocSpy_PostDidAlloc(allocator
.spy
, mem
, spyed_block
, did_alloc
);
324 LeaveCriticalSection(&allocspy_cs
);
330 static void WINAPI
allocator_HeapMinimize(IMalloc
*iface
)
332 BOOL spy_active
= FALSE
;
338 EnterCriticalSection(&allocspy_cs
);
340 IMallocSpy_PreHeapMinimize(allocator
.spy
);
345 IMallocSpy_PostHeapMinimize(allocator
.spy
);
346 LeaveCriticalSection(&allocspy_cs
);
350 static const IMallocVtbl allocator_vtbl
=
352 allocator_QueryInterface
,
360 allocator_HeapMinimize
363 /******************************************************************************
364 * CoGetMalloc (combase.@)
366 HRESULT WINAPI
CoGetMalloc(DWORD context
, IMalloc
**imalloc
)
368 if (context
!= MEMCTX_TASK
)
374 *imalloc
= &allocator
.IMalloc_iface
;
379 /***********************************************************************
380 * CoTaskMemAlloc (combase.@)
382 void * WINAPI
CoTaskMemAlloc(SIZE_T size
)
384 return IMalloc_Alloc(&allocator
.IMalloc_iface
, size
);
387 /***********************************************************************
388 * CoTaskMemFree (combase.@)
390 void WINAPI
CoTaskMemFree(void *ptr
)
392 IMalloc_Free(&allocator
.IMalloc_iface
, ptr
);
395 /***********************************************************************
396 * CoTaskMemRealloc (combase.@)
398 void * WINAPI
CoTaskMemRealloc(void *ptr
, SIZE_T size
)
400 return IMalloc_Realloc(&allocator
.IMalloc_iface
, ptr
, size
);
403 /***********************************************************************
404 * CoRegisterMallocSpy (combase.@)
406 HRESULT WINAPI
CoRegisterMallocSpy(IMallocSpy
*spy
)
408 HRESULT hr
= E_INVALIDARG
;
412 if (!spy
) return E_INVALIDARG
;
414 EnterCriticalSection(&allocspy_cs
);
418 else if (SUCCEEDED(IMallocSpy_QueryInterface(spy
, &IID_IMallocSpy
, (void **)&spy
)))
424 LeaveCriticalSection(&allocspy_cs
);
429 /***********************************************************************
430 * CoRevokeMallocSpy (combase.@)
432 HRESULT WINAPI
CoRevokeMallocSpy(void)
438 EnterCriticalSection(&allocspy_cs
);
442 else if (allocator
.spyed_allocations
)
444 allocator
.spy_release_pending
= TRUE
;
449 IMallocSpy_Release(allocator
.spy
);
450 allocator
.spy
= NULL
;
453 LeaveCriticalSection(&allocspy_cs
);