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/obj_base.h"
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
= CRITICAL_SECTION_INIT("IMalloc32_SpyCS");
66 /* resize the old table */
67 static int SetSpyedBlockTableLength ( int NewLength
)
69 Malloc32
.SpyedBlocks
= (LPVOID
*)LocalReAlloc((HLOCAL
)Malloc32
.SpyedBlocks
, NewLength
, GMEM_ZEROINIT
);
70 Malloc32
.SpyedBlockTableLength
= NewLength
;
71 return Malloc32
.SpyedBlocks
? 1 : 0;
74 /* add a location to the table */
75 static int AddMemoryLocation(LPVOID
* pMem
)
79 /* allocate the table if not already allocated */
80 if (!Malloc32
.SpyedBlockTableLength
) {
81 if (!SetSpyedBlockTableLength(0x1000)) return 0;
84 /* find a free location */
85 Current
= Malloc32
.SpyedBlocks
;
88 if (Current
>= Malloc32
.SpyedBlocks
+ Malloc32
.SpyedBlockTableLength
) {
89 /* no more space in table, grow it */
90 if (!SetSpyedBlockTableLength( Malloc32
.SpyedBlockTableLength
+ 0x1000 )) return 0;
94 /* put the location in our table */
96 Malloc32
.SpyedAllocationsLeft
++;
97 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
101 static int RemoveMemoryLocation(LPVOID
* pMem
)
103 LPVOID
* Current
= Malloc32
.SpyedBlocks
;
105 /* find the location */
106 while (*Current
!= pMem
) {
108 if (Current
>= Malloc32
.SpyedBlocks
+ Malloc32
.SpyedBlockTableLength
) return 0; /* not found */
112 Malloc32
.SpyedAllocationsLeft
--;
113 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
118 /******************************************************************************
119 * IMalloc32_QueryInterface [VTABLE]
121 static HRESULT WINAPI
IMalloc_fnQueryInterface(LPMALLOC iface
,REFIID refiid
,LPVOID
*obj
) {
123 TRACE("(%s,%p)\n",debugstr_guid(refiid
),obj
);
125 if (IsEqualIID(&IID_IUnknown
,refiid
) || IsEqualIID(&IID_IMalloc
,refiid
)) {
126 *obj
= (LPMALLOC
)&Malloc32
;
129 return E_NOINTERFACE
;
132 /******************************************************************************
133 * IMalloc32_AddRefRelease [VTABLE]
135 static ULONG WINAPI
IMalloc_fnAddRefRelease (LPMALLOC iface
) {
139 /******************************************************************************
140 * IMalloc32_Alloc [VTABLE]
142 static LPVOID WINAPI
IMalloc_fnAlloc(LPMALLOC iface
, DWORD cb
) {
149 EnterCriticalSection(&IMalloc32_SpyCS
);
150 cb
= IMallocSpy_PreAlloc(Malloc32
.pSpy
, cb
);
152 /* PreAlloc can force Alloc to fail */
153 LeaveCriticalSection(&IMalloc32_SpyCS
);
159 addr
= HeapAlloc(GetProcessHeap(),0,cb
);
162 addr
= IMallocSpy_PostAlloc(Malloc32
.pSpy
, addr
);
163 if (addr
) AddMemoryLocation(addr
);
164 LeaveCriticalSection(&IMalloc32_SpyCS
);
167 TRACE("--(%p)\n",addr
);
171 /******************************************************************************
172 * IMalloc32_Realloc [VTABLE]
174 static LPVOID WINAPI
IMalloc_fnRealloc(LPMALLOC iface
,LPVOID pv
,DWORD cb
) {
178 TRACE("(%p,%ld)\n",pv
,cb
);
184 EnterCriticalSection(&IMalloc32_SpyCS
);
185 fSpyed
= RemoveMemoryLocation(pv
);
186 cb
= IMallocSpy_PreRealloc(Malloc32
.pSpy
, pv
, cb
, &pRealMemory
, fSpyed
);
188 /* check if can release the spy */
189 if(Malloc32
.SpyReleasePending
&& !Malloc32
.SpyedAllocationsLeft
) {
190 IMallocSpy_Release(Malloc32
.pSpy
);
191 Malloc32
.SpyReleasePending
= FALSE
;
192 Malloc32
.pSpy
= NULL
;
196 /* PreRealloc can force Realloc to fail */
197 LeaveCriticalSection(&IMalloc32_SpyCS
);
203 pNewMemory
= HeapReAlloc(GetProcessHeap(),0,pv
,cb
);
206 pNewMemory
= IMallocSpy_PostRealloc(Malloc32
.pSpy
, pNewMemory
, TRUE
);
207 if (pNewMemory
) AddMemoryLocation(pNewMemory
);
208 LeaveCriticalSection(&IMalloc32_SpyCS
);
211 TRACE("--(%p)\n",pNewMemory
);
215 /******************************************************************************
216 * IMalloc32_Free [VTABLE]
218 static VOID WINAPI
IMalloc_fnFree(LPMALLOC iface
,LPVOID pv
) {
225 EnterCriticalSection(&IMalloc32_SpyCS
);
226 fSpyed
= RemoveMemoryLocation(pv
);
227 pv
= IMallocSpy_PreFree(Malloc32
.pSpy
, pv
, fSpyed
);
230 HeapFree(GetProcessHeap(),0,pv
);
233 IMallocSpy_PostFree(Malloc32
.pSpy
, fSpyed
);
235 /* check if can release the spy */
236 if(Malloc32
.SpyReleasePending
&& !Malloc32
.SpyedAllocationsLeft
) {
237 IMallocSpy_Release(Malloc32
.pSpy
);
238 Malloc32
.SpyReleasePending
= FALSE
;
239 Malloc32
.pSpy
= NULL
;
242 LeaveCriticalSection(&IMalloc32_SpyCS
);
246 /******************************************************************************
247 * IMalloc32_GetSize [VTABLE]
251 * win95: size allocated (4 byte boundarys)
252 * win2k: size originally requested !!! (allocated on 8 byte boundarys)
254 static DWORD WINAPI
IMalloc_fnGetSize(LPMALLOC iface
,LPVOID pv
) {
262 EnterCriticalSection(&IMalloc32_SpyCS
);
263 pv
= IMallocSpy_PreGetSize(Malloc32
.pSpy
, pv
, fSpyed
);
266 cb
= HeapSize(GetProcessHeap(),0,pv
);
269 cb
= IMallocSpy_PostGetSize(Malloc32
.pSpy
, cb
, fSpyed
);
270 LeaveCriticalSection(&IMalloc32_SpyCS
);
276 /******************************************************************************
277 * IMalloc32_DidAlloc [VTABLE]
279 static INT WINAPI
IMalloc_fnDidAlloc(LPMALLOC iface
,LPVOID pv
) {
287 EnterCriticalSection(&IMalloc32_SpyCS
);
288 pv
= IMallocSpy_PreDidAlloc(Malloc32
.pSpy
, pv
, fSpyed
);
294 didAlloc
= IMallocSpy_PostDidAlloc(Malloc32
.pSpy
, pv
, fSpyed
, didAlloc
);
295 LeaveCriticalSection(&IMalloc32_SpyCS
);
300 /******************************************************************************
301 * IMalloc32_HeapMinimize [VTABLE]
303 static VOID WINAPI
IMalloc_fnHeapMinimize(LPMALLOC iface
) {
307 EnterCriticalSection(&IMalloc32_SpyCS
);
308 IMallocSpy_PreHeapMinimize(Malloc32
.pSpy
);
312 IMallocSpy_PostHeapMinimize(Malloc32
.pSpy
);
313 LeaveCriticalSection(&IMalloc32_SpyCS
);
317 static ICOM_VTABLE(IMalloc
) VT_IMalloc32
=
319 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
320 IMalloc_fnQueryInterface
,
321 IMalloc_fnAddRefRelease
,
322 IMalloc_fnAddRefRelease
,
328 IMalloc_fnHeapMinimize
331 /******************************************************************************
332 * IMallocSpy implementation
333 *****************************************************************************/
335 /* set the vtable later */
336 extern ICOM_VTABLE(IMallocSpy
) VT_IMallocSpy
;
339 ICOM_VFIELD(IMallocSpy
);
343 /* this is the static object instance */
344 _MallocSpy MallocSpy
= {&VT_IMallocSpy
, 0};
346 /******************************************************************************
347 * IMalloc32_QueryInterface [VTABLE]
349 static HRESULT WINAPI
IMallocSpy_fnQueryInterface(LPMALLOCSPY iface
,REFIID refiid
,LPVOID
*obj
)
352 TRACE("(%s,%p)\n",debugstr_guid(refiid
),obj
);
354 if (IsEqualIID(&IID_IUnknown
,refiid
) || IsEqualIID(&IID_IMallocSpy
,refiid
)) {
355 *obj
= (LPMALLOC
)&MallocSpy
;
358 return E_NOINTERFACE
;
361 /******************************************************************************
362 * IMalloc32_AddRef [VTABLE]
364 static ULONG WINAPI
IMallocSpy_fnAddRef (LPMALLOCSPY iface
)
367 ICOM_THIS (_MallocSpy
, iface
);
369 TRACE ("(%p)->(count=%lu)\n", This
, This
->ref
);
371 return ++(This
->ref
);
374 /******************************************************************************
375 * IMalloc32_AddRelease [VTABLE]
378 * Our MallocSpy is static. If the count reaches 0 we dump the leaks
380 static ULONG WINAPI
IMallocSpy_fnRelease (LPMALLOCSPY iface
)
383 ICOM_THIS (_MallocSpy
, iface
);
385 TRACE ("(%p)->(count=%lu)\n", This
, This
->ref
);
387 if (!--(This
->ref
)) {
388 /* our allocation list MUST be empty here */
393 static ULONG WINAPI
IMallocSpy_fnPreAlloc(LPMALLOCSPY iface
, ULONG cbRequest
)
395 ICOM_THIS (_MallocSpy
, iface
);
396 TRACE ("(%p)->(%lu)\n", This
, cbRequest
);
399 static PVOID WINAPI
IMallocSpy_fnPostAlloc(LPMALLOCSPY iface
, void* pActual
)
401 ICOM_THIS (_MallocSpy
, iface
);
402 TRACE ("(%p)->(%p)\n", This
, pActual
);
406 static PVOID WINAPI
IMallocSpy_fnPreFree(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
)
408 ICOM_THIS (_MallocSpy
, iface
);
409 TRACE ("(%p)->(%p %u)\n", This
, pRequest
, fSpyed
);
412 static void WINAPI
IMallocSpy_fnPostFree(LPMALLOCSPY iface
, BOOL fSpyed
)
414 ICOM_THIS (_MallocSpy
, iface
);
415 TRACE ("(%p)->(%u)\n", This
, fSpyed
);
418 static ULONG WINAPI
IMallocSpy_fnPreRealloc(LPMALLOCSPY iface
, void* pRequest
, ULONG cbRequest
, void** ppNewRequest
, BOOL fSpyed
)
420 ICOM_THIS (_MallocSpy
, iface
);
421 TRACE ("(%p)->(%p %lu %u)\n", This
, pRequest
, cbRequest
, fSpyed
);
422 *ppNewRequest
= pRequest
;
426 static PVOID WINAPI
IMallocSpy_fnPostRealloc(LPMALLOCSPY iface
, void* pActual
, BOOL fSpyed
)
428 ICOM_THIS (_MallocSpy
, iface
);
429 TRACE ("(%p)->(%p %u)\n", This
, pActual
, fSpyed
);
433 static PVOID WINAPI
IMallocSpy_fnPreGetSize(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
)
435 ICOM_THIS (_MallocSpy
, iface
);
436 TRACE ("(%p)->(%p %u)\n", This
, pRequest
, fSpyed
);
440 static ULONG WINAPI
IMallocSpy_fnPostGetSize(LPMALLOCSPY iface
, ULONG cbActual
, BOOL fSpyed
)
442 ICOM_THIS (_MallocSpy
, iface
);
443 TRACE ("(%p)->(%lu %u)\n", This
, cbActual
, fSpyed
);
447 static PVOID WINAPI
IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
)
449 ICOM_THIS (_MallocSpy
, iface
);
450 TRACE ("(%p)->(%p %u)\n", This
, pRequest
, fSpyed
);
454 static int WINAPI
IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface
, void* pRequest
, BOOL fSpyed
, int fActual
)
456 ICOM_THIS (_MallocSpy
, iface
);
457 TRACE ("(%p)->(%p %u %u)\n", This
, pRequest
, fSpyed
, fActual
);
461 static int WINAPI
IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface
)
463 ICOM_THIS (_MallocSpy
, iface
);
464 TRACE ("(%p)->()\n", This
);
468 static int WINAPI
IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface
)
470 ICOM_THIS (_MallocSpy
, iface
);
471 TRACE ("(%p)->()\n", This
);
475 static void MallocSpyDumpLeaks() {
476 TRACE("leaks: %lu\n", Malloc32
.SpyedAllocationsLeft
);
479 static ICOM_VTABLE(IMallocSpy
) VT_IMallocSpy
=
481 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
482 IMallocSpy_fnQueryInterface
,
484 IMallocSpy_fnRelease
,
485 IMallocSpy_fnPreAlloc
,
486 IMallocSpy_fnPostAlloc
,
487 IMallocSpy_fnPreFree
,
488 IMallocSpy_fnPostFree
,
489 IMallocSpy_fnPreRealloc
,
490 IMallocSpy_fnPostRealloc
,
491 IMallocSpy_fnPreGetSize
,
492 IMallocSpy_fnPostGetSize
,
493 IMallocSpy_fnPreDidAlloc
,
494 IMallocSpy_fnPostDidAlloc
,
495 IMallocSpy_fnPreHeapMinimize
,
496 IMallocSpy_fnPostHeapMinimize
499 /******************************************************************************
500 * CoGetMalloc [OLE32.20]
505 HRESULT WINAPI
CoGetMalloc(DWORD dwMemContext
, LPMALLOC
*lpMalloc
)
507 *lpMalloc
= (LPMALLOC
)&Malloc32
;
511 /***********************************************************************
512 * CoTaskMemAlloc [OLE32.43]
514 * pointer to newly allocated block
516 LPVOID WINAPI
CoTaskMemAlloc(ULONG size
)
518 return IMalloc_Alloc((LPMALLOC
)&Malloc32
,size
);
520 /***********************************************************************
521 * CoTaskMemFree [OLE32.44]
523 VOID WINAPI
CoTaskMemFree(LPVOID ptr
)
525 IMalloc_Free((LPMALLOC
)&Malloc32
, ptr
);
528 /***********************************************************************
529 * CoTaskMemRealloc [OLE32.45]
531 * pointer to newly allocated block
533 LPVOID WINAPI
CoTaskMemRealloc(LPVOID pvOld
, ULONG size
)
535 return IMalloc_Realloc((LPMALLOC
)&Malloc32
, pvOld
, size
);
538 /***********************************************************************
539 * CoRegisterMallocSpy [OLE32.37]
542 * if a mallocspy is already registered, we cant do it again since
543 * only the spy knows, how to free a memory block
545 HRESULT WINAPI
CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy
)
548 HRESULT hres
= E_INVALIDARG
;
552 /* HACK TO ACTIVATE OUT SPY */
553 if (pMallocSpy
== (LPVOID
)-1) pMallocSpy
=(IMallocSpy
*)&MallocSpy
;
555 if(Malloc32
.pSpy
) return CO_E_OBJISREG
;
557 EnterCriticalSection(&IMalloc32_SpyCS
);
559 if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy
, &IID_IMallocSpy
, (LPVOID
*)&pSpy
))) {
560 Malloc32
.pSpy
= pSpy
;
564 LeaveCriticalSection(&IMalloc32_SpyCS
);
569 /***********************************************************************
570 * CoRevokeMallocSpy [OLE32.41]
573 * we can't rewoke a malloc spy as long as memory blocks allocated with
574 * the spy are active since only the spy knows how to free them
576 HRESULT WINAPI
CoRevokeMallocSpy(void)
581 EnterCriticalSection(&IMalloc32_SpyCS
);
583 /* if it's our spy it's time to dump the leaks */
584 if (Malloc32
.pSpy
== (IMallocSpy
*)&MallocSpy
) {
585 MallocSpyDumpLeaks();
588 if (Malloc32
.SpyedAllocationsLeft
) {
589 TRACE("SpyReleasePending with %lu allocations left\n", Malloc32
.SpyedAllocationsLeft
);
590 Malloc32
.SpyReleasePending
= TRUE
;
591 hres
= E_ACCESSDENIED
;
593 IMallocSpy_Release(Malloc32
.pSpy
);
594 Malloc32
.pSpy
= NULL
;
596 LeaveCriticalSection(&IMalloc32_SpyCS
);
601 /******************************************************************************
602 * IsValidInterface [OLE32.78]
605 * True, if the passed pointer is a valid interface
607 BOOL WINAPI
IsValidInterface(
608 LPUNKNOWN punk
/* [in] interface to be tested */
611 IsBadReadPtr(punk
,4) ||
612 IsBadReadPtr(ICOM_VTBL(punk
),4) ||
613 IsBadReadPtr(ICOM_VTBL(punk
)->QueryInterface
,9) ||
614 IsBadCodePtr((FARPROC
)ICOM_VTBL(punk
)->QueryInterface
)