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
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(olemalloc
);
41 /******************************************************************************
42 * IMalloc32 implementation
45 * For supporting CoRegisterMallocSpy the IMalloc implementation must know if
46 * a given memory block was allocated with a spy active.
48 *****************************************************************************/
49 /* set the vtable later */
50 static const IMallocVtbl VT_IMalloc32
;
53 const IMallocVtbl
*lpVtbl
;
54 DWORD dummy
; /* nothing, we are static */
55 IMallocSpy
* pSpy
; /* the spy when active */
56 DWORD SpyedAllocationsLeft
; /* number of spyed allocations left */
57 BOOL SpyReleasePending
; /* CoRevokeMallocSpy called with spyed allocations left*/
58 LPVOID
* SpyedBlocks
; /* root of the table */
59 DWORD SpyedBlockTableLength
;/* size of the table*/
62 /* this is the static object instance */
63 static _Malloc32 Malloc32
= {&VT_IMalloc32
, 0, NULL
, 0, 0, NULL
, 0};
65 /* with a spy active all calls from pre to post methods are threadsave */
66 static CRITICAL_SECTION IMalloc32_SpyCS
;
67 static CRITICAL_SECTION_DEBUG critsect_debug
=
69 0, 0, &IMalloc32_SpyCS
,
70 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
71 0, 0, { (DWORD_PTR
)(__FILE__
": IMalloc32_SpyCS") }
73 static CRITICAL_SECTION IMalloc32_SpyCS
= { &critsect_debug
, -1, 0, 0, 0, 0 };
75 /* resize the old table */
76 static int SetSpyedBlockTableLength ( DWORD NewLength
)
78 LPVOID
*NewSpyedBlocks
;
80 if (!Malloc32
.SpyedBlocks
) NewSpyedBlocks
= LocalAlloc(LMEM_ZEROINIT
, NewLength
* sizeof(PVOID
));
81 else NewSpyedBlocks
= LocalReAlloc(Malloc32
.SpyedBlocks
, NewLength
* sizeof(PVOID
), LMEM_ZEROINIT
);
83 Malloc32
.SpyedBlocks
= NewSpyedBlocks
;
84 Malloc32
.SpyedBlockTableLength
= NewLength
;
87 return NewSpyedBlocks
!= NULL
;
90 /* add a location to the table */
91 static int AddMemoryLocation(LPVOID
* pMem
)
95 /* allocate the table if not already allocated */
96 if (!Malloc32
.SpyedBlockTableLength
) {
97 if (!SetSpyedBlockTableLength(0x1000)) return 0;
100 /* find a free location */
101 Current
= Malloc32
.SpyedBlocks
;
104 if (Current
>= Malloc32
.SpyedBlocks
+ Malloc32
.SpyedBlockTableLength
) {
105 /* no more space in table, grow it */
106 DWORD old_length
= Malloc32
.SpyedBlockTableLength
;
107 if (!SetSpyedBlockTableLength( Malloc32
.SpyedBlockTableLength
+ 0x1000 )) return 0;
108 Current
= Malloc32
.SpyedBlocks
+ old_length
;
112 /* put the location in our table */
114 Malloc32
.SpyedAllocationsLeft
++;
115 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
119 static int RemoveMemoryLocation(LPCVOID pMem
)
123 /* allocate the table if not already allocated */
124 if (!Malloc32
.SpyedBlockTableLength
) {
125 if (!SetSpyedBlockTableLength(0x1000)) return 0;
128 Current
= Malloc32
.SpyedBlocks
;
130 /* find the location */
131 while (*Current
!= pMem
) {
133 if (Current
>= Malloc32
.SpyedBlocks
+ Malloc32
.SpyedBlockTableLength
) return 0; /* not found */
137 Malloc32
.SpyedAllocationsLeft
--;
138 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
143 /******************************************************************************
144 * IMalloc32_QueryInterface [VTABLE]
146 static HRESULT WINAPI
IMalloc_fnQueryInterface(LPMALLOC iface
,REFIID refiid
,LPVOID
*obj
) {
148 TRACE("(%s,%p)\n",debugstr_guid(refiid
),obj
);
150 if (IsEqualIID(&IID_IUnknown
,refiid
) || IsEqualIID(&IID_IMalloc
,refiid
)) {
151 *obj
= (LPMALLOC
)&Malloc32
;
154 return E_NOINTERFACE
;
157 /******************************************************************************
158 * IMalloc32_AddRefRelease [VTABLE]
160 static ULONG WINAPI
IMalloc_fnAddRefRelease (LPMALLOC iface
) {
164 /******************************************************************************
165 * IMalloc32_Alloc [VTABLE]
167 static LPVOID WINAPI
IMalloc_fnAlloc(LPMALLOC iface
, DWORD cb
) {
174 DWORD preAllocResult
;
176 EnterCriticalSection(&IMalloc32_SpyCS
);
177 preAllocResult
= IMallocSpy_PreAlloc(Malloc32
.pSpy
, cb
);
178 if ((cb
!= 0) && (preAllocResult
== 0)) {
179 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
180 TRACE("returning null\n");
181 LeaveCriticalSection(&IMalloc32_SpyCS
);
186 addr
= HeapAlloc(GetProcessHeap(),0,cb
);
189 addr
= IMallocSpy_PostAlloc(Malloc32
.pSpy
, addr
);
190 if (addr
) AddMemoryLocation(addr
);
191 LeaveCriticalSection(&IMalloc32_SpyCS
);
194 TRACE("--(%p)\n",addr
);
198 /******************************************************************************
199 * IMalloc32_Realloc [VTABLE]
201 static LPVOID WINAPI
IMalloc_fnRealloc(LPMALLOC iface
,LPVOID pv
,DWORD cb
) {
205 TRACE("(%p,%d)\n",pv
,cb
);
211 EnterCriticalSection(&IMalloc32_SpyCS
);
212 fSpyed
= RemoveMemoryLocation(pv
);
213 cb
= IMallocSpy_PreRealloc(Malloc32
.pSpy
, pv
, cb
, &pRealMemory
, fSpyed
);
215 /* check if can release the spy */
216 if(Malloc32
.SpyReleasePending
&& !Malloc32
.SpyedAllocationsLeft
) {
217 IMallocSpy_Release(Malloc32
.pSpy
);
218 Malloc32
.SpyReleasePending
= FALSE
;
219 Malloc32
.pSpy
= NULL
;
223 /* PreRealloc can force Realloc to fail */
224 LeaveCriticalSection(&IMalloc32_SpyCS
);
230 if (!pv
) pNewMemory
= HeapAlloc(GetProcessHeap(),0,cb
);
231 else if (cb
) pNewMemory
= HeapReAlloc(GetProcessHeap(),0,pv
,cb
);
233 HeapFree(GetProcessHeap(),0,pv
);
238 pNewMemory
= IMallocSpy_PostRealloc(Malloc32
.pSpy
, pNewMemory
, TRUE
);
239 if (pNewMemory
) AddMemoryLocation(pNewMemory
);
240 LeaveCriticalSection(&IMalloc32_SpyCS
);
243 TRACE("--(%p)\n",pNewMemory
);
247 /******************************************************************************
248 * IMalloc32_Free [VTABLE]
250 static VOID WINAPI
IMalloc_fnFree(LPMALLOC iface
,LPVOID pv
) {
257 EnterCriticalSection(&IMalloc32_SpyCS
);
258 fSpyed
= RemoveMemoryLocation(pv
);
259 pv
= IMallocSpy_PreFree(Malloc32
.pSpy
, pv
, fSpyed
);
262 HeapFree(GetProcessHeap(),0,pv
);
265 IMallocSpy_PostFree(Malloc32
.pSpy
, fSpyed
);
267 /* check if can release the spy */
268 if(Malloc32
.SpyReleasePending
&& !Malloc32
.SpyedAllocationsLeft
) {
269 IMallocSpy_Release(Malloc32
.pSpy
);
270 Malloc32
.SpyReleasePending
= FALSE
;
271 Malloc32
.pSpy
= NULL
;
274 LeaveCriticalSection(&IMalloc32_SpyCS
);
278 /******************************************************************************
279 * IMalloc32_GetSize [VTABLE]
283 * win95: size allocated (4 byte boundarys)
284 * win2k: size originally requested !!! (allocated on 8 byte boundarys)
286 static DWORD WINAPI
IMalloc_fnGetSize(LPMALLOC iface
,LPVOID pv
) {
294 EnterCriticalSection(&IMalloc32_SpyCS
);
295 pv
= IMallocSpy_PreGetSize(Malloc32
.pSpy
, pv
, fSpyed
);
298 cb
= HeapSize(GetProcessHeap(),0,pv
);
301 cb
= IMallocSpy_PostGetSize(Malloc32
.pSpy
, cb
, fSpyed
);
302 LeaveCriticalSection(&IMalloc32_SpyCS
);
308 /******************************************************************************
309 * IMalloc32_DidAlloc [VTABLE]
311 static INT WINAPI
IMalloc_fnDidAlloc(LPMALLOC iface
,LPVOID pv
) {
319 EnterCriticalSection(&IMalloc32_SpyCS
);
320 pv
= IMallocSpy_PreDidAlloc(Malloc32
.pSpy
, pv
, fSpyed
);
326 didAlloc
= IMallocSpy_PostDidAlloc(Malloc32
.pSpy
, pv
, fSpyed
, didAlloc
);
327 LeaveCriticalSection(&IMalloc32_SpyCS
);
332 /******************************************************************************
333 * IMalloc32_HeapMinimize [VTABLE]
335 static VOID WINAPI
IMalloc_fnHeapMinimize(LPMALLOC iface
) {
339 EnterCriticalSection(&IMalloc32_SpyCS
);
340 IMallocSpy_PreHeapMinimize(Malloc32
.pSpy
);
344 IMallocSpy_PostHeapMinimize(Malloc32
.pSpy
);
345 LeaveCriticalSection(&IMalloc32_SpyCS
);
349 static const IMallocVtbl VT_IMalloc32
=
351 IMalloc_fnQueryInterface
,
352 IMalloc_fnAddRefRelease
,
353 IMalloc_fnAddRefRelease
,
359 IMalloc_fnHeapMinimize
362 /******************************************************************************
363 * IMallocSpy implementation
364 *****************************************************************************/
366 /* set the vtable later */
367 static const IMallocSpyVtbl VT_IMallocSpy
;
370 const IMallocSpyVtbl
*lpVtbl
;
374 /* this is the static object instance */
375 static _MallocSpy MallocSpy
= {&VT_IMallocSpy
, 0};
377 /******************************************************************************
378 * IMalloc32_QueryInterface [VTABLE]
380 static HRESULT WINAPI
IMallocSpy_fnQueryInterface(LPMALLOCSPY iface
,REFIID refiid
,LPVOID
*obj
)
383 TRACE("(%s,%p)\n",debugstr_guid(refiid
),obj
);
385 if (IsEqualIID(&IID_IUnknown
,refiid
) || IsEqualIID(&IID_IMallocSpy
,refiid
)) {
386 *obj
= (LPMALLOC
)&MallocSpy
;
389 return E_NOINTERFACE
;
392 /******************************************************************************
393 * IMalloc32_AddRef [VTABLE]
395 static ULONG WINAPI
IMallocSpy_fnAddRef (LPMALLOCSPY iface
)
398 _MallocSpy
*This
= (_MallocSpy
*)iface
;
399 ULONG ref
= InterlockedIncrement(&This
->ref
);
401 TRACE ("(%p)->(count=%u)\n", This
, ref
- 1);
406 /******************************************************************************
407 * IMalloc32_AddRelease [VTABLE]
410 * Our MallocSpy is static. If the count reaches 0 we dump the leaks
412 static ULONG WINAPI
IMallocSpy_fnRelease (LPMALLOCSPY iface
)
415 _MallocSpy
*This
= (_MallocSpy
*)iface
;
416 ULONG ref
= InterlockedDecrement(&This
->ref
);
418 TRACE ("(%p)->(count=%u)\n", This
, ref
+ 1);
421 /* our allocation list MUST be empty here */
426 static ULONG WINAPI
IMallocSpy_fnPreAlloc(LPMALLOCSPY iface
, ULONG cbRequest
)
428 _MallocSpy
*This
= (_MallocSpy
*)iface
;
429 TRACE ("(%p)->(%u)\n", This
, cbRequest
);
432 static PVOID WINAPI
IMallocSpy_fnPostAlloc(LPMALLOCSPY iface
, void* pActual
)
434 _MallocSpy
*This
= (_MallocSpy
*)iface
;
435 TRACE ("(%p)->(%p)\n", This
, pActual
);
439 static PVOID WINAPI
IMallocSpy_fnPreFree(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
)
441 _MallocSpy
*This
= (_MallocSpy
*)iface
;
442 TRACE ("(%p)->(%p %u)\n", This
, pRequest
, fSpyed
);
445 static void WINAPI
IMallocSpy_fnPostFree(LPMALLOCSPY iface
, BOOL fSpyed
)
447 _MallocSpy
*This
= (_MallocSpy
*)iface
;
448 TRACE ("(%p)->(%u)\n", This
, fSpyed
);
451 static ULONG WINAPI
IMallocSpy_fnPreRealloc(LPMALLOCSPY iface
, void* pRequest
, ULONG cbRequest
, void** ppNewRequest
, BOOL fSpyed
)
453 _MallocSpy
*This
= (_MallocSpy
*)iface
;
454 TRACE ("(%p)->(%p %u %u)\n", This
, pRequest
, cbRequest
, fSpyed
);
455 *ppNewRequest
= pRequest
;
459 static PVOID WINAPI
IMallocSpy_fnPostRealloc(LPMALLOCSPY iface
, void* pActual
, BOOL fSpyed
)
461 _MallocSpy
*This
= (_MallocSpy
*)iface
;
462 TRACE ("(%p)->(%p %u)\n", This
, pActual
, fSpyed
);
466 static PVOID WINAPI
IMallocSpy_fnPreGetSize(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
)
468 _MallocSpy
*This
= (_MallocSpy
*)iface
;
469 TRACE ("(%p)->(%p %u)\n", This
, pRequest
, fSpyed
);
473 static ULONG WINAPI
IMallocSpy_fnPostGetSize(LPMALLOCSPY iface
, ULONG cbActual
, BOOL fSpyed
)
475 _MallocSpy
*This
= (_MallocSpy
*)iface
;
476 TRACE ("(%p)->(%u %u)\n", This
, cbActual
, fSpyed
);
480 static PVOID WINAPI
IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
)
482 _MallocSpy
*This
= (_MallocSpy
*)iface
;
483 TRACE ("(%p)->(%p %u)\n", This
, pRequest
, fSpyed
);
487 static int WINAPI
IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
, int fActual
)
489 _MallocSpy
*This
= (_MallocSpy
*)iface
;
490 TRACE ("(%p)->(%p %u %u)\n", This
, pRequest
, fSpyed
, fActual
);
494 static void WINAPI
IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface
)
496 _MallocSpy
*This
= (_MallocSpy
*)iface
;
497 TRACE ("(%p)->()\n", This
);
500 static void WINAPI
IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface
)
502 _MallocSpy
*This
= (_MallocSpy
*)iface
;
503 TRACE ("(%p)->()\n", This
);
506 static void MallocSpyDumpLeaks(void) {
507 TRACE("leaks: %u\n", Malloc32
.SpyedAllocationsLeft
);
510 static const IMallocSpyVtbl VT_IMallocSpy
=
512 IMallocSpy_fnQueryInterface
,
514 IMallocSpy_fnRelease
,
515 IMallocSpy_fnPreAlloc
,
516 IMallocSpy_fnPostAlloc
,
517 IMallocSpy_fnPreFree
,
518 IMallocSpy_fnPostFree
,
519 IMallocSpy_fnPreRealloc
,
520 IMallocSpy_fnPostRealloc
,
521 IMallocSpy_fnPreGetSize
,
522 IMallocSpy_fnPostGetSize
,
523 IMallocSpy_fnPreDidAlloc
,
524 IMallocSpy_fnPostDidAlloc
,
525 IMallocSpy_fnPreHeapMinimize
,
526 IMallocSpy_fnPostHeapMinimize
529 /******************************************************************************
530 * CoGetMalloc [OLE32.@]
532 * Retrieves the current IMalloc interface for the process.
536 * lpMalloc [O] Address where memory allocator object will be stored.
540 * Failure: HRESULT code.
542 HRESULT WINAPI
CoGetMalloc(DWORD dwMemContext
, LPMALLOC
*lpMalloc
)
544 *lpMalloc
= (LPMALLOC
)&Malloc32
;
548 /***********************************************************************
549 * CoTaskMemAlloc [OLE32.@]
551 * Allocates memory using the current process memory allocator.
554 * size [I] Size of the memory block to allocate.
557 * Success: Pointer to newly allocated memory block.
560 LPVOID WINAPI
CoTaskMemAlloc(ULONG size
)
562 return IMalloc_Alloc((LPMALLOC
)&Malloc32
,size
);
565 /***********************************************************************
566 * CoTaskMemFree [OLE32.@]
568 * Frees memory allocated from the current process memory allocator.
571 * ptr [I] Memory block to free.
576 VOID WINAPI
CoTaskMemFree(LPVOID ptr
)
578 IMalloc_Free((LPMALLOC
)&Malloc32
, ptr
);
581 /***********************************************************************
582 * CoTaskMemRealloc [OLE32.@]
584 * Allocates memory using the current process memory allocator.
587 * pvOld [I] Pointer to old memory block.
588 * size [I] Size of the new memory block.
591 * Success: Pointer to newly allocated memory block.
594 LPVOID WINAPI
CoTaskMemRealloc(LPVOID pvOld
, ULONG size
)
596 return IMalloc_Realloc((LPMALLOC
)&Malloc32
, pvOld
, size
);
599 /***********************************************************************
600 * CoRegisterMallocSpy [OLE32.@]
602 * Registers an object that receives notifications on memory allocations and
606 * pMallocSpy [I] New spy object.
610 * Failure: HRESULT code.
613 * if a mallocspy is already registered, we can't do it again since
614 * only the spy knows, how to free a memory block
616 HRESULT WINAPI
CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy
)
619 HRESULT hres
= E_INVALIDARG
;
623 /* HACK TO ACTIVATE OUT SPY */
624 if (pMallocSpy
== (LPVOID
)-1) pMallocSpy
=(IMallocSpy
*)&MallocSpy
;
626 if(Malloc32
.pSpy
) return CO_E_OBJISREG
;
628 EnterCriticalSection(&IMalloc32_SpyCS
);
630 if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy
, &IID_IMallocSpy
, (LPVOID
*)&pSpy
))) {
631 Malloc32
.pSpy
= pSpy
;
635 LeaveCriticalSection(&IMalloc32_SpyCS
);
640 /***********************************************************************
641 * CoRevokeMallocSpy [OLE32.@]
643 * Revokes a previously registered object that receives notifications on memory
644 * allocations and frees.
647 * pMallocSpy [I] New spy object.
651 * Failure: HRESULT code.
654 * we can't revoke a malloc spy as long as memory blocks allocated with
655 * the spy are active since only the spy knows how to free them
657 HRESULT WINAPI
CoRevokeMallocSpy(void)
662 EnterCriticalSection(&IMalloc32_SpyCS
);
664 /* if it's our spy it's time to dump the leaks */
665 if (Malloc32
.pSpy
== (IMallocSpy
*)&MallocSpy
) {
666 MallocSpyDumpLeaks();
669 if (Malloc32
.SpyedAllocationsLeft
) {
670 TRACE("SpyReleasePending with %u allocations left\n", Malloc32
.SpyedAllocationsLeft
);
671 Malloc32
.SpyReleasePending
= TRUE
;
672 hres
= E_ACCESSDENIED
;
674 IMallocSpy_Release(Malloc32
.pSpy
);
675 Malloc32
.pSpy
= NULL
;
677 LeaveCriticalSection(&IMalloc32_SpyCS
);
682 /******************************************************************************
683 * IsValidInterface [OLE32.@]
685 * Determines whether a pointer is a valid interface.
688 * punk [I] Interface to be tested.
691 * TRUE, if the passed pointer is a valid interface, or FALSE otherwise.
693 BOOL WINAPI
IsValidInterface(LPUNKNOWN punk
)
696 IsBadReadPtr(punk
,4) ||
697 IsBadReadPtr(punk
->lpVtbl
,4) ||
698 IsBadReadPtr(punk
->lpVtbl
->QueryInterface
,9) ||
699 IsBadCodePtr((FARPROC
)punk
->lpVtbl
->QueryInterface
)