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
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 IMallocVtbl VT_IMalloc32;
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 _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, { 0, (DWORD)(__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(GMEM_ZEROINIT, NewLength);
81 else NewSpyedBlocks = LocalReAlloc(Malloc32.SpyedBlocks, NewLength, GMEM_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,%ld)\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 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 IMallocSpyVtbl VT_IMallocSpy;
368 IMallocSpyVtbl *lpVtbl;
372 /* this is the static object instance */
373 _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;
398 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
400 return ++(This->ref);
403 /******************************************************************************
404 * IMalloc32_AddRelease [VTABLE]
407 * Our MallocSpy is static. If the count reaches 0 we dump the leaks
409 static ULONG WINAPI IMallocSpy_fnRelease (LPMALLOCSPY iface)
412 _MallocSpy *This = (_MallocSpy *)iface;
414 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
416 if (!--(This->ref)) {
417 /* our allocation list MUST be empty here */
422 static ULONG WINAPI IMallocSpy_fnPreAlloc(LPMALLOCSPY iface, ULONG cbRequest)
424 _MallocSpy *This = (_MallocSpy *)iface;
425 TRACE ("(%p)->(%lu)\n", This, cbRequest);
428 static PVOID WINAPI IMallocSpy_fnPostAlloc(LPMALLOCSPY iface, void* pActual)
430 _MallocSpy *This = (_MallocSpy *)iface;
431 TRACE ("(%p)->(%p)\n", This, pActual);
435 static PVOID WINAPI IMallocSpy_fnPreFree(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
437 _MallocSpy *This = (_MallocSpy *)iface;
438 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
441 static void WINAPI IMallocSpy_fnPostFree(LPMALLOCSPY iface, BOOL fSpyed)
443 _MallocSpy *This = (_MallocSpy *)iface;
444 TRACE ("(%p)->(%u)\n", This, fSpyed);
447 static ULONG WINAPI IMallocSpy_fnPreRealloc(LPMALLOCSPY iface, void* pRequest, ULONG cbRequest, void** ppNewRequest, BOOL fSpyed)
449 _MallocSpy *This = (_MallocSpy *)iface;
450 TRACE ("(%p)->(%p %lu %u)\n", This, pRequest, cbRequest, fSpyed);
451 *ppNewRequest = pRequest;
455 static PVOID WINAPI IMallocSpy_fnPostRealloc(LPMALLOCSPY iface, void* pActual, BOOL fSpyed)
457 _MallocSpy *This = (_MallocSpy *)iface;
458 TRACE ("(%p)->(%p %u)\n", This, pActual, fSpyed);
462 static PVOID WINAPI IMallocSpy_fnPreGetSize(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
464 _MallocSpy *This = (_MallocSpy *)iface;
465 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
469 static ULONG WINAPI IMallocSpy_fnPostGetSize(LPMALLOCSPY iface, ULONG cbActual, BOOL fSpyed)
471 _MallocSpy *This = (_MallocSpy *)iface;
472 TRACE ("(%p)->(%lu %u)\n", This, cbActual, fSpyed);
476 static PVOID WINAPI IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
478 _MallocSpy *This = (_MallocSpy *)iface;
479 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
483 static int WINAPI IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed, int fActual)
485 _MallocSpy *This = (_MallocSpy *)iface;
486 TRACE ("(%p)->(%p %u %u)\n", This, pRequest, fSpyed, fActual);
490 static void WINAPI IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface)
492 _MallocSpy *This = (_MallocSpy *)iface;
493 TRACE ("(%p)->()\n", This);
496 static void WINAPI IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface)
498 _MallocSpy *This = (_MallocSpy *)iface;
499 TRACE ("(%p)->()\n", This);
502 static void MallocSpyDumpLeaks() {
503 TRACE("leaks: %lu\n", Malloc32.SpyedAllocationsLeft);
506 static IMallocSpyVtbl VT_IMallocSpy =
508 IMallocSpy_fnQueryInterface,
510 IMallocSpy_fnRelease,
511 IMallocSpy_fnPreAlloc,
512 IMallocSpy_fnPostAlloc,
513 IMallocSpy_fnPreFree,
514 IMallocSpy_fnPostFree,
515 IMallocSpy_fnPreRealloc,
516 IMallocSpy_fnPostRealloc,
517 IMallocSpy_fnPreGetSize,
518 IMallocSpy_fnPostGetSize,
519 IMallocSpy_fnPreDidAlloc,
520 IMallocSpy_fnPostDidAlloc,
521 IMallocSpy_fnPreHeapMinimize,
522 IMallocSpy_fnPostHeapMinimize
525 /******************************************************************************
526 * CoGetMalloc [OLE32.@]
531 HRESULT WINAPI CoGetMalloc(DWORD dwMemContext, LPMALLOC *lpMalloc)
533 *lpMalloc = (LPMALLOC)&Malloc32;
537 /***********************************************************************
538 * CoTaskMemAlloc [OLE32.@]
540 * pointer to newly allocated block
542 LPVOID WINAPI CoTaskMemAlloc(ULONG size)
544 return IMalloc_Alloc((LPMALLOC)&Malloc32,size);
546 /***********************************************************************
547 * CoTaskMemFree [OLE32.@]
549 VOID WINAPI CoTaskMemFree(LPVOID ptr)
551 IMalloc_Free((LPMALLOC)&Malloc32, ptr);
554 /***********************************************************************
555 * CoTaskMemRealloc [OLE32.@]
557 * pointer to newly allocated block
559 LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, ULONG size)
561 return IMalloc_Realloc((LPMALLOC)&Malloc32, pvOld, size);
564 /***********************************************************************
565 * CoRegisterMallocSpy [OLE32.@]
568 * if a mallocspy is already registered, we can't do it again since
569 * only the spy knows, how to free a memory block
571 HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy)
574 HRESULT hres = E_INVALIDARG;
578 /* HACK TO ACTIVATE OUT SPY */
579 if (pMallocSpy == (LPVOID)-1) pMallocSpy =(IMallocSpy*)&MallocSpy;
581 if(Malloc32.pSpy) return CO_E_OBJISREG;
583 EnterCriticalSection(&IMalloc32_SpyCS);
585 if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy, &IID_IMallocSpy, (LPVOID*)&pSpy))) {
586 Malloc32.pSpy = pSpy;
590 LeaveCriticalSection(&IMalloc32_SpyCS);
595 /***********************************************************************
596 * CoRevokeMallocSpy [OLE32.@]
599 * we can't revoke a malloc spy as long as memory blocks allocated with
600 * the spy are active since only the spy knows how to free them
602 HRESULT WINAPI CoRevokeMallocSpy(void)
607 EnterCriticalSection(&IMalloc32_SpyCS);
609 /* if it's our spy it's time to dump the leaks */
610 if (Malloc32.pSpy == (IMallocSpy*)&MallocSpy) {
611 MallocSpyDumpLeaks();
614 if (Malloc32.SpyedAllocationsLeft) {
615 TRACE("SpyReleasePending with %lu allocations left\n", Malloc32.SpyedAllocationsLeft);
616 Malloc32.SpyReleasePending = TRUE;
617 hres = E_ACCESSDENIED;
619 IMallocSpy_Release(Malloc32.pSpy);
620 Malloc32.pSpy = NULL;
622 LeaveCriticalSection(&IMalloc32_SpyCS);
627 /******************************************************************************
628 * IsValidInterface [OLE32.@]
631 * True, if the passed pointer is a valid interface
633 BOOL WINAPI IsValidInterface(
634 LPUNKNOWN punk /* [in] interface to be tested */
637 IsBadReadPtr(punk,4) ||
638 IsBadReadPtr(punk->lpVtbl,4) ||
639 IsBadReadPtr(punk->lpVtbl->QueryInterface,9) ||
640 IsBadCodePtr((FARPROC)punk->lpVtbl->QueryInterface)