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 int 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 ( int 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 if (!SetSpyedBlockTableLength( Malloc32
.SpyedBlockTableLength
+ 0x1000 )) return 0;
110 /* put the location in our table */
112 Malloc32
.SpyedAllocationsLeft
++;
113 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
117 static int RemoveMemoryLocation(LPVOID
* pMem
)
121 /* allocate the table if not already allocated */
122 if (!Malloc32
.SpyedBlockTableLength
) {
123 if (!SetSpyedBlockTableLength(0x1000)) return 0;
126 Current
= Malloc32
.SpyedBlocks
;
128 /* find the location */
129 while (*Current
!= pMem
) {
131 if (Current
>= Malloc32
.SpyedBlocks
+ Malloc32
.SpyedBlockTableLength
) return 0; /* not found */
135 Malloc32
.SpyedAllocationsLeft
--;
136 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
141 /******************************************************************************
142 * IMalloc32_QueryInterface [VTABLE]
144 static HRESULT WINAPI
IMalloc_fnQueryInterface(LPMALLOC iface
,REFIID refiid
,LPVOID
*obj
) {
146 TRACE("(%s,%p)\n",debugstr_guid(refiid
),obj
);
148 if (IsEqualIID(&IID_IUnknown
,refiid
) || IsEqualIID(&IID_IMalloc
,refiid
)) {
149 *obj
= (LPMALLOC
)&Malloc32
;
152 return E_NOINTERFACE
;
155 /******************************************************************************
156 * IMalloc32_AddRefRelease [VTABLE]
158 static ULONG WINAPI
IMalloc_fnAddRefRelease (LPMALLOC iface
) {
162 /******************************************************************************
163 * IMalloc32_Alloc [VTABLE]
165 static LPVOID WINAPI
IMalloc_fnAlloc(LPMALLOC iface
, DWORD cb
) {
172 DWORD preAllocResult
;
174 EnterCriticalSection(&IMalloc32_SpyCS
);
175 preAllocResult
= IMallocSpy_PreAlloc(Malloc32
.pSpy
, cb
);
176 if ((cb
!= 0) && (preAllocResult
== 0)) {
177 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
178 TRACE("returning null\n");
179 LeaveCriticalSection(&IMalloc32_SpyCS
);
184 addr
= HeapAlloc(GetProcessHeap(),0,cb
);
187 addr
= IMallocSpy_PostAlloc(Malloc32
.pSpy
, addr
);
188 if (addr
) AddMemoryLocation(addr
);
189 LeaveCriticalSection(&IMalloc32_SpyCS
);
192 TRACE("--(%p)\n",addr
);
196 /******************************************************************************
197 * IMalloc32_Realloc [VTABLE]
199 static LPVOID WINAPI
IMalloc_fnRealloc(LPMALLOC iface
,LPVOID pv
,DWORD cb
) {
203 TRACE("(%p,%d)\n",pv
,cb
);
209 EnterCriticalSection(&IMalloc32_SpyCS
);
210 fSpyed
= RemoveMemoryLocation(pv
);
211 cb
= IMallocSpy_PreRealloc(Malloc32
.pSpy
, pv
, cb
, &pRealMemory
, fSpyed
);
213 /* check if can release the spy */
214 if(Malloc32
.SpyReleasePending
&& !Malloc32
.SpyedAllocationsLeft
) {
215 IMallocSpy_Release(Malloc32
.pSpy
);
216 Malloc32
.SpyReleasePending
= FALSE
;
217 Malloc32
.pSpy
= NULL
;
221 /* PreRealloc can force Realloc to fail */
222 LeaveCriticalSection(&IMalloc32_SpyCS
);
228 if (!pv
) pNewMemory
= HeapAlloc(GetProcessHeap(),0,cb
);
229 else if (cb
) pNewMemory
= HeapReAlloc(GetProcessHeap(),0,pv
,cb
);
231 HeapFree(GetProcessHeap(),0,pv
);
236 pNewMemory
= IMallocSpy_PostRealloc(Malloc32
.pSpy
, pNewMemory
, TRUE
);
237 if (pNewMemory
) AddMemoryLocation(pNewMemory
);
238 LeaveCriticalSection(&IMalloc32_SpyCS
);
241 TRACE("--(%p)\n",pNewMemory
);
245 /******************************************************************************
246 * IMalloc32_Free [VTABLE]
248 static VOID WINAPI
IMalloc_fnFree(LPMALLOC iface
,LPVOID pv
) {
255 EnterCriticalSection(&IMalloc32_SpyCS
);
256 fSpyed
= RemoveMemoryLocation(pv
);
257 pv
= IMallocSpy_PreFree(Malloc32
.pSpy
, pv
, fSpyed
);
260 HeapFree(GetProcessHeap(),0,pv
);
263 IMallocSpy_PostFree(Malloc32
.pSpy
, fSpyed
);
265 /* check if can release the spy */
266 if(Malloc32
.SpyReleasePending
&& !Malloc32
.SpyedAllocationsLeft
) {
267 IMallocSpy_Release(Malloc32
.pSpy
);
268 Malloc32
.SpyReleasePending
= FALSE
;
269 Malloc32
.pSpy
= NULL
;
272 LeaveCriticalSection(&IMalloc32_SpyCS
);
276 /******************************************************************************
277 * IMalloc32_GetSize [VTABLE]
281 * win95: size allocated (4 byte boundarys)
282 * win2k: size originally requested !!! (allocated on 8 byte boundarys)
284 static DWORD WINAPI
IMalloc_fnGetSize(LPMALLOC iface
,LPVOID pv
) {
292 EnterCriticalSection(&IMalloc32_SpyCS
);
293 pv
= IMallocSpy_PreGetSize(Malloc32
.pSpy
, pv
, fSpyed
);
296 cb
= HeapSize(GetProcessHeap(),0,pv
);
299 cb
= IMallocSpy_PostGetSize(Malloc32
.pSpy
, cb
, fSpyed
);
300 LeaveCriticalSection(&IMalloc32_SpyCS
);
306 /******************************************************************************
307 * IMalloc32_DidAlloc [VTABLE]
309 static INT WINAPI
IMalloc_fnDidAlloc(LPMALLOC iface
,LPVOID pv
) {
317 EnterCriticalSection(&IMalloc32_SpyCS
);
318 pv
= IMallocSpy_PreDidAlloc(Malloc32
.pSpy
, pv
, fSpyed
);
324 didAlloc
= IMallocSpy_PostDidAlloc(Malloc32
.pSpy
, pv
, fSpyed
, didAlloc
);
325 LeaveCriticalSection(&IMalloc32_SpyCS
);
330 /******************************************************************************
331 * IMalloc32_HeapMinimize [VTABLE]
333 static VOID WINAPI
IMalloc_fnHeapMinimize(LPMALLOC iface
) {
337 EnterCriticalSection(&IMalloc32_SpyCS
);
338 IMallocSpy_PreHeapMinimize(Malloc32
.pSpy
);
342 IMallocSpy_PostHeapMinimize(Malloc32
.pSpy
);
343 LeaveCriticalSection(&IMalloc32_SpyCS
);
347 static const IMallocVtbl VT_IMalloc32
=
349 IMalloc_fnQueryInterface
,
350 IMalloc_fnAddRefRelease
,
351 IMalloc_fnAddRefRelease
,
357 IMalloc_fnHeapMinimize
360 /******************************************************************************
361 * IMallocSpy implementation
362 *****************************************************************************/
364 /* set the vtable later */
365 static const IMallocSpyVtbl VT_IMallocSpy
;
368 const IMallocSpyVtbl
*lpVtbl
;
372 /* this is the static object instance */
373 static _MallocSpy MallocSpy
= {&VT_IMallocSpy
, 0};
375 /******************************************************************************
376 * IMalloc32_QueryInterface [VTABLE]
378 static HRESULT WINAPI
IMallocSpy_fnQueryInterface(LPMALLOCSPY iface
,REFIID refiid
,LPVOID
*obj
)
381 TRACE("(%s,%p)\n",debugstr_guid(refiid
),obj
);
383 if (IsEqualIID(&IID_IUnknown
,refiid
) || IsEqualIID(&IID_IMallocSpy
,refiid
)) {
384 *obj
= (LPMALLOC
)&MallocSpy
;
387 return E_NOINTERFACE
;
390 /******************************************************************************
391 * IMalloc32_AddRef [VTABLE]
393 static ULONG WINAPI
IMallocSpy_fnAddRef (LPMALLOCSPY iface
)
396 _MallocSpy
*This
= (_MallocSpy
*)iface
;
397 ULONG ref
= InterlockedIncrement(&This
->ref
);
399 TRACE ("(%p)->(count=%u)\n", This
, ref
- 1);
404 /******************************************************************************
405 * IMalloc32_AddRelease [VTABLE]
408 * Our MallocSpy is static. If the count reaches 0 we dump the leaks
410 static ULONG WINAPI
IMallocSpy_fnRelease (LPMALLOCSPY iface
)
413 _MallocSpy
*This
= (_MallocSpy
*)iface
;
414 ULONG ref
= InterlockedDecrement(&This
->ref
);
416 TRACE ("(%p)->(count=%u)\n", This
, ref
+ 1);
419 /* our allocation list MUST be empty here */
424 static ULONG WINAPI
IMallocSpy_fnPreAlloc(LPMALLOCSPY iface
, ULONG cbRequest
)
426 _MallocSpy
*This
= (_MallocSpy
*)iface
;
427 TRACE ("(%p)->(%u)\n", This
, cbRequest
);
430 static PVOID WINAPI
IMallocSpy_fnPostAlloc(LPMALLOCSPY iface
, void* pActual
)
432 _MallocSpy
*This
= (_MallocSpy
*)iface
;
433 TRACE ("(%p)->(%p)\n", This
, pActual
);
437 static PVOID WINAPI
IMallocSpy_fnPreFree(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
)
439 _MallocSpy
*This
= (_MallocSpy
*)iface
;
440 TRACE ("(%p)->(%p %u)\n", This
, pRequest
, fSpyed
);
443 static void WINAPI
IMallocSpy_fnPostFree(LPMALLOCSPY iface
, BOOL fSpyed
)
445 _MallocSpy
*This
= (_MallocSpy
*)iface
;
446 TRACE ("(%p)->(%u)\n", This
, fSpyed
);
449 static ULONG WINAPI
IMallocSpy_fnPreRealloc(LPMALLOCSPY iface
, void* pRequest
, ULONG cbRequest
, void** ppNewRequest
, BOOL fSpyed
)
451 _MallocSpy
*This
= (_MallocSpy
*)iface
;
452 TRACE ("(%p)->(%p %u %u)\n", This
, pRequest
, cbRequest
, fSpyed
);
453 *ppNewRequest
= pRequest
;
457 static PVOID WINAPI
IMallocSpy_fnPostRealloc(LPMALLOCSPY iface
, void* pActual
, BOOL fSpyed
)
459 _MallocSpy
*This
= (_MallocSpy
*)iface
;
460 TRACE ("(%p)->(%p %u)\n", This
, pActual
, fSpyed
);
464 static PVOID WINAPI
IMallocSpy_fnPreGetSize(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
)
466 _MallocSpy
*This
= (_MallocSpy
*)iface
;
467 TRACE ("(%p)->(%p %u)\n", This
, pRequest
, fSpyed
);
471 static ULONG WINAPI
IMallocSpy_fnPostGetSize(LPMALLOCSPY iface
, ULONG cbActual
, BOOL fSpyed
)
473 _MallocSpy
*This
= (_MallocSpy
*)iface
;
474 TRACE ("(%p)->(%u %u)\n", This
, cbActual
, fSpyed
);
478 static PVOID WINAPI
IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
)
480 _MallocSpy
*This
= (_MallocSpy
*)iface
;
481 TRACE ("(%p)->(%p %u)\n", This
, pRequest
, fSpyed
);
485 static int WINAPI
IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
, int fActual
)
487 _MallocSpy
*This
= (_MallocSpy
*)iface
;
488 TRACE ("(%p)->(%p %u %u)\n", This
, pRequest
, fSpyed
, fActual
);
492 static void WINAPI
IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface
)
494 _MallocSpy
*This
= (_MallocSpy
*)iface
;
495 TRACE ("(%p)->()\n", This
);
498 static void WINAPI
IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface
)
500 _MallocSpy
*This
= (_MallocSpy
*)iface
;
501 TRACE ("(%p)->()\n", This
);
504 static void MallocSpyDumpLeaks(void) {
505 TRACE("leaks: %u\n", Malloc32
.SpyedAllocationsLeft
);
508 static const IMallocSpyVtbl VT_IMallocSpy
=
510 IMallocSpy_fnQueryInterface
,
512 IMallocSpy_fnRelease
,
513 IMallocSpy_fnPreAlloc
,
514 IMallocSpy_fnPostAlloc
,
515 IMallocSpy_fnPreFree
,
516 IMallocSpy_fnPostFree
,
517 IMallocSpy_fnPreRealloc
,
518 IMallocSpy_fnPostRealloc
,
519 IMallocSpy_fnPreGetSize
,
520 IMallocSpy_fnPostGetSize
,
521 IMallocSpy_fnPreDidAlloc
,
522 IMallocSpy_fnPostDidAlloc
,
523 IMallocSpy_fnPreHeapMinimize
,
524 IMallocSpy_fnPostHeapMinimize
527 /******************************************************************************
528 * CoGetMalloc [OLE32.@]
530 * Retrieves the current IMalloc interface for the process.
534 * lpMalloc [O] Address where memory allocator object will be stored.
538 * Failure: HRESULT code.
540 HRESULT WINAPI
CoGetMalloc(DWORD dwMemContext
, LPMALLOC
*lpMalloc
)
542 *lpMalloc
= (LPMALLOC
)&Malloc32
;
546 /***********************************************************************
547 * CoTaskMemAlloc [OLE32.@]
549 * Allocates memory using the current process memory allocator.
552 * size [I] Size of the memory block to allocate.
555 * Success: Pointer to newly allocated memory block.
558 LPVOID WINAPI
CoTaskMemAlloc(ULONG size
)
560 return IMalloc_Alloc((LPMALLOC
)&Malloc32
,size
);
563 /***********************************************************************
564 * CoTaskMemFree [OLE32.@]
566 * Frees memory allocated from the current process memory allocator.
569 * ptr [I] Memory block to free.
574 VOID WINAPI
CoTaskMemFree(LPVOID ptr
)
576 IMalloc_Free((LPMALLOC
)&Malloc32
, ptr
);
579 /***********************************************************************
580 * CoTaskMemRealloc [OLE32.@]
582 * Allocates memory using the current process memory allocator.
585 * pvOld [I] Pointer to old memory block.
586 * size [I] Size of the new memory block.
589 * Success: Pointer to newly allocated memory block.
592 LPVOID WINAPI
CoTaskMemRealloc(LPVOID pvOld
, ULONG size
)
594 return IMalloc_Realloc((LPMALLOC
)&Malloc32
, pvOld
, size
);
597 /***********************************************************************
598 * CoRegisterMallocSpy [OLE32.@]
600 * Registers an object that receives notifications on memory allocations and
604 * pMallocSpy [I] New spy object.
608 * Failure: HRESULT code.
611 * if a mallocspy is already registered, we can't do it again since
612 * only the spy knows, how to free a memory block
614 HRESULT WINAPI
CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy
)
617 HRESULT hres
= E_INVALIDARG
;
621 /* HACK TO ACTIVATE OUT SPY */
622 if (pMallocSpy
== (LPVOID
)-1) pMallocSpy
=(IMallocSpy
*)&MallocSpy
;
624 if(Malloc32
.pSpy
) return CO_E_OBJISREG
;
626 EnterCriticalSection(&IMalloc32_SpyCS
);
628 if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy
, &IID_IMallocSpy
, (LPVOID
*)&pSpy
))) {
629 Malloc32
.pSpy
= pSpy
;
633 LeaveCriticalSection(&IMalloc32_SpyCS
);
638 /***********************************************************************
639 * CoRevokeMallocSpy [OLE32.@]
641 * Revokes a previousl registered object that receives notifications on memory
642 * allocations and frees.
645 * pMallocSpy [I] New spy object.
649 * Failure: HRESULT code.
652 * we can't revoke a malloc spy as long as memory blocks allocated with
653 * the spy are active since only the spy knows how to free them
655 HRESULT WINAPI
CoRevokeMallocSpy(void)
660 EnterCriticalSection(&IMalloc32_SpyCS
);
662 /* if it's our spy it's time to dump the leaks */
663 if (Malloc32
.pSpy
== (IMallocSpy
*)&MallocSpy
) {
664 MallocSpyDumpLeaks();
667 if (Malloc32
.SpyedAllocationsLeft
) {
668 TRACE("SpyReleasePending with %u allocations left\n", Malloc32
.SpyedAllocationsLeft
);
669 Malloc32
.SpyReleasePending
= TRUE
;
670 hres
= E_ACCESSDENIED
;
672 IMallocSpy_Release(Malloc32
.pSpy
);
673 Malloc32
.pSpy
= NULL
;
675 LeaveCriticalSection(&IMalloc32_SpyCS
);
680 /******************************************************************************
681 * IsValidInterface [OLE32.@]
683 * Determines whether a pointer is a valid interface.
686 * punk [I] Interface to be tested.
689 * TRUE, if the passed pointer is a valid interface, or FALSE otherwise.
691 BOOL WINAPI
IsValidInterface(LPUNKNOWN punk
)
694 IsBadReadPtr(punk
,4) ||
695 IsBadReadPtr(punk
->lpVtbl
,4) ||
696 IsBadReadPtr(punk
->lpVtbl
->QueryInterface
,9) ||
697 IsBadCodePtr((FARPROC
)punk
->lpVtbl
->QueryInterface
)