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
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(ole);
38 /******************************************************************************
39 * IMalloc32 implementation
42 * For supporting CoRegisterMallocSpy the IMalloc implementation must know if
43 * a given memory block was allocated with a spy active.
45 *****************************************************************************/
46 /* set the vtable later */
47 extern ICOM_VTABLE(IMalloc) VT_IMalloc32;
51 DWORD dummy; /* nothing, we are static */
52 IMallocSpy * pSpy; /* the spy when active */
53 DWORD SpyedAllocationsLeft; /* number of spyed allocations left */
54 BOOL SpyReleasePending; /* CoRevokeMallocSpy called with spyed allocations left*/
55 LPVOID * SpyedBlocks; /* root of the table */
56 int SpyedBlockTableLength; /* size of the table*/
59 /* this is the static object instance */
60 _Malloc32 Malloc32 = {&VT_IMalloc32, 0, NULL, 0, 0, NULL, 0};
62 /* with a spy active all calls from pre to post methods are threadsave */
63 static CRITICAL_SECTION IMalloc32_SpyCS;
64 static CRITICAL_SECTION_DEBUG critsect_debug =
66 0, 0, &IMalloc32_SpyCS,
67 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
68 0, 0, { 0, (DWORD)(__FILE__ ": IMalloc32_SpyCS") }
70 static CRITICAL_SECTION IMalloc32_SpyCS = { &critsect_debug, -1, 0, 0, 0, 0 };
72 /* resize the old table */
73 static int SetSpyedBlockTableLength ( int NewLength )
75 Malloc32.SpyedBlocks = (LPVOID*)LocalReAlloc((HLOCAL)Malloc32.SpyedBlocks, NewLength, GMEM_ZEROINIT);
76 Malloc32.SpyedBlockTableLength = NewLength;
77 return Malloc32.SpyedBlocks ? 1 : 0;
80 /* add a location to the table */
81 static int AddMemoryLocation(LPVOID * pMem)
85 /* allocate the table if not already allocated */
86 if (!Malloc32.SpyedBlockTableLength) {
87 if (!SetSpyedBlockTableLength(0x1000)) return 0;
90 /* find a free location */
91 Current = Malloc32.SpyedBlocks;
94 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) {
95 /* no more space in table, grow it */
96 if (!SetSpyedBlockTableLength( Malloc32.SpyedBlockTableLength + 0x1000 )) return 0;
100 /* put the location in our table */
102 Malloc32.SpyedAllocationsLeft++;
103 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
107 static int RemoveMemoryLocation(LPVOID * pMem)
109 LPVOID * Current = Malloc32.SpyedBlocks;
111 /* find the location */
112 while (*Current != pMem) {
114 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) return 0; /* not found */
118 Malloc32.SpyedAllocationsLeft--;
119 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
124 /******************************************************************************
125 * IMalloc32_QueryInterface [VTABLE]
127 static HRESULT WINAPI IMalloc_fnQueryInterface(LPMALLOC iface,REFIID refiid,LPVOID *obj) {
129 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
131 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMalloc,refiid)) {
132 *obj = (LPMALLOC)&Malloc32;
135 return E_NOINTERFACE;
138 /******************************************************************************
139 * IMalloc32_AddRefRelease [VTABLE]
141 static ULONG WINAPI IMalloc_fnAddRefRelease (LPMALLOC iface) {
145 /******************************************************************************
146 * IMalloc32_Alloc [VTABLE]
148 static LPVOID WINAPI IMalloc_fnAlloc(LPMALLOC iface, DWORD cb) {
155 DWORD preAllocResult;
157 EnterCriticalSection(&IMalloc32_SpyCS);
158 preAllocResult = IMallocSpy_PreAlloc(Malloc32.pSpy, cb);
159 if ((cb != 0) && (preAllocResult == 0)) {
160 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
161 TRACE("returning null\n");
162 LeaveCriticalSection(&IMalloc32_SpyCS);
167 addr = HeapAlloc(GetProcessHeap(),0,cb);
170 addr = IMallocSpy_PostAlloc(Malloc32.pSpy, addr);
171 if (addr) AddMemoryLocation(addr);
172 LeaveCriticalSection(&IMalloc32_SpyCS);
175 TRACE("--(%p)\n",addr);
179 /******************************************************************************
180 * IMalloc32_Realloc [VTABLE]
182 static LPVOID WINAPI IMalloc_fnRealloc(LPMALLOC iface,LPVOID pv,DWORD cb) {
186 TRACE("(%p,%ld)\n",pv,cb);
192 EnterCriticalSection(&IMalloc32_SpyCS);
193 fSpyed = RemoveMemoryLocation(pv);
194 cb = IMallocSpy_PreRealloc(Malloc32.pSpy, pv, cb, &pRealMemory, fSpyed);
196 /* check if can release the spy */
197 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
198 IMallocSpy_Release(Malloc32.pSpy);
199 Malloc32.SpyReleasePending = FALSE;
200 Malloc32.pSpy = NULL;
204 /* PreRealloc can force Realloc to fail */
205 LeaveCriticalSection(&IMalloc32_SpyCS);
211 pNewMemory = HeapReAlloc(GetProcessHeap(),0,pv,cb);
214 pNewMemory = IMallocSpy_PostRealloc(Malloc32.pSpy, pNewMemory, TRUE);
215 if (pNewMemory) AddMemoryLocation(pNewMemory);
216 LeaveCriticalSection(&IMalloc32_SpyCS);
219 TRACE("--(%p)\n",pNewMemory);
223 /******************************************************************************
224 * IMalloc32_Free [VTABLE]
226 static VOID WINAPI IMalloc_fnFree(LPMALLOC iface,LPVOID pv) {
233 EnterCriticalSection(&IMalloc32_SpyCS);
234 fSpyed = RemoveMemoryLocation(pv);
235 pv = IMallocSpy_PreFree(Malloc32.pSpy, pv, fSpyed);
238 HeapFree(GetProcessHeap(),0,pv);
241 IMallocSpy_PostFree(Malloc32.pSpy, fSpyed);
243 /* check if can release the spy */
244 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
245 IMallocSpy_Release(Malloc32.pSpy);
246 Malloc32.SpyReleasePending = FALSE;
247 Malloc32.pSpy = NULL;
250 LeaveCriticalSection(&IMalloc32_SpyCS);
254 /******************************************************************************
255 * IMalloc32_GetSize [VTABLE]
259 * win95: size allocated (4 byte boundarys)
260 * win2k: size originally requested !!! (allocated on 8 byte boundarys)
262 static DWORD WINAPI IMalloc_fnGetSize(LPMALLOC iface,LPVOID pv) {
270 EnterCriticalSection(&IMalloc32_SpyCS);
271 pv = IMallocSpy_PreGetSize(Malloc32.pSpy, pv, fSpyed);
274 cb = HeapSize(GetProcessHeap(),0,pv);
277 cb = IMallocSpy_PostGetSize(Malloc32.pSpy, cb, fSpyed);
278 LeaveCriticalSection(&IMalloc32_SpyCS);
284 /******************************************************************************
285 * IMalloc32_DidAlloc [VTABLE]
287 static INT WINAPI IMalloc_fnDidAlloc(LPMALLOC iface,LPVOID pv) {
295 EnterCriticalSection(&IMalloc32_SpyCS);
296 pv = IMallocSpy_PreDidAlloc(Malloc32.pSpy, pv, fSpyed);
302 didAlloc = IMallocSpy_PostDidAlloc(Malloc32.pSpy, pv, fSpyed, didAlloc);
303 LeaveCriticalSection(&IMalloc32_SpyCS);
308 /******************************************************************************
309 * IMalloc32_HeapMinimize [VTABLE]
311 static VOID WINAPI IMalloc_fnHeapMinimize(LPMALLOC iface) {
315 EnterCriticalSection(&IMalloc32_SpyCS);
316 IMallocSpy_PreHeapMinimize(Malloc32.pSpy);
320 IMallocSpy_PostHeapMinimize(Malloc32.pSpy);
321 LeaveCriticalSection(&IMalloc32_SpyCS);
325 static ICOM_VTABLE(IMalloc) VT_IMalloc32 =
327 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
328 IMalloc_fnQueryInterface,
329 IMalloc_fnAddRefRelease,
330 IMalloc_fnAddRefRelease,
336 IMalloc_fnHeapMinimize
339 /******************************************************************************
340 * IMallocSpy implementation
341 *****************************************************************************/
343 /* set the vtable later */
344 extern ICOM_VTABLE(IMallocSpy) VT_IMallocSpy;
347 ICOM_VFIELD(IMallocSpy);
351 /* this is the static object instance */
352 _MallocSpy MallocSpy = {&VT_IMallocSpy, 0};
354 /******************************************************************************
355 * IMalloc32_QueryInterface [VTABLE]
357 static HRESULT WINAPI IMallocSpy_fnQueryInterface(LPMALLOCSPY iface,REFIID refiid,LPVOID *obj)
360 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
362 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMallocSpy,refiid)) {
363 *obj = (LPMALLOC)&MallocSpy;
366 return E_NOINTERFACE;
369 /******************************************************************************
370 * IMalloc32_AddRef [VTABLE]
372 static ULONG WINAPI IMallocSpy_fnAddRef (LPMALLOCSPY iface)
375 ICOM_THIS (_MallocSpy, iface);
377 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
379 return ++(This->ref);
382 /******************************************************************************
383 * IMalloc32_AddRelease [VTABLE]
386 * Our MallocSpy is static. If the count reaches 0 we dump the leaks
388 static ULONG WINAPI IMallocSpy_fnRelease (LPMALLOCSPY iface)
391 ICOM_THIS (_MallocSpy, iface);
393 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
395 if (!--(This->ref)) {
396 /* our allocation list MUST be empty here */
401 static ULONG WINAPI IMallocSpy_fnPreAlloc(LPMALLOCSPY iface, ULONG cbRequest)
403 ICOM_THIS (_MallocSpy, iface);
404 TRACE ("(%p)->(%lu)\n", This, cbRequest);
407 static PVOID WINAPI IMallocSpy_fnPostAlloc(LPMALLOCSPY iface, void* pActual)
409 ICOM_THIS (_MallocSpy, iface);
410 TRACE ("(%p)->(%p)\n", This, pActual);
414 static PVOID WINAPI IMallocSpy_fnPreFree(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
416 ICOM_THIS (_MallocSpy, iface);
417 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
420 static void WINAPI IMallocSpy_fnPostFree(LPMALLOCSPY iface, BOOL fSpyed)
422 ICOM_THIS (_MallocSpy, iface);
423 TRACE ("(%p)->(%u)\n", This, fSpyed);
426 static ULONG WINAPI IMallocSpy_fnPreRealloc(LPMALLOCSPY iface, void* pRequest, ULONG cbRequest, void** ppNewRequest, BOOL fSpyed)
428 ICOM_THIS (_MallocSpy, iface);
429 TRACE ("(%p)->(%p %lu %u)\n", This, pRequest, cbRequest, fSpyed);
430 *ppNewRequest = pRequest;
434 static PVOID WINAPI IMallocSpy_fnPostRealloc(LPMALLOCSPY iface, void* pActual, BOOL fSpyed)
436 ICOM_THIS (_MallocSpy, iface);
437 TRACE ("(%p)->(%p %u)\n", This, pActual, fSpyed);
441 static PVOID WINAPI IMallocSpy_fnPreGetSize(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
443 ICOM_THIS (_MallocSpy, iface);
444 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
448 static ULONG WINAPI IMallocSpy_fnPostGetSize(LPMALLOCSPY iface, ULONG cbActual, BOOL fSpyed)
450 ICOM_THIS (_MallocSpy, iface);
451 TRACE ("(%p)->(%lu %u)\n", This, cbActual, fSpyed);
455 static PVOID WINAPI IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
457 ICOM_THIS (_MallocSpy, iface);
458 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
462 static int WINAPI IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed, int fActual)
464 ICOM_THIS (_MallocSpy, iface);
465 TRACE ("(%p)->(%p %u %u)\n", This, pRequest, fSpyed, fActual);
469 static void WINAPI IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface)
471 ICOM_THIS (_MallocSpy, iface);
472 TRACE ("(%p)->()\n", This);
475 static void WINAPI IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface)
477 ICOM_THIS (_MallocSpy, iface);
478 TRACE ("(%p)->()\n", This);
481 static void MallocSpyDumpLeaks() {
482 TRACE("leaks: %lu\n", Malloc32.SpyedAllocationsLeft);
485 static ICOM_VTABLE(IMallocSpy) VT_IMallocSpy =
487 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
488 IMallocSpy_fnQueryInterface,
490 IMallocSpy_fnRelease,
491 IMallocSpy_fnPreAlloc,
492 IMallocSpy_fnPostAlloc,
493 IMallocSpy_fnPreFree,
494 IMallocSpy_fnPostFree,
495 IMallocSpy_fnPreRealloc,
496 IMallocSpy_fnPostRealloc,
497 IMallocSpy_fnPreGetSize,
498 IMallocSpy_fnPostGetSize,
499 IMallocSpy_fnPreDidAlloc,
500 IMallocSpy_fnPostDidAlloc,
501 IMallocSpy_fnPreHeapMinimize,
502 IMallocSpy_fnPostHeapMinimize
505 /******************************************************************************
506 * CoGetMalloc [OLE32.20]
511 HRESULT WINAPI CoGetMalloc(DWORD dwMemContext, LPMALLOC *lpMalloc)
513 *lpMalloc = (LPMALLOC)&Malloc32;
517 /***********************************************************************
518 * CoTaskMemAlloc [OLE32.43]
520 * pointer to newly allocated block
522 LPVOID WINAPI CoTaskMemAlloc(ULONG size)
524 return IMalloc_Alloc((LPMALLOC)&Malloc32,size);
526 /***********************************************************************
527 * CoTaskMemFree [OLE32.44]
529 VOID WINAPI CoTaskMemFree(LPVOID ptr)
531 IMalloc_Free((LPMALLOC)&Malloc32, ptr);
534 /***********************************************************************
535 * CoTaskMemRealloc [OLE32.45]
537 * pointer to newly allocated block
539 LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, ULONG size)
541 return IMalloc_Realloc((LPMALLOC)&Malloc32, pvOld, size);
544 /***********************************************************************
545 * CoRegisterMallocSpy [OLE32.37]
548 * if a mallocspy is already registered, we cant do it again since
549 * only the spy knows, how to free a memory block
551 HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy)
554 HRESULT hres = E_INVALIDARG;
558 /* HACK TO ACTIVATE OUT SPY */
559 if (pMallocSpy == (LPVOID)-1) pMallocSpy =(IMallocSpy*)&MallocSpy;
561 if(Malloc32.pSpy) return CO_E_OBJISREG;
563 EnterCriticalSection(&IMalloc32_SpyCS);
565 if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy, &IID_IMallocSpy, (LPVOID*)&pSpy))) {
566 Malloc32.pSpy = pSpy;
570 LeaveCriticalSection(&IMalloc32_SpyCS);
575 /***********************************************************************
576 * CoRevokeMallocSpy [OLE32.41]
579 * we can't rewoke a malloc spy as long as memory blocks allocated with
580 * the spy are active since only the spy knows how to free them
582 HRESULT WINAPI CoRevokeMallocSpy(void)
587 EnterCriticalSection(&IMalloc32_SpyCS);
589 /* if it's our spy it's time to dump the leaks */
590 if (Malloc32.pSpy == (IMallocSpy*)&MallocSpy) {
591 MallocSpyDumpLeaks();
594 if (Malloc32.SpyedAllocationsLeft) {
595 TRACE("SpyReleasePending with %lu allocations left\n", Malloc32.SpyedAllocationsLeft);
596 Malloc32.SpyReleasePending = TRUE;
597 hres = E_ACCESSDENIED;
599 IMallocSpy_Release(Malloc32.pSpy);
600 Malloc32.pSpy = NULL;
602 LeaveCriticalSection(&IMalloc32_SpyCS);
607 /******************************************************************************
608 * IsValidInterface [OLE32.78]
611 * True, if the passed pointer is a valid interface
613 BOOL WINAPI IsValidInterface(
614 LPUNKNOWN punk /* [in] interface to be tested */
617 IsBadReadPtr(punk,4) ||
618 IsBadReadPtr(punk->lpVtbl,4) ||
619 IsBadReadPtr(punk->lpVtbl->QueryInterface,9) ||
620 IsBadCodePtr((FARPROC)punk->lpVtbl->QueryInterface)