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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
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 extern ICOM_VTABLE(IMalloc
) VT_IMalloc32
;
52 DWORD dummy
; /* nothing, we are static */
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 int SpyedBlockTableLength
; /* size of the table*/
60 /* this is the static object instance */
61 _Malloc32 Malloc32
= {&VT_IMalloc32
, 0, NULL
, 0, 0, NULL
, 0};
63 /* with a spy active all calls from pre to post methods are threadsave */
64 static CRITICAL_SECTION IMalloc32_SpyCS
;
65 static CRITICAL_SECTION_DEBUG critsect_debug
=
67 0, 0, &IMalloc32_SpyCS
,
68 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
69 0, 0, { 0, (DWORD
)(__FILE__
": IMalloc32_SpyCS") }
71 static CRITICAL_SECTION IMalloc32_SpyCS
= { &critsect_debug
, -1, 0, 0, 0, 0 };
73 /* resize the old table */
74 static int SetSpyedBlockTableLength ( int NewLength
)
76 if (!Malloc32
.SpyedBlocks
) Malloc32
.SpyedBlocks
= (LPVOID
*)LocalAlloc(NewLength
, GMEM_ZEROINIT
);
77 else Malloc32
.SpyedBlocks
= (LPVOID
*)LocalReAlloc((HLOCAL
)Malloc32
.SpyedBlocks
, NewLength
, GMEM_ZEROINIT
);
78 Malloc32
.SpyedBlockTableLength
= NewLength
;
79 return Malloc32
.SpyedBlocks
? 1 : 0;
82 /* add a location to the table */
83 static int AddMemoryLocation(LPVOID
* pMem
)
87 /* allocate the table if not already allocated */
88 if (!Malloc32
.SpyedBlockTableLength
) {
89 if (!SetSpyedBlockTableLength(0x1000)) return 0;
92 /* find a free location */
93 Current
= Malloc32
.SpyedBlocks
;
96 if (Current
>= Malloc32
.SpyedBlocks
+ Malloc32
.SpyedBlockTableLength
) {
97 /* no more space in table, grow it */
98 if (!SetSpyedBlockTableLength( Malloc32
.SpyedBlockTableLength
+ 0x1000 )) return 0;
102 /* put the location in our table */
104 Malloc32
.SpyedAllocationsLeft
++;
105 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
109 static int RemoveMemoryLocation(LPVOID
* pMem
)
113 /* allocate the table if not already allocated */
114 if (!Malloc32
.SpyedBlockTableLength
) {
115 if (!SetSpyedBlockTableLength(0x1000)) return 0;
118 Current
= Malloc32
.SpyedBlocks
;
120 /* find the location */
121 while (*Current
!= pMem
) {
123 if (Current
>= Malloc32
.SpyedBlocks
+ Malloc32
.SpyedBlockTableLength
) return 0; /* not found */
127 Malloc32
.SpyedAllocationsLeft
--;
128 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
133 /******************************************************************************
134 * IMalloc32_QueryInterface [VTABLE]
136 static HRESULT WINAPI
IMalloc_fnQueryInterface(LPMALLOC iface
,REFIID refiid
,LPVOID
*obj
) {
138 TRACE("(%s,%p)\n",debugstr_guid(refiid
),obj
);
140 if (IsEqualIID(&IID_IUnknown
,refiid
) || IsEqualIID(&IID_IMalloc
,refiid
)) {
141 *obj
= (LPMALLOC
)&Malloc32
;
144 return E_NOINTERFACE
;
147 /******************************************************************************
148 * IMalloc32_AddRefRelease [VTABLE]
150 static ULONG WINAPI
IMalloc_fnAddRefRelease (LPMALLOC iface
) {
154 /******************************************************************************
155 * IMalloc32_Alloc [VTABLE]
157 static LPVOID WINAPI
IMalloc_fnAlloc(LPMALLOC iface
, DWORD cb
) {
164 DWORD preAllocResult
;
166 EnterCriticalSection(&IMalloc32_SpyCS
);
167 preAllocResult
= IMallocSpy_PreAlloc(Malloc32
.pSpy
, cb
);
168 if ((cb
!= 0) && (preAllocResult
== 0)) {
169 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
170 TRACE("returning null\n");
171 LeaveCriticalSection(&IMalloc32_SpyCS
);
176 addr
= HeapAlloc(GetProcessHeap(),0,cb
);
179 addr
= IMallocSpy_PostAlloc(Malloc32
.pSpy
, addr
);
180 if (addr
) AddMemoryLocation(addr
);
181 LeaveCriticalSection(&IMalloc32_SpyCS
);
184 TRACE("--(%p)\n",addr
);
188 /******************************************************************************
189 * IMalloc32_Realloc [VTABLE]
191 static LPVOID WINAPI
IMalloc_fnRealloc(LPMALLOC iface
,LPVOID pv
,DWORD cb
) {
195 TRACE("(%p,%ld)\n",pv
,cb
);
201 EnterCriticalSection(&IMalloc32_SpyCS
);
202 fSpyed
= RemoveMemoryLocation(pv
);
203 cb
= IMallocSpy_PreRealloc(Malloc32
.pSpy
, pv
, cb
, &pRealMemory
, fSpyed
);
205 /* check if can release the spy */
206 if(Malloc32
.SpyReleasePending
&& !Malloc32
.SpyedAllocationsLeft
) {
207 IMallocSpy_Release(Malloc32
.pSpy
);
208 Malloc32
.SpyReleasePending
= FALSE
;
209 Malloc32
.pSpy
= NULL
;
213 /* PreRealloc can force Realloc to fail */
214 LeaveCriticalSection(&IMalloc32_SpyCS
);
220 if (!pv
) pNewMemory
= HeapAlloc(GetProcessHeap(),0,cb
);
221 else if (cb
) pNewMemory
= HeapReAlloc(GetProcessHeap(),0,pv
,cb
);
223 HeapFree(GetProcessHeap(),0,pv
);
228 pNewMemory
= IMallocSpy_PostRealloc(Malloc32
.pSpy
, pNewMemory
, TRUE
);
229 if (pNewMemory
) AddMemoryLocation(pNewMemory
);
230 LeaveCriticalSection(&IMalloc32_SpyCS
);
233 TRACE("--(%p)\n",pNewMemory
);
237 /******************************************************************************
238 * IMalloc32_Free [VTABLE]
240 static VOID WINAPI
IMalloc_fnFree(LPMALLOC iface
,LPVOID pv
) {
247 EnterCriticalSection(&IMalloc32_SpyCS
);
248 fSpyed
= RemoveMemoryLocation(pv
);
249 pv
= IMallocSpy_PreFree(Malloc32
.pSpy
, pv
, fSpyed
);
252 HeapFree(GetProcessHeap(),0,pv
);
255 IMallocSpy_PostFree(Malloc32
.pSpy
, fSpyed
);
257 /* check if can release the spy */
258 if(Malloc32
.SpyReleasePending
&& !Malloc32
.SpyedAllocationsLeft
) {
259 IMallocSpy_Release(Malloc32
.pSpy
);
260 Malloc32
.SpyReleasePending
= FALSE
;
261 Malloc32
.pSpy
= NULL
;
264 LeaveCriticalSection(&IMalloc32_SpyCS
);
268 /******************************************************************************
269 * IMalloc32_GetSize [VTABLE]
273 * win95: size allocated (4 byte boundarys)
274 * win2k: size originally requested !!! (allocated on 8 byte boundarys)
276 static DWORD WINAPI
IMalloc_fnGetSize(LPMALLOC iface
,LPVOID pv
) {
284 EnterCriticalSection(&IMalloc32_SpyCS
);
285 pv
= IMallocSpy_PreGetSize(Malloc32
.pSpy
, pv
, fSpyed
);
288 cb
= HeapSize(GetProcessHeap(),0,pv
);
291 cb
= IMallocSpy_PostGetSize(Malloc32
.pSpy
, cb
, fSpyed
);
292 LeaveCriticalSection(&IMalloc32_SpyCS
);
298 /******************************************************************************
299 * IMalloc32_DidAlloc [VTABLE]
301 static INT WINAPI
IMalloc_fnDidAlloc(LPMALLOC iface
,LPVOID pv
) {
309 EnterCriticalSection(&IMalloc32_SpyCS
);
310 pv
= IMallocSpy_PreDidAlloc(Malloc32
.pSpy
, pv
, fSpyed
);
316 didAlloc
= IMallocSpy_PostDidAlloc(Malloc32
.pSpy
, pv
, fSpyed
, didAlloc
);
317 LeaveCriticalSection(&IMalloc32_SpyCS
);
322 /******************************************************************************
323 * IMalloc32_HeapMinimize [VTABLE]
325 static VOID WINAPI
IMalloc_fnHeapMinimize(LPMALLOC iface
) {
329 EnterCriticalSection(&IMalloc32_SpyCS
);
330 IMallocSpy_PreHeapMinimize(Malloc32
.pSpy
);
334 IMallocSpy_PostHeapMinimize(Malloc32
.pSpy
);
335 LeaveCriticalSection(&IMalloc32_SpyCS
);
339 static ICOM_VTABLE(IMalloc
) VT_IMalloc32
=
341 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
342 IMalloc_fnQueryInterface
,
343 IMalloc_fnAddRefRelease
,
344 IMalloc_fnAddRefRelease
,
350 IMalloc_fnHeapMinimize
353 /******************************************************************************
354 * IMallocSpy implementation
355 *****************************************************************************/
357 /* set the vtable later */
358 extern ICOM_VTABLE(IMallocSpy
) VT_IMallocSpy
;
361 ICOM_VFIELD(IMallocSpy
);
365 /* this is the static object instance */
366 _MallocSpy MallocSpy
= {&VT_IMallocSpy
, 0};
368 /******************************************************************************
369 * IMalloc32_QueryInterface [VTABLE]
371 static HRESULT WINAPI
IMallocSpy_fnQueryInterface(LPMALLOCSPY iface
,REFIID refiid
,LPVOID
*obj
)
374 TRACE("(%s,%p)\n",debugstr_guid(refiid
),obj
);
376 if (IsEqualIID(&IID_IUnknown
,refiid
) || IsEqualIID(&IID_IMallocSpy
,refiid
)) {
377 *obj
= (LPMALLOC
)&MallocSpy
;
380 return E_NOINTERFACE
;
383 /******************************************************************************
384 * IMalloc32_AddRef [VTABLE]
386 static ULONG WINAPI
IMallocSpy_fnAddRef (LPMALLOCSPY iface
)
389 ICOM_THIS (_MallocSpy
, iface
);
391 TRACE ("(%p)->(count=%lu)\n", This
, This
->ref
);
393 return ++(This
->ref
);
396 /******************************************************************************
397 * IMalloc32_AddRelease [VTABLE]
400 * Our MallocSpy is static. If the count reaches 0 we dump the leaks
402 static ULONG WINAPI
IMallocSpy_fnRelease (LPMALLOCSPY iface
)
405 ICOM_THIS (_MallocSpy
, iface
);
407 TRACE ("(%p)->(count=%lu)\n", This
, This
->ref
);
409 if (!--(This
->ref
)) {
410 /* our allocation list MUST be empty here */
415 static ULONG WINAPI
IMallocSpy_fnPreAlloc(LPMALLOCSPY iface
, ULONG cbRequest
)
417 ICOM_THIS (_MallocSpy
, iface
);
418 TRACE ("(%p)->(%lu)\n", This
, cbRequest
);
421 static PVOID WINAPI
IMallocSpy_fnPostAlloc(LPMALLOCSPY iface
, void* pActual
)
423 ICOM_THIS (_MallocSpy
, iface
);
424 TRACE ("(%p)->(%p)\n", This
, pActual
);
428 static PVOID WINAPI
IMallocSpy_fnPreFree(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
)
430 ICOM_THIS (_MallocSpy
, iface
);
431 TRACE ("(%p)->(%p %u)\n", This
, pRequest
, fSpyed
);
434 static void WINAPI
IMallocSpy_fnPostFree(LPMALLOCSPY iface
, BOOL fSpyed
)
436 ICOM_THIS (_MallocSpy
, iface
);
437 TRACE ("(%p)->(%u)\n", This
, fSpyed
);
440 static ULONG WINAPI
IMallocSpy_fnPreRealloc(LPMALLOCSPY iface
, void* pRequest
, ULONG cbRequest
, void** ppNewRequest
, BOOL fSpyed
)
442 ICOM_THIS (_MallocSpy
, iface
);
443 TRACE ("(%p)->(%p %lu %u)\n", This
, pRequest
, cbRequest
, fSpyed
);
444 *ppNewRequest
= pRequest
;
448 static PVOID WINAPI
IMallocSpy_fnPostRealloc(LPMALLOCSPY iface
, void* pActual
, BOOL fSpyed
)
450 ICOM_THIS (_MallocSpy
, iface
);
451 TRACE ("(%p)->(%p %u)\n", This
, pActual
, fSpyed
);
455 static PVOID WINAPI
IMallocSpy_fnPreGetSize(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
)
457 ICOM_THIS (_MallocSpy
, iface
);
458 TRACE ("(%p)->(%p %u)\n", This
, pRequest
, fSpyed
);
462 static ULONG WINAPI
IMallocSpy_fnPostGetSize(LPMALLOCSPY iface
, ULONG cbActual
, BOOL fSpyed
)
464 ICOM_THIS (_MallocSpy
, iface
);
465 TRACE ("(%p)->(%lu %u)\n", This
, cbActual
, fSpyed
);
469 static PVOID WINAPI
IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
)
471 ICOM_THIS (_MallocSpy
, iface
);
472 TRACE ("(%p)->(%p %u)\n", This
, pRequest
, fSpyed
);
476 static int WINAPI
IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
, int fActual
)
478 ICOM_THIS (_MallocSpy
, iface
);
479 TRACE ("(%p)->(%p %u %u)\n", This
, pRequest
, fSpyed
, fActual
);
483 static void WINAPI
IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface
)
485 ICOM_THIS (_MallocSpy
, iface
);
486 TRACE ("(%p)->()\n", This
);
489 static void WINAPI
IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface
)
491 ICOM_THIS (_MallocSpy
, iface
);
492 TRACE ("(%p)->()\n", This
);
495 static void MallocSpyDumpLeaks() {
496 TRACE("leaks: %lu\n", Malloc32
.SpyedAllocationsLeft
);
499 static ICOM_VTABLE(IMallocSpy
) VT_IMallocSpy
=
501 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
502 IMallocSpy_fnQueryInterface
,
504 IMallocSpy_fnRelease
,
505 IMallocSpy_fnPreAlloc
,
506 IMallocSpy_fnPostAlloc
,
507 IMallocSpy_fnPreFree
,
508 IMallocSpy_fnPostFree
,
509 IMallocSpy_fnPreRealloc
,
510 IMallocSpy_fnPostRealloc
,
511 IMallocSpy_fnPreGetSize
,
512 IMallocSpy_fnPostGetSize
,
513 IMallocSpy_fnPreDidAlloc
,
514 IMallocSpy_fnPostDidAlloc
,
515 IMallocSpy_fnPreHeapMinimize
,
516 IMallocSpy_fnPostHeapMinimize
519 /******************************************************************************
520 * CoGetMalloc [OLE32.@]
525 HRESULT WINAPI
CoGetMalloc(DWORD dwMemContext
, LPMALLOC
*lpMalloc
)
527 *lpMalloc
= (LPMALLOC
)&Malloc32
;
531 /***********************************************************************
532 * CoTaskMemAlloc [OLE32.@]
534 * pointer to newly allocated block
536 LPVOID WINAPI
CoTaskMemAlloc(ULONG size
)
538 return IMalloc_Alloc((LPMALLOC
)&Malloc32
,size
);
540 /***********************************************************************
541 * CoTaskMemFree [OLE32.@]
543 VOID WINAPI
CoTaskMemFree(LPVOID ptr
)
545 IMalloc_Free((LPMALLOC
)&Malloc32
, ptr
);
548 /***********************************************************************
549 * CoTaskMemRealloc [OLE32.@]
551 * pointer to newly allocated block
553 LPVOID WINAPI
CoTaskMemRealloc(LPVOID pvOld
, ULONG size
)
555 return IMalloc_Realloc((LPMALLOC
)&Malloc32
, pvOld
, size
);
558 /***********************************************************************
559 * CoRegisterMallocSpy [OLE32.@]
562 * if a mallocspy is already registered, we cant do it again since
563 * only the spy knows, how to free a memory block
565 HRESULT WINAPI
CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy
)
568 HRESULT hres
= E_INVALIDARG
;
572 /* HACK TO ACTIVATE OUT SPY */
573 if (pMallocSpy
== (LPVOID
)-1) pMallocSpy
=(IMallocSpy
*)&MallocSpy
;
575 if(Malloc32
.pSpy
) return CO_E_OBJISREG
;
577 EnterCriticalSection(&IMalloc32_SpyCS
);
579 if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy
, &IID_IMallocSpy
, (LPVOID
*)&pSpy
))) {
580 Malloc32
.pSpy
= pSpy
;
584 LeaveCriticalSection(&IMalloc32_SpyCS
);
589 /***********************************************************************
590 * CoRevokeMallocSpy [OLE32.@]
593 * we can't rewoke a malloc spy as long as memory blocks allocated with
594 * the spy are active since only the spy knows how to free them
596 HRESULT WINAPI
CoRevokeMallocSpy(void)
601 EnterCriticalSection(&IMalloc32_SpyCS
);
603 /* if it's our spy it's time to dump the leaks */
604 if (Malloc32
.pSpy
== (IMallocSpy
*)&MallocSpy
) {
605 MallocSpyDumpLeaks();
608 if (Malloc32
.SpyedAllocationsLeft
) {
609 TRACE("SpyReleasePending with %lu allocations left\n", Malloc32
.SpyedAllocationsLeft
);
610 Malloc32
.SpyReleasePending
= TRUE
;
611 hres
= E_ACCESSDENIED
;
613 IMallocSpy_Release(Malloc32
.pSpy
);
614 Malloc32
.pSpy
= NULL
;
616 LeaveCriticalSection(&IMalloc32_SpyCS
);
621 /******************************************************************************
622 * IsValidInterface [OLE32.@]
625 * True, if the passed pointer is a valid interface
627 BOOL WINAPI
IsValidInterface(
628 LPUNKNOWN punk
/* [in] interface to be tested */
631 IsBadReadPtr(punk
,4) ||
632 IsBadReadPtr(punk
->lpVtbl
,4) ||
633 IsBadReadPtr(punk
->lpVtbl
->QueryInterface
,9) ||
634 IsBadCodePtr((FARPROC
)punk
->lpVtbl
->QueryInterface
)