4 * Copyright 1997 Marcus Meissner
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(olemalloc
);
39 /******************************************************************************
40 * IMalloc32 implementation
43 * For supporting CoRegisterMallocSpy the IMalloc implementation must know if
44 * a given memory block was allocated with a spy active.
46 *****************************************************************************/
47 /* set the vtable later */
48 static const IMallocVtbl VT_IMalloc32
;
52 IMalloc IMalloc_iface
;
53 IMallocSpy
* pSpy
; /* the spy when active */
54 DWORD SpyedAllocationsLeft
; /* number of spyed allocations left */
55 BOOL SpyReleasePending
; /* CoRevokeMallocSpy called with spyed allocations left*/
56 LPVOID
* SpyedBlocks
; /* root of the table */
57 DWORD SpyedBlockTableLength
;/* size of the table*/
60 static struct allocator Malloc32
= { .IMalloc_iface
.lpVtbl
= &VT_IMalloc32
};
62 /* with a spy active all calls from pre to post methods are threadsafe */
63 static CRITICAL_SECTION IMalloc32_SpyCS
;
64 static CRITICAL_SECTION_DEBUG critsect_debug
=
66 0, 0, &IMalloc32_SpyCS
,
67 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
68 0, 0, { (DWORD_PTR
)(__FILE__
": IMalloc32_SpyCS") }
70 static CRITICAL_SECTION IMalloc32_SpyCS
= { &critsect_debug
, -1, 0, 0, 0, 0 };
72 /* resize the old table */
73 static BOOL
SetSpyedBlockTableLength ( DWORD NewLength
)
75 LPVOID
*NewSpyedBlocks
;
77 if (!Malloc32
.SpyedBlocks
) NewSpyedBlocks
= LocalAlloc(LMEM_ZEROINIT
, NewLength
* sizeof(PVOID
));
78 else NewSpyedBlocks
= LocalReAlloc(Malloc32
.SpyedBlocks
, NewLength
* sizeof(PVOID
), LMEM_ZEROINIT
| LMEM_MOVEABLE
);
80 Malloc32
.SpyedBlocks
= NewSpyedBlocks
;
81 Malloc32
.SpyedBlockTableLength
= NewLength
;
84 return NewSpyedBlocks
!= NULL
;
87 /* add a location to the table */
88 static BOOL
AddMemoryLocation(LPVOID
* pMem
)
92 /* allocate the table if not already allocated */
93 if (!Malloc32
.SpyedBlockTableLength
&& !SetSpyedBlockTableLength(0x1000))
96 /* find a free location */
97 Current
= Malloc32
.SpyedBlocks
;
100 if (Current
>= Malloc32
.SpyedBlocks
+ Malloc32
.SpyedBlockTableLength
) {
101 /* no more space in table, grow it */
102 DWORD old_length
= Malloc32
.SpyedBlockTableLength
;
103 if (!SetSpyedBlockTableLength( Malloc32
.SpyedBlockTableLength
+ 0x1000))
105 Current
= Malloc32
.SpyedBlocks
+ old_length
;
109 /* put the location in our table */
111 Malloc32
.SpyedAllocationsLeft
++;
112 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
116 static void** mallocspy_is_allocation_spyed(const void *mem
)
118 void **current
= Malloc32
.SpyedBlocks
;
120 while (*current
!= mem
)
123 if (current
>= Malloc32
.SpyedBlocks
+ Malloc32
.SpyedBlockTableLength
)
130 static BOOL
mallocspy_remove_spyed_memory(const void *mem
)
134 if (!Malloc32
.SpyedBlockTableLength
)
137 if (!(current
= mallocspy_is_allocation_spyed(mem
)))
140 Malloc32
.SpyedAllocationsLeft
--;
145 /******************************************************************************
146 * IMalloc32_QueryInterface [VTABLE]
148 static HRESULT WINAPI
IMalloc_fnQueryInterface(IMalloc
*iface
, REFIID refiid
, void **obj
)
150 TRACE("(%s,%p)\n",debugstr_guid(refiid
),obj
);
152 if (IsEqualIID(&IID_IUnknown
,refiid
) || IsEqualIID(&IID_IMalloc
,refiid
)) {
156 return E_NOINTERFACE
;
159 /******************************************************************************
160 * IMalloc32_AddRefRelease [VTABLE]
162 static ULONG WINAPI
IMalloc_fnAddRefRelease(IMalloc
*iface
)
167 /******************************************************************************
168 * IMalloc32_Alloc [VTABLE]
170 static void * WINAPI
IMalloc_fnAlloc(IMalloc
*iface
, SIZE_T cb
)
177 SIZE_T preAllocResult
;
179 EnterCriticalSection(&IMalloc32_SpyCS
);
180 preAllocResult
= IMallocSpy_PreAlloc(Malloc32
.pSpy
, cb
);
181 if ((cb
!= 0) && (preAllocResult
== 0)) {
182 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
183 TRACE("returning null\n");
184 LeaveCriticalSection(&IMalloc32_SpyCS
);
189 addr
= HeapAlloc(GetProcessHeap(),0,cb
);
192 addr
= IMallocSpy_PostAlloc(Malloc32
.pSpy
, addr
);
193 if (addr
) AddMemoryLocation(addr
);
194 LeaveCriticalSection(&IMalloc32_SpyCS
);
197 TRACE("--(%p)\n",addr
);
201 /******************************************************************************
202 * IMalloc32_Realloc [VTABLE]
204 static void * WINAPI
IMalloc_fnRealloc(IMalloc
*iface
, void *pv
, SIZE_T cb
)
208 TRACE("(%p,%ld)\n",pv
,cb
);
214 EnterCriticalSection(&IMalloc32_SpyCS
);
215 fSpyed
= mallocspy_remove_spyed_memory(pv
);
216 cb
= IMallocSpy_PreRealloc(Malloc32
.pSpy
, pv
, cb
, &pRealMemory
, fSpyed
);
218 /* check if can release the spy */
219 if(Malloc32
.SpyReleasePending
&& !Malloc32
.SpyedAllocationsLeft
) {
220 IMallocSpy_Release(Malloc32
.pSpy
);
221 Malloc32
.SpyReleasePending
= FALSE
;
222 Malloc32
.pSpy
= NULL
;
223 LeaveCriticalSection(&IMalloc32_SpyCS
);
227 /* PreRealloc can force Realloc to fail */
229 LeaveCriticalSection(&IMalloc32_SpyCS
);
236 if (!pv
) pNewMemory
= HeapAlloc(GetProcessHeap(),0,cb
);
237 else if (cb
) pNewMemory
= HeapReAlloc(GetProcessHeap(),0,pv
,cb
);
239 HeapFree(GetProcessHeap(),0,pv
);
244 pNewMemory
= IMallocSpy_PostRealloc(Malloc32
.pSpy
, pNewMemory
, TRUE
);
245 if (pNewMemory
) AddMemoryLocation(pNewMemory
);
246 LeaveCriticalSection(&IMalloc32_SpyCS
);
249 TRACE("--(%p)\n",pNewMemory
);
253 /******************************************************************************
254 * IMalloc32_Free [VTABLE]
256 static void WINAPI
IMalloc_fnFree(IMalloc
*iface
, void *mem
)
258 BOOL spyed_block
= FALSE
, spy_active
= FALSE
;
260 TRACE("(%p)\n", mem
);
267 EnterCriticalSection(&IMalloc32_SpyCS
);
268 spyed_block
= mallocspy_remove_spyed_memory(mem
);
270 mem
= IMallocSpy_PreFree(Malloc32
.pSpy
, mem
, spyed_block
);
273 HeapFree(GetProcessHeap(), 0, mem
);
277 IMallocSpy_PostFree(Malloc32
.pSpy
, spyed_block
);
279 /* check if can release the spy */
280 if (Malloc32
.SpyReleasePending
&& !Malloc32
.SpyedAllocationsLeft
)
282 IMallocSpy_Release(Malloc32
.pSpy
);
283 Malloc32
.SpyReleasePending
= FALSE
;
284 Malloc32
.pSpy
= NULL
;
287 LeaveCriticalSection(&IMalloc32_SpyCS
);
291 /******************************************************************************
292 * IMalloc32_GetSize [VTABLE]
296 * win95: size allocated (4 byte boundaries)
297 * win2k: size originally requested !!! (allocated on 8 byte boundaries)
299 static SIZE_T WINAPI
IMalloc_fnGetSize(IMalloc
*iface
, void *mem
)
301 BOOL spyed_block
= FALSE
, spy_active
= FALSE
;
304 TRACE("(%p)\n", mem
);
311 EnterCriticalSection(&IMalloc32_SpyCS
);
312 spyed_block
= !!mallocspy_is_allocation_spyed(mem
);
314 mem
= IMallocSpy_PreGetSize(Malloc32
.pSpy
, mem
, spyed_block
);
317 size
= HeapSize(GetProcessHeap(), 0, mem
);
321 size
= IMallocSpy_PostGetSize(Malloc32
.pSpy
, size
, spyed_block
);
322 LeaveCriticalSection(&IMalloc32_SpyCS
);
328 /******************************************************************************
329 * IMalloc32_DidAlloc [VTABLE]
331 static INT WINAPI
IMalloc_fnDidAlloc(IMalloc
*iface
, void *mem
)
333 BOOL spyed_block
= FALSE
, spy_active
= FALSE
;
336 TRACE("(%p)\n", mem
);
343 EnterCriticalSection(&IMalloc32_SpyCS
);
344 spyed_block
= !!mallocspy_is_allocation_spyed(mem
);
346 mem
= IMallocSpy_PreDidAlloc(Malloc32
.pSpy
, mem
, spyed_block
);
349 did_alloc
= HeapValidate(GetProcessHeap(), 0, mem
);
353 did_alloc
= IMallocSpy_PostDidAlloc(Malloc32
.pSpy
, mem
, spyed_block
, did_alloc
);
354 LeaveCriticalSection(&IMalloc32_SpyCS
);
360 /******************************************************************************
361 * IMalloc32_HeapMinimize [VTABLE]
363 static void WINAPI
IMalloc_fnHeapMinimize(IMalloc
*iface
)
365 BOOL spy_active
= FALSE
;
371 EnterCriticalSection(&IMalloc32_SpyCS
);
373 IMallocSpy_PreHeapMinimize(Malloc32
.pSpy
);
378 IMallocSpy_PostHeapMinimize(Malloc32
.pSpy
);
379 LeaveCriticalSection(&IMalloc32_SpyCS
);
383 static const IMallocVtbl VT_IMalloc32
=
385 IMalloc_fnQueryInterface
,
386 IMalloc_fnAddRefRelease
,
387 IMalloc_fnAddRefRelease
,
393 IMalloc_fnHeapMinimize
396 /******************************************************************************
397 * CoGetMalloc [OLE32.@]
399 * Retrieves the current IMalloc interface for the process.
402 * context [I] Should always be MEMCTX_TASK.
403 * imalloc [O] Address where memory allocator object will be stored.
407 * Failure: HRESULT code.
409 HRESULT WINAPI
CoGetMalloc(DWORD context
, IMalloc
**imalloc
)
411 if (context
!= MEMCTX_TASK
) {
416 *imalloc
= &Malloc32
.IMalloc_iface
;
420 /***********************************************************************
421 * CoTaskMemAlloc [OLE32.@]
423 * Allocates memory using the current process memory allocator.
426 * size [I] Size of the memory block to allocate.
429 * Success: Pointer to newly allocated memory block.
432 LPVOID WINAPI
CoTaskMemAlloc(SIZE_T size
)
434 return IMalloc_Alloc(&Malloc32
.IMalloc_iface
,size
);
437 /***********************************************************************
438 * CoTaskMemFree [OLE32.@]
440 * Frees memory allocated from the current process memory allocator.
443 * ptr [I] Memory block to free.
448 VOID WINAPI
CoTaskMemFree(LPVOID ptr
)
450 IMalloc_Free(&Malloc32
.IMalloc_iface
, ptr
);
453 /***********************************************************************
454 * CoTaskMemRealloc [OLE32.@]
456 * Allocates memory using the current process memory allocator.
459 * pvOld [I] Pointer to old memory block.
460 * size [I] Size of the new memory block.
463 * Success: Pointer to newly allocated memory block.
466 LPVOID WINAPI
CoTaskMemRealloc(LPVOID pvOld
, SIZE_T size
)
468 return IMalloc_Realloc(&Malloc32
.IMalloc_iface
, pvOld
, size
);
471 /***********************************************************************
472 * CoRegisterMallocSpy [OLE32.@]
474 * Registers an object that receives notifications on memory allocations and
478 * pMallocSpy [I] New spy object.
482 * Failure: HRESULT code.
485 * if a mallocspy is already registered, we can't do it again since
486 * only the spy knows, how to free a memory block
488 HRESULT WINAPI
CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy
)
491 HRESULT hres
= E_INVALIDARG
;
493 TRACE("%p\n", pMallocSpy
);
495 if(!pMallocSpy
) return E_INVALIDARG
;
497 EnterCriticalSection(&IMalloc32_SpyCS
);
500 hres
= CO_E_OBJISREG
;
501 else if (SUCCEEDED(IMallocSpy_QueryInterface(pMallocSpy
, &IID_IMallocSpy
, (void**)&pSpy
))) {
502 Malloc32
.pSpy
= pSpy
;
506 LeaveCriticalSection(&IMalloc32_SpyCS
);
511 /***********************************************************************
512 * CoRevokeMallocSpy [OLE32.@]
514 * Revokes a previously registered object that receives notifications on memory
515 * allocations and frees.
518 * pMallocSpy [I] New spy object.
522 * Failure: HRESULT code.
525 * we can't revoke a malloc spy as long as memory blocks allocated with
526 * the spy are active since only the spy knows how to free them
528 HRESULT WINAPI
CoRevokeMallocSpy(void)
533 EnterCriticalSection(&IMalloc32_SpyCS
);
536 hres
= CO_E_OBJNOTREG
;
537 else if (Malloc32
.SpyedAllocationsLeft
) {
538 TRACE("SpyReleasePending with %u allocations left\n", Malloc32
.SpyedAllocationsLeft
);
539 Malloc32
.SpyReleasePending
= TRUE
;
540 hres
= E_ACCESSDENIED
;
542 IMallocSpy_Release(Malloc32
.pSpy
);
543 Malloc32
.pSpy
= NULL
;
545 LeaveCriticalSection(&IMalloc32_SpyCS
);
550 /******************************************************************************
551 * IsValidInterface [OLE32.@]
553 * Determines whether a pointer is a valid interface.
556 * punk [I] Interface to be tested.
559 * TRUE, if the passed pointer is a valid interface, or FALSE otherwise.
561 BOOL WINAPI
IsValidInterface(LPUNKNOWN punk
)
564 IsBadReadPtr(punk
,4) ||
565 IsBadReadPtr(punk
->lpVtbl
,4) ||
566 IsBadReadPtr(punk
->lpVtbl
->QueryInterface
,9) ||
567 IsBadCodePtr((FARPROC
)punk
->lpVtbl
->QueryInterface
)