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
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
37 /******************************************************************************
38 * IMalloc32 implementation
41 * For supporting CoRegisterMallocSpy the IMalloc implementation must know if
42 * a given memory block was allocated with a spy active.
44 *****************************************************************************/
45 /* set the vtable later */
46 extern ICOM_VTABLE(IMalloc
) VT_IMalloc32
;
50 DWORD dummy
; /* nothing, we are static */
51 IMallocSpy
* pSpy
; /* the spy when active */
52 DWORD SpyedAllocationsLeft
; /* number of spyed allocations left */
53 BOOL SpyReleasePending
; /* CoRevokeMallocSpy called with spyed allocations left*/
54 LPVOID
* SpyedBlocks
; /* root of the table */
55 int SpyedBlockTableLength
; /* size of the table*/
58 /* this is the static object instance */
59 _Malloc32 Malloc32
= {&VT_IMalloc32
, 0, NULL
, 0, 0, NULL
, 0};
61 /* with a spy active all calls from pre to post methods are threadsave */
62 static CRITICAL_SECTION IMalloc32_SpyCS
;
63 static CRITICAL_SECTION_DEBUG critsect_debug
=
65 0, 0, &IMalloc32_SpyCS
,
66 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
67 0, 0, { 0, (DWORD
)(__FILE__
": IMalloc32_SpyCS") }
69 static CRITICAL_SECTION IMalloc32_SpyCS
= { &critsect_debug
, -1, 0, 0, 0, 0 };
71 /* resize the old table */
72 static int SetSpyedBlockTableLength ( int NewLength
)
74 Malloc32
.SpyedBlocks
= (LPVOID
*)LocalReAlloc((HLOCAL
)Malloc32
.SpyedBlocks
, NewLength
, GMEM_ZEROINIT
);
75 Malloc32
.SpyedBlockTableLength
= NewLength
;
76 return Malloc32
.SpyedBlocks
? 1 : 0;
79 /* add a location to the table */
80 static int AddMemoryLocation(LPVOID
* pMem
)
84 /* allocate the table if not already allocated */
85 if (!Malloc32
.SpyedBlockTableLength
) {
86 if (!SetSpyedBlockTableLength(0x1000)) return 0;
89 /* find a free location */
90 Current
= Malloc32
.SpyedBlocks
;
93 if (Current
>= Malloc32
.SpyedBlocks
+ Malloc32
.SpyedBlockTableLength
) {
94 /* no more space in table, grow it */
95 if (!SetSpyedBlockTableLength( Malloc32
.SpyedBlockTableLength
+ 0x1000 )) return 0;
99 /* put the location in our table */
101 Malloc32
.SpyedAllocationsLeft
++;
102 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
106 static int RemoveMemoryLocation(LPVOID
* pMem
)
108 LPVOID
* Current
= Malloc32
.SpyedBlocks
;
110 /* find the location */
111 while (*Current
!= pMem
) {
113 if (Current
>= Malloc32
.SpyedBlocks
+ Malloc32
.SpyedBlockTableLength
) return 0; /* not found */
117 Malloc32
.SpyedAllocationsLeft
--;
118 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
123 /******************************************************************************
124 * IMalloc32_QueryInterface [VTABLE]
126 static HRESULT WINAPI
IMalloc_fnQueryInterface(LPMALLOC iface
,REFIID refiid
,LPVOID
*obj
) {
128 TRACE("(%s,%p)\n",debugstr_guid(refiid
),obj
);
130 if (IsEqualIID(&IID_IUnknown
,refiid
) || IsEqualIID(&IID_IMalloc
,refiid
)) {
131 *obj
= (LPMALLOC
)&Malloc32
;
134 return E_NOINTERFACE
;
137 /******************************************************************************
138 * IMalloc32_AddRefRelease [VTABLE]
140 static ULONG WINAPI
IMalloc_fnAddRefRelease (LPMALLOC iface
) {
144 /******************************************************************************
145 * IMalloc32_Alloc [VTABLE]
147 static LPVOID WINAPI
IMalloc_fnAlloc(LPMALLOC iface
, DWORD cb
) {
154 DWORD preAllocResult
;
156 EnterCriticalSection(&IMalloc32_SpyCS
);
157 preAllocResult
= IMallocSpy_PreAlloc(Malloc32
.pSpy
, cb
);
158 if ((cb
!= 0) && (preAllocResult
== 0)) {
159 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
160 TRACE("returning null\n");
161 LeaveCriticalSection(&IMalloc32_SpyCS
);
166 addr
= HeapAlloc(GetProcessHeap(),0,cb
);
169 addr
= IMallocSpy_PostAlloc(Malloc32
.pSpy
, addr
);
170 if (addr
) AddMemoryLocation(addr
);
171 LeaveCriticalSection(&IMalloc32_SpyCS
);
174 TRACE("--(%p)\n",addr
);
178 /******************************************************************************
179 * IMalloc32_Realloc [VTABLE]
181 static LPVOID WINAPI
IMalloc_fnRealloc(LPMALLOC iface
,LPVOID pv
,DWORD cb
) {
185 TRACE("(%p,%ld)\n",pv
,cb
);
191 EnterCriticalSection(&IMalloc32_SpyCS
);
192 fSpyed
= RemoveMemoryLocation(pv
);
193 cb
= IMallocSpy_PreRealloc(Malloc32
.pSpy
, pv
, cb
, &pRealMemory
, fSpyed
);
195 /* check if can release the spy */
196 if(Malloc32
.SpyReleasePending
&& !Malloc32
.SpyedAllocationsLeft
) {
197 IMallocSpy_Release(Malloc32
.pSpy
);
198 Malloc32
.SpyReleasePending
= FALSE
;
199 Malloc32
.pSpy
= NULL
;
203 /* PreRealloc can force Realloc to fail */
204 LeaveCriticalSection(&IMalloc32_SpyCS
);
210 pNewMemory
= HeapReAlloc(GetProcessHeap(),0,pv
,cb
);
213 pNewMemory
= IMallocSpy_PostRealloc(Malloc32
.pSpy
, pNewMemory
, TRUE
);
214 if (pNewMemory
) AddMemoryLocation(pNewMemory
);
215 LeaveCriticalSection(&IMalloc32_SpyCS
);
218 TRACE("--(%p)\n",pNewMemory
);
222 /******************************************************************************
223 * IMalloc32_Free [VTABLE]
225 static VOID WINAPI
IMalloc_fnFree(LPMALLOC iface
,LPVOID pv
) {
232 EnterCriticalSection(&IMalloc32_SpyCS
);
233 fSpyed
= RemoveMemoryLocation(pv
);
234 pv
= IMallocSpy_PreFree(Malloc32
.pSpy
, pv
, fSpyed
);
237 HeapFree(GetProcessHeap(),0,pv
);
240 IMallocSpy_PostFree(Malloc32
.pSpy
, fSpyed
);
242 /* check if can release the spy */
243 if(Malloc32
.SpyReleasePending
&& !Malloc32
.SpyedAllocationsLeft
) {
244 IMallocSpy_Release(Malloc32
.pSpy
);
245 Malloc32
.SpyReleasePending
= FALSE
;
246 Malloc32
.pSpy
= NULL
;
249 LeaveCriticalSection(&IMalloc32_SpyCS
);
253 /******************************************************************************
254 * IMalloc32_GetSize [VTABLE]
258 * win95: size allocated (4 byte boundarys)
259 * win2k: size originally requested !!! (allocated on 8 byte boundarys)
261 static DWORD WINAPI
IMalloc_fnGetSize(LPMALLOC iface
,LPVOID pv
) {
269 EnterCriticalSection(&IMalloc32_SpyCS
);
270 pv
= IMallocSpy_PreGetSize(Malloc32
.pSpy
, pv
, fSpyed
);
273 cb
= HeapSize(GetProcessHeap(),0,pv
);
276 cb
= IMallocSpy_PostGetSize(Malloc32
.pSpy
, cb
, fSpyed
);
277 LeaveCriticalSection(&IMalloc32_SpyCS
);
283 /******************************************************************************
284 * IMalloc32_DidAlloc [VTABLE]
286 static INT WINAPI
IMalloc_fnDidAlloc(LPMALLOC iface
,LPVOID pv
) {
294 EnterCriticalSection(&IMalloc32_SpyCS
);
295 pv
= IMallocSpy_PreDidAlloc(Malloc32
.pSpy
, pv
, fSpyed
);
301 didAlloc
= IMallocSpy_PostDidAlloc(Malloc32
.pSpy
, pv
, fSpyed
, didAlloc
);
302 LeaveCriticalSection(&IMalloc32_SpyCS
);
307 /******************************************************************************
308 * IMalloc32_HeapMinimize [VTABLE]
310 static VOID WINAPI
IMalloc_fnHeapMinimize(LPMALLOC iface
) {
314 EnterCriticalSection(&IMalloc32_SpyCS
);
315 IMallocSpy_PreHeapMinimize(Malloc32
.pSpy
);
319 IMallocSpy_PostHeapMinimize(Malloc32
.pSpy
);
320 LeaveCriticalSection(&IMalloc32_SpyCS
);
324 static ICOM_VTABLE(IMalloc
) VT_IMalloc32
=
326 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
327 IMalloc_fnQueryInterface
,
328 IMalloc_fnAddRefRelease
,
329 IMalloc_fnAddRefRelease
,
335 IMalloc_fnHeapMinimize
338 /******************************************************************************
339 * IMallocSpy implementation
340 *****************************************************************************/
342 /* set the vtable later */
343 extern ICOM_VTABLE(IMallocSpy
) VT_IMallocSpy
;
346 ICOM_VFIELD(IMallocSpy
);
350 /* this is the static object instance */
351 _MallocSpy MallocSpy
= {&VT_IMallocSpy
, 0};
353 /******************************************************************************
354 * IMalloc32_QueryInterface [VTABLE]
356 static HRESULT WINAPI
IMallocSpy_fnQueryInterface(LPMALLOCSPY iface
,REFIID refiid
,LPVOID
*obj
)
359 TRACE("(%s,%p)\n",debugstr_guid(refiid
),obj
);
361 if (IsEqualIID(&IID_IUnknown
,refiid
) || IsEqualIID(&IID_IMallocSpy
,refiid
)) {
362 *obj
= (LPMALLOC
)&MallocSpy
;
365 return E_NOINTERFACE
;
368 /******************************************************************************
369 * IMalloc32_AddRef [VTABLE]
371 static ULONG WINAPI
IMallocSpy_fnAddRef (LPMALLOCSPY iface
)
374 ICOM_THIS (_MallocSpy
, iface
);
376 TRACE ("(%p)->(count=%lu)\n", This
, This
->ref
);
378 return ++(This
->ref
);
381 /******************************************************************************
382 * IMalloc32_AddRelease [VTABLE]
385 * Our MallocSpy is static. If the count reaches 0 we dump the leaks
387 static ULONG WINAPI
IMallocSpy_fnRelease (LPMALLOCSPY iface
)
390 ICOM_THIS (_MallocSpy
, iface
);
392 TRACE ("(%p)->(count=%lu)\n", This
, This
->ref
);
394 if (!--(This
->ref
)) {
395 /* our allocation list MUST be empty here */
400 static ULONG WINAPI
IMallocSpy_fnPreAlloc(LPMALLOCSPY iface
, ULONG cbRequest
)
402 ICOM_THIS (_MallocSpy
, iface
);
403 TRACE ("(%p)->(%lu)\n", This
, cbRequest
);
406 static PVOID WINAPI
IMallocSpy_fnPostAlloc(LPMALLOCSPY iface
, void* pActual
)
408 ICOM_THIS (_MallocSpy
, iface
);
409 TRACE ("(%p)->(%p)\n", This
, pActual
);
413 static PVOID WINAPI
IMallocSpy_fnPreFree(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
)
415 ICOM_THIS (_MallocSpy
, iface
);
416 TRACE ("(%p)->(%p %u)\n", This
, pRequest
, fSpyed
);
419 static void WINAPI
IMallocSpy_fnPostFree(LPMALLOCSPY iface
, BOOL fSpyed
)
421 ICOM_THIS (_MallocSpy
, iface
);
422 TRACE ("(%p)->(%u)\n", This
, fSpyed
);
425 static ULONG WINAPI
IMallocSpy_fnPreRealloc(LPMALLOCSPY iface
, void* pRequest
, ULONG cbRequest
, void** ppNewRequest
, BOOL fSpyed
)
427 ICOM_THIS (_MallocSpy
, iface
);
428 TRACE ("(%p)->(%p %lu %u)\n", This
, pRequest
, cbRequest
, fSpyed
);
429 *ppNewRequest
= pRequest
;
433 static PVOID WINAPI
IMallocSpy_fnPostRealloc(LPMALLOCSPY iface
, void* pActual
, BOOL fSpyed
)
435 ICOM_THIS (_MallocSpy
, iface
);
436 TRACE ("(%p)->(%p %u)\n", This
, pActual
, fSpyed
);
440 static PVOID WINAPI
IMallocSpy_fnPreGetSize(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
)
442 ICOM_THIS (_MallocSpy
, iface
);
443 TRACE ("(%p)->(%p %u)\n", This
, pRequest
, fSpyed
);
447 static ULONG WINAPI
IMallocSpy_fnPostGetSize(LPMALLOCSPY iface
, ULONG cbActual
, BOOL fSpyed
)
449 ICOM_THIS (_MallocSpy
, iface
);
450 TRACE ("(%p)->(%lu %u)\n", This
, cbActual
, fSpyed
);
454 static PVOID WINAPI
IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
)
456 ICOM_THIS (_MallocSpy
, iface
);
457 TRACE ("(%p)->(%p %u)\n", This
, pRequest
, fSpyed
);
461 static int WINAPI
IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
, int fActual
)
463 ICOM_THIS (_MallocSpy
, iface
);
464 TRACE ("(%p)->(%p %u %u)\n", This
, pRequest
, fSpyed
, fActual
);
468 static void WINAPI
IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface
)
470 ICOM_THIS (_MallocSpy
, iface
);
471 TRACE ("(%p)->()\n", This
);
474 static void WINAPI
IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface
)
476 ICOM_THIS (_MallocSpy
, iface
);
477 TRACE ("(%p)->()\n", This
);
480 static void MallocSpyDumpLeaks() {
481 TRACE("leaks: %lu\n", Malloc32
.SpyedAllocationsLeft
);
484 static ICOM_VTABLE(IMallocSpy
) VT_IMallocSpy
=
486 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
487 IMallocSpy_fnQueryInterface
,
489 IMallocSpy_fnRelease
,
490 IMallocSpy_fnPreAlloc
,
491 IMallocSpy_fnPostAlloc
,
492 IMallocSpy_fnPreFree
,
493 IMallocSpy_fnPostFree
,
494 IMallocSpy_fnPreRealloc
,
495 IMallocSpy_fnPostRealloc
,
496 IMallocSpy_fnPreGetSize
,
497 IMallocSpy_fnPostGetSize
,
498 IMallocSpy_fnPreDidAlloc
,
499 IMallocSpy_fnPostDidAlloc
,
500 IMallocSpy_fnPreHeapMinimize
,
501 IMallocSpy_fnPostHeapMinimize
504 /******************************************************************************
505 * CoGetMalloc [OLE32.20]
510 HRESULT WINAPI
CoGetMalloc(DWORD dwMemContext
, LPMALLOC
*lpMalloc
)
512 *lpMalloc
= (LPMALLOC
)&Malloc32
;
516 /***********************************************************************
517 * CoTaskMemAlloc [OLE32.43]
519 * pointer to newly allocated block
521 LPVOID WINAPI
CoTaskMemAlloc(ULONG size
)
523 return IMalloc_Alloc((LPMALLOC
)&Malloc32
,size
);
525 /***********************************************************************
526 * CoTaskMemFree [OLE32.44]
528 VOID WINAPI
CoTaskMemFree(LPVOID ptr
)
530 IMalloc_Free((LPMALLOC
)&Malloc32
, ptr
);
533 /***********************************************************************
534 * CoTaskMemRealloc [OLE32.45]
536 * pointer to newly allocated block
538 LPVOID WINAPI
CoTaskMemRealloc(LPVOID pvOld
, ULONG size
)
540 return IMalloc_Realloc((LPMALLOC
)&Malloc32
, pvOld
, size
);
543 /***********************************************************************
544 * CoRegisterMallocSpy [OLE32.37]
547 * if a mallocspy is already registered, we cant do it again since
548 * only the spy knows, how to free a memory block
550 HRESULT WINAPI
CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy
)
553 HRESULT hres
= E_INVALIDARG
;
557 /* HACK TO ACTIVATE OUT SPY */
558 if (pMallocSpy
== (LPVOID
)-1) pMallocSpy
=(IMallocSpy
*)&MallocSpy
;
560 if(Malloc32
.pSpy
) return CO_E_OBJISREG
;
562 EnterCriticalSection(&IMalloc32_SpyCS
);
564 if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy
, &IID_IMallocSpy
, (LPVOID
*)&pSpy
))) {
565 Malloc32
.pSpy
= pSpy
;
569 LeaveCriticalSection(&IMalloc32_SpyCS
);
574 /***********************************************************************
575 * CoRevokeMallocSpy [OLE32.41]
578 * we can't rewoke a malloc spy as long as memory blocks allocated with
579 * the spy are active since only the spy knows how to free them
581 HRESULT WINAPI
CoRevokeMallocSpy(void)
586 EnterCriticalSection(&IMalloc32_SpyCS
);
588 /* if it's our spy it's time to dump the leaks */
589 if (Malloc32
.pSpy
== (IMallocSpy
*)&MallocSpy
) {
590 MallocSpyDumpLeaks();
593 if (Malloc32
.SpyedAllocationsLeft
) {
594 TRACE("SpyReleasePending with %lu allocations left\n", Malloc32
.SpyedAllocationsLeft
);
595 Malloc32
.SpyReleasePending
= TRUE
;
596 hres
= E_ACCESSDENIED
;
598 IMallocSpy_Release(Malloc32
.pSpy
);
599 Malloc32
.pSpy
= NULL
;
601 LeaveCriticalSection(&IMalloc32_SpyCS
);
606 /******************************************************************************
607 * IsValidInterface [OLE32.78]
610 * True, if the passed pointer is a valid interface
612 BOOL WINAPI
IsValidInterface(
613 LPUNKNOWN punk
/* [in] interface to be tested */
616 IsBadReadPtr(punk
,4) ||
617 IsBadReadPtr(punk
->lpVtbl
,4) ||
618 IsBadReadPtr(punk
->lpVtbl
->QueryInterface
,9) ||
619 IsBadCodePtr((FARPROC
)punk
->lpVtbl
->QueryInterface
)