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 = CRITICAL_SECTION_INIT("IMalloc32_SpyCS");
64 /* resize the old table */
65 static int SetSpyedBlockTableLength ( int NewLength )
67 Malloc32.SpyedBlocks = (LPVOID*)LocalReAlloc((HLOCAL)Malloc32.SpyedBlocks, NewLength, GMEM_ZEROINIT);
68 Malloc32.SpyedBlockTableLength = NewLength;
69 return Malloc32.SpyedBlocks ? 1 : 0;
72 /* add a location to the table */
73 static int AddMemoryLocation(LPVOID * pMem)
77 /* allocate the table if not already allocated */
78 if (!Malloc32.SpyedBlockTableLength) {
79 if (!SetSpyedBlockTableLength(0x1000)) return 0;
82 /* find a free location */
83 Current = Malloc32.SpyedBlocks;
86 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) {
87 /* no more space in table, grow it */
88 if (!SetSpyedBlockTableLength( Malloc32.SpyedBlockTableLength + 0x1000 )) return 0;
92 /* put the location in our table */
94 Malloc32.SpyedAllocationsLeft++;
95 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
99 static int RemoveMemoryLocation(LPVOID * pMem)
101 LPVOID * Current = Malloc32.SpyedBlocks;
103 /* find the location */
104 while (*Current != pMem) {
106 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) return 0; /* not found */
110 Malloc32.SpyedAllocationsLeft--;
111 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
116 /******************************************************************************
117 * IMalloc32_QueryInterface [VTABLE]
119 static HRESULT WINAPI IMalloc_fnQueryInterface(LPMALLOC iface,REFIID refiid,LPVOID *obj) {
121 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
123 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMalloc,refiid)) {
124 *obj = (LPMALLOC)&Malloc32;
127 return E_NOINTERFACE;
130 /******************************************************************************
131 * IMalloc32_AddRefRelease [VTABLE]
133 static ULONG WINAPI IMalloc_fnAddRefRelease (LPMALLOC iface) {
137 /******************************************************************************
138 * IMalloc32_Alloc [VTABLE]
140 static LPVOID WINAPI IMalloc_fnAlloc(LPMALLOC iface, DWORD cb) {
147 EnterCriticalSection(&IMalloc32_SpyCS);
148 cb = IMallocSpy_PreAlloc(Malloc32.pSpy, cb);
150 /* PreAlloc can force Alloc to fail */
151 LeaveCriticalSection(&IMalloc32_SpyCS);
157 addr = HeapAlloc(GetProcessHeap(),0,cb);
160 addr = IMallocSpy_PostAlloc(Malloc32.pSpy, addr);
161 if (addr) AddMemoryLocation(addr);
162 LeaveCriticalSection(&IMalloc32_SpyCS);
165 TRACE("--(%p)\n",addr);
169 /******************************************************************************
170 * IMalloc32_Realloc [VTABLE]
172 static LPVOID WINAPI IMalloc_fnRealloc(LPMALLOC iface,LPVOID pv,DWORD cb) {
176 TRACE("(%p,%ld)\n",pv,cb);
182 EnterCriticalSection(&IMalloc32_SpyCS);
183 fSpyed = RemoveMemoryLocation(pv);
184 cb = IMallocSpy_PreRealloc(Malloc32.pSpy, pv, cb, &pRealMemory, fSpyed);
186 /* check if can release the spy */
187 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
188 IMallocSpy_Release(Malloc32.pSpy);
189 Malloc32.SpyReleasePending = FALSE;
190 Malloc32.pSpy = NULL;
194 /* PreRealloc can force Realloc to fail */
195 LeaveCriticalSection(&IMalloc32_SpyCS);
201 pNewMemory = HeapReAlloc(GetProcessHeap(),0,pv,cb);
204 pNewMemory = IMallocSpy_PostRealloc(Malloc32.pSpy, pNewMemory, TRUE);
205 if (pNewMemory) AddMemoryLocation(pNewMemory);
206 LeaveCriticalSection(&IMalloc32_SpyCS);
209 TRACE("--(%p)\n",pNewMemory);
213 /******************************************************************************
214 * IMalloc32_Free [VTABLE]
216 static VOID WINAPI IMalloc_fnFree(LPMALLOC iface,LPVOID pv) {
223 EnterCriticalSection(&IMalloc32_SpyCS);
224 fSpyed = RemoveMemoryLocation(pv);
225 pv = IMallocSpy_PreFree(Malloc32.pSpy, pv, fSpyed);
228 HeapFree(GetProcessHeap(),0,pv);
231 IMallocSpy_PostFree(Malloc32.pSpy, fSpyed);
233 /* check if can release the spy */
234 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
235 IMallocSpy_Release(Malloc32.pSpy);
236 Malloc32.SpyReleasePending = FALSE;
237 Malloc32.pSpy = NULL;
240 LeaveCriticalSection(&IMalloc32_SpyCS);
244 /******************************************************************************
245 * IMalloc32_GetSize [VTABLE]
249 * win95: size allocated (4 byte boundarys)
250 * win2k: size originally requested !!! (allocated on 8 byte boundarys)
252 static DWORD WINAPI IMalloc_fnGetSize(LPMALLOC iface,LPVOID pv) {
260 EnterCriticalSection(&IMalloc32_SpyCS);
261 pv = IMallocSpy_PreGetSize(Malloc32.pSpy, pv, fSpyed);
264 cb = HeapSize(GetProcessHeap(),0,pv);
267 cb = IMallocSpy_PostGetSize(Malloc32.pSpy, cb, fSpyed);
268 LeaveCriticalSection(&IMalloc32_SpyCS);
274 /******************************************************************************
275 * IMalloc32_DidAlloc [VTABLE]
277 static INT WINAPI IMalloc_fnDidAlloc(LPMALLOC iface,LPVOID pv) {
285 EnterCriticalSection(&IMalloc32_SpyCS);
286 pv = IMallocSpy_PreDidAlloc(Malloc32.pSpy, pv, fSpyed);
292 didAlloc = IMallocSpy_PostDidAlloc(Malloc32.pSpy, pv, fSpyed, didAlloc);
293 LeaveCriticalSection(&IMalloc32_SpyCS);
298 /******************************************************************************
299 * IMalloc32_HeapMinimize [VTABLE]
301 static VOID WINAPI IMalloc_fnHeapMinimize(LPMALLOC iface) {
305 EnterCriticalSection(&IMalloc32_SpyCS);
306 IMallocSpy_PreHeapMinimize(Malloc32.pSpy);
310 IMallocSpy_PostHeapMinimize(Malloc32.pSpy);
311 LeaveCriticalSection(&IMalloc32_SpyCS);
315 static ICOM_VTABLE(IMalloc) VT_IMalloc32 =
317 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
318 IMalloc_fnQueryInterface,
319 IMalloc_fnAddRefRelease,
320 IMalloc_fnAddRefRelease,
326 IMalloc_fnHeapMinimize
329 /******************************************************************************
330 * IMallocSpy implementation
331 *****************************************************************************/
333 /* set the vtable later */
334 extern ICOM_VTABLE(IMallocSpy) VT_IMallocSpy;
337 ICOM_VFIELD(IMallocSpy);
341 /* this is the static object instance */
342 _MallocSpy MallocSpy = {&VT_IMallocSpy, 0};
344 /******************************************************************************
345 * IMalloc32_QueryInterface [VTABLE]
347 static HRESULT WINAPI IMallocSpy_fnQueryInterface(LPMALLOCSPY iface,REFIID refiid,LPVOID *obj)
350 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
352 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMallocSpy,refiid)) {
353 *obj = (LPMALLOC)&MallocSpy;
356 return E_NOINTERFACE;
359 /******************************************************************************
360 * IMalloc32_AddRef [VTABLE]
362 static ULONG WINAPI IMallocSpy_fnAddRef (LPMALLOCSPY iface)
365 ICOM_THIS (_MallocSpy, iface);
367 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
369 return ++(This->ref);
372 /******************************************************************************
373 * IMalloc32_AddRelease [VTABLE]
376 * Our MallocSpy is static. If the count reaches 0 we dump the leaks
378 static ULONG WINAPI IMallocSpy_fnRelease (LPMALLOCSPY iface)
381 ICOM_THIS (_MallocSpy, iface);
383 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
385 if (!--(This->ref)) {
386 /* our allocation list MUST be empty here */
391 static ULONG WINAPI IMallocSpy_fnPreAlloc(LPMALLOCSPY iface, ULONG cbRequest)
393 ICOM_THIS (_MallocSpy, iface);
394 TRACE ("(%p)->(%lu)\n", This, cbRequest);
397 static PVOID WINAPI IMallocSpy_fnPostAlloc(LPMALLOCSPY iface, void* pActual)
399 ICOM_THIS (_MallocSpy, iface);
400 TRACE ("(%p)->(%p)\n", This, pActual);
404 static PVOID WINAPI IMallocSpy_fnPreFree(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
406 ICOM_THIS (_MallocSpy, iface);
407 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
410 static void WINAPI IMallocSpy_fnPostFree(LPMALLOCSPY iface, BOOL fSpyed)
412 ICOM_THIS (_MallocSpy, iface);
413 TRACE ("(%p)->(%u)\n", This, fSpyed);
416 static ULONG WINAPI IMallocSpy_fnPreRealloc(LPMALLOCSPY iface, void* pRequest, ULONG cbRequest, void** ppNewRequest, BOOL fSpyed)
418 ICOM_THIS (_MallocSpy, iface);
419 TRACE ("(%p)->(%p %lu %u)\n", This, pRequest, cbRequest, fSpyed);
420 *ppNewRequest = pRequest;
424 static PVOID WINAPI IMallocSpy_fnPostRealloc(LPMALLOCSPY iface, void* pActual, BOOL fSpyed)
426 ICOM_THIS (_MallocSpy, iface);
427 TRACE ("(%p)->(%p %u)\n", This, pActual, fSpyed);
431 static PVOID WINAPI IMallocSpy_fnPreGetSize(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
433 ICOM_THIS (_MallocSpy, iface);
434 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
438 static ULONG WINAPI IMallocSpy_fnPostGetSize(LPMALLOCSPY iface, ULONG cbActual, BOOL fSpyed)
440 ICOM_THIS (_MallocSpy, iface);
441 TRACE ("(%p)->(%lu %u)\n", This, cbActual, fSpyed);
445 static PVOID WINAPI IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
447 ICOM_THIS (_MallocSpy, iface);
448 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
452 static int WINAPI IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed, int fActual)
454 ICOM_THIS (_MallocSpy, iface);
455 TRACE ("(%p)->(%p %u %u)\n", This, pRequest, fSpyed, fActual);
459 static void WINAPI IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface)
461 ICOM_THIS (_MallocSpy, iface);
462 TRACE ("(%p)->()\n", This);
465 static void WINAPI IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface)
467 ICOM_THIS (_MallocSpy, iface);
468 TRACE ("(%p)->()\n", This);
471 static void MallocSpyDumpLeaks() {
472 TRACE("leaks: %lu\n", Malloc32.SpyedAllocationsLeft);
475 static ICOM_VTABLE(IMallocSpy) VT_IMallocSpy =
477 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
478 IMallocSpy_fnQueryInterface,
480 IMallocSpy_fnRelease,
481 IMallocSpy_fnPreAlloc,
482 IMallocSpy_fnPostAlloc,
483 IMallocSpy_fnPreFree,
484 IMallocSpy_fnPostFree,
485 IMallocSpy_fnPreRealloc,
486 IMallocSpy_fnPostRealloc,
487 IMallocSpy_fnPreGetSize,
488 IMallocSpy_fnPostGetSize,
489 IMallocSpy_fnPreDidAlloc,
490 IMallocSpy_fnPostDidAlloc,
491 IMallocSpy_fnPreHeapMinimize,
492 IMallocSpy_fnPostHeapMinimize
495 /******************************************************************************
496 * CoGetMalloc [OLE32.20]
501 HRESULT WINAPI CoGetMalloc(DWORD dwMemContext, LPMALLOC *lpMalloc)
503 *lpMalloc = (LPMALLOC)&Malloc32;
507 /***********************************************************************
508 * CoTaskMemAlloc [OLE32.43]
510 * pointer to newly allocated block
512 LPVOID WINAPI CoTaskMemAlloc(ULONG size)
514 return IMalloc_Alloc((LPMALLOC)&Malloc32,size);
516 /***********************************************************************
517 * CoTaskMemFree [OLE32.44]
519 VOID WINAPI CoTaskMemFree(LPVOID ptr)
521 IMalloc_Free((LPMALLOC)&Malloc32, ptr);
524 /***********************************************************************
525 * CoTaskMemRealloc [OLE32.45]
527 * pointer to newly allocated block
529 LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, ULONG size)
531 return IMalloc_Realloc((LPMALLOC)&Malloc32, pvOld, size);
534 /***********************************************************************
535 * CoRegisterMallocSpy [OLE32.37]
538 * if a mallocspy is already registered, we cant do it again since
539 * only the spy knows, how to free a memory block
541 HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy)
544 HRESULT hres = E_INVALIDARG;
548 /* HACK TO ACTIVATE OUT SPY */
549 if (pMallocSpy == (LPVOID)-1) pMallocSpy =(IMallocSpy*)&MallocSpy;
551 if(Malloc32.pSpy) return CO_E_OBJISREG;
553 EnterCriticalSection(&IMalloc32_SpyCS);
555 if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy, &IID_IMallocSpy, (LPVOID*)&pSpy))) {
556 Malloc32.pSpy = pSpy;
560 LeaveCriticalSection(&IMalloc32_SpyCS);
565 /***********************************************************************
566 * CoRevokeMallocSpy [OLE32.41]
569 * we can't rewoke a malloc spy as long as memory blocks allocated with
570 * the spy are active since only the spy knows how to free them
572 HRESULT WINAPI CoRevokeMallocSpy(void)
577 EnterCriticalSection(&IMalloc32_SpyCS);
579 /* if it's our spy it's time to dump the leaks */
580 if (Malloc32.pSpy == (IMallocSpy*)&MallocSpy) {
581 MallocSpyDumpLeaks();
584 if (Malloc32.SpyedAllocationsLeft) {
585 TRACE("SpyReleasePending with %lu allocations left\n", Malloc32.SpyedAllocationsLeft);
586 Malloc32.SpyReleasePending = TRUE;
587 hres = E_ACCESSDENIED;
589 IMallocSpy_Release(Malloc32.pSpy);
590 Malloc32.pSpy = NULL;
592 LeaveCriticalSection(&IMalloc32_SpyCS);
597 /******************************************************************************
598 * IsValidInterface [OLE32.78]
601 * True, if the passed pointer is a valid interface
603 BOOL WINAPI IsValidInterface(
604 LPUNKNOWN punk /* [in] interface to be tested */
607 IsBadReadPtr(punk,4) ||
608 IsBadReadPtr(ICOM_VTBL(punk),4) ||
609 IsBadReadPtr(ICOM_VTBL(punk)->QueryInterface,9) ||
610 IsBadCodePtr((FARPROC)ICOM_VTBL(punk)->QueryInterface)