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
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;
65 static CRITICAL_SECTION_DEBUG critsect_debug =
67 0, 0, &IMalloc32_SpyCS,
68 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
69 0, 0, { 0, (DWORD)(__FILE__ ": IMalloc32_SpyCS") }
71 static CRITICAL_SECTION IMalloc32_SpyCS = { &critsect_debug, -1, 0, 0, 0, 0 };
73 /* resize the old table */
74 static int SetSpyedBlockTableLength ( int NewLength )
76 if (!Malloc32.SpyedBlocks) Malloc32.SpyedBlocks = (LPVOID*)LocalAlloc(NewLength, GMEM_ZEROINIT);
77 else Malloc32.SpyedBlocks = (LPVOID*)LocalReAlloc((HLOCAL)Malloc32.SpyedBlocks, NewLength, GMEM_ZEROINIT);
78 Malloc32.SpyedBlockTableLength = NewLength;
79 return Malloc32.SpyedBlocks ? 1 : 0;
82 /* add a location to the table */
83 static int AddMemoryLocation(LPVOID * pMem)
87 /* allocate the table if not already allocated */
88 if (!Malloc32.SpyedBlockTableLength) {
89 if (!SetSpyedBlockTableLength(0x1000)) return 0;
92 /* find a free location */
93 Current = Malloc32.SpyedBlocks;
96 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) {
97 /* no more space in table, grow it */
98 if (!SetSpyedBlockTableLength( Malloc32.SpyedBlockTableLength + 0x1000 )) return 0;
102 /* put the location in our table */
104 Malloc32.SpyedAllocationsLeft++;
105 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
109 static int RemoveMemoryLocation(LPVOID * pMem)
111 LPVOID * Current = Malloc32.SpyedBlocks;
113 /* find the location */
114 while (*Current != pMem) {
116 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) return 0; /* not found */
120 Malloc32.SpyedAllocationsLeft--;
121 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
126 /******************************************************************************
127 * IMalloc32_QueryInterface [VTABLE]
129 static HRESULT WINAPI IMalloc_fnQueryInterface(LPMALLOC iface,REFIID refiid,LPVOID *obj) {
131 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
133 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMalloc,refiid)) {
134 *obj = (LPMALLOC)&Malloc32;
137 return E_NOINTERFACE;
140 /******************************************************************************
141 * IMalloc32_AddRefRelease [VTABLE]
143 static ULONG WINAPI IMalloc_fnAddRefRelease (LPMALLOC iface) {
147 /******************************************************************************
148 * IMalloc32_Alloc [VTABLE]
150 static LPVOID WINAPI IMalloc_fnAlloc(LPMALLOC iface, DWORD cb) {
157 DWORD preAllocResult;
159 EnterCriticalSection(&IMalloc32_SpyCS);
160 preAllocResult = IMallocSpy_PreAlloc(Malloc32.pSpy, cb);
161 if ((cb != 0) && (preAllocResult == 0)) {
162 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
163 TRACE("returning null\n");
164 LeaveCriticalSection(&IMalloc32_SpyCS);
169 addr = HeapAlloc(GetProcessHeap(),0,cb);
172 addr = IMallocSpy_PostAlloc(Malloc32.pSpy, addr);
173 if (addr) AddMemoryLocation(addr);
174 LeaveCriticalSection(&IMalloc32_SpyCS);
177 TRACE("--(%p)\n",addr);
181 /******************************************************************************
182 * IMalloc32_Realloc [VTABLE]
184 static LPVOID WINAPI IMalloc_fnRealloc(LPMALLOC iface,LPVOID pv,DWORD cb) {
188 TRACE("(%p,%ld)\n",pv,cb);
194 EnterCriticalSection(&IMalloc32_SpyCS);
195 fSpyed = RemoveMemoryLocation(pv);
196 cb = IMallocSpy_PreRealloc(Malloc32.pSpy, pv, cb, &pRealMemory, fSpyed);
198 /* check if can release the spy */
199 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
200 IMallocSpy_Release(Malloc32.pSpy);
201 Malloc32.SpyReleasePending = FALSE;
202 Malloc32.pSpy = NULL;
206 /* PreRealloc can force Realloc to fail */
207 LeaveCriticalSection(&IMalloc32_SpyCS);
213 if (!pv) pNewMemory = HeapAlloc(GetProcessHeap(),0,cb);
214 else if (cb) pNewMemory = HeapReAlloc(GetProcessHeap(),0,pv,cb);
216 HeapFree(GetProcessHeap(),0,pv);
221 pNewMemory = IMallocSpy_PostRealloc(Malloc32.pSpy, pNewMemory, TRUE);
222 if (pNewMemory) AddMemoryLocation(pNewMemory);
223 LeaveCriticalSection(&IMalloc32_SpyCS);
226 TRACE("--(%p)\n",pNewMemory);
230 /******************************************************************************
231 * IMalloc32_Free [VTABLE]
233 static VOID WINAPI IMalloc_fnFree(LPMALLOC iface,LPVOID pv) {
240 EnterCriticalSection(&IMalloc32_SpyCS);
241 fSpyed = RemoveMemoryLocation(pv);
242 pv = IMallocSpy_PreFree(Malloc32.pSpy, pv, fSpyed);
245 HeapFree(GetProcessHeap(),0,pv);
248 IMallocSpy_PostFree(Malloc32.pSpy, fSpyed);
250 /* check if can release the spy */
251 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
252 IMallocSpy_Release(Malloc32.pSpy);
253 Malloc32.SpyReleasePending = FALSE;
254 Malloc32.pSpy = NULL;
257 LeaveCriticalSection(&IMalloc32_SpyCS);
261 /******************************************************************************
262 * IMalloc32_GetSize [VTABLE]
266 * win95: size allocated (4 byte boundarys)
267 * win2k: size originally requested !!! (allocated on 8 byte boundarys)
269 static DWORD WINAPI IMalloc_fnGetSize(LPMALLOC iface,LPVOID pv) {
277 EnterCriticalSection(&IMalloc32_SpyCS);
278 pv = IMallocSpy_PreGetSize(Malloc32.pSpy, pv, fSpyed);
281 cb = HeapSize(GetProcessHeap(),0,pv);
284 cb = IMallocSpy_PostGetSize(Malloc32.pSpy, cb, fSpyed);
285 LeaveCriticalSection(&IMalloc32_SpyCS);
291 /******************************************************************************
292 * IMalloc32_DidAlloc [VTABLE]
294 static INT WINAPI IMalloc_fnDidAlloc(LPMALLOC iface,LPVOID pv) {
302 EnterCriticalSection(&IMalloc32_SpyCS);
303 pv = IMallocSpy_PreDidAlloc(Malloc32.pSpy, pv, fSpyed);
309 didAlloc = IMallocSpy_PostDidAlloc(Malloc32.pSpy, pv, fSpyed, didAlloc);
310 LeaveCriticalSection(&IMalloc32_SpyCS);
315 /******************************************************************************
316 * IMalloc32_HeapMinimize [VTABLE]
318 static VOID WINAPI IMalloc_fnHeapMinimize(LPMALLOC iface) {
322 EnterCriticalSection(&IMalloc32_SpyCS);
323 IMallocSpy_PreHeapMinimize(Malloc32.pSpy);
327 IMallocSpy_PostHeapMinimize(Malloc32.pSpy);
328 LeaveCriticalSection(&IMalloc32_SpyCS);
332 static ICOM_VTABLE(IMalloc) VT_IMalloc32 =
334 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
335 IMalloc_fnQueryInterface,
336 IMalloc_fnAddRefRelease,
337 IMalloc_fnAddRefRelease,
343 IMalloc_fnHeapMinimize
346 /******************************************************************************
347 * IMallocSpy implementation
348 *****************************************************************************/
350 /* set the vtable later */
351 extern ICOM_VTABLE(IMallocSpy) VT_IMallocSpy;
354 ICOM_VFIELD(IMallocSpy);
358 /* this is the static object instance */
359 _MallocSpy MallocSpy = {&VT_IMallocSpy, 0};
361 /******************************************************************************
362 * IMalloc32_QueryInterface [VTABLE]
364 static HRESULT WINAPI IMallocSpy_fnQueryInterface(LPMALLOCSPY iface,REFIID refiid,LPVOID *obj)
367 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
369 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMallocSpy,refiid)) {
370 *obj = (LPMALLOC)&MallocSpy;
373 return E_NOINTERFACE;
376 /******************************************************************************
377 * IMalloc32_AddRef [VTABLE]
379 static ULONG WINAPI IMallocSpy_fnAddRef (LPMALLOCSPY iface)
382 ICOM_THIS (_MallocSpy, iface);
384 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
386 return ++(This->ref);
389 /******************************************************************************
390 * IMalloc32_AddRelease [VTABLE]
393 * Our MallocSpy is static. If the count reaches 0 we dump the leaks
395 static ULONG WINAPI IMallocSpy_fnRelease (LPMALLOCSPY iface)
398 ICOM_THIS (_MallocSpy, iface);
400 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
402 if (!--(This->ref)) {
403 /* our allocation list MUST be empty here */
408 static ULONG WINAPI IMallocSpy_fnPreAlloc(LPMALLOCSPY iface, ULONG cbRequest)
410 ICOM_THIS (_MallocSpy, iface);
411 TRACE ("(%p)->(%lu)\n", This, cbRequest);
414 static PVOID WINAPI IMallocSpy_fnPostAlloc(LPMALLOCSPY iface, void* pActual)
416 ICOM_THIS (_MallocSpy, iface);
417 TRACE ("(%p)->(%p)\n", This, pActual);
421 static PVOID WINAPI IMallocSpy_fnPreFree(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
423 ICOM_THIS (_MallocSpy, iface);
424 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
427 static void WINAPI IMallocSpy_fnPostFree(LPMALLOCSPY iface, BOOL fSpyed)
429 ICOM_THIS (_MallocSpy, iface);
430 TRACE ("(%p)->(%u)\n", This, fSpyed);
433 static ULONG WINAPI IMallocSpy_fnPreRealloc(LPMALLOCSPY iface, void* pRequest, ULONG cbRequest, void** ppNewRequest, BOOL fSpyed)
435 ICOM_THIS (_MallocSpy, iface);
436 TRACE ("(%p)->(%p %lu %u)\n", This, pRequest, cbRequest, fSpyed);
437 *ppNewRequest = pRequest;
441 static PVOID WINAPI IMallocSpy_fnPostRealloc(LPMALLOCSPY iface, void* pActual, BOOL fSpyed)
443 ICOM_THIS (_MallocSpy, iface);
444 TRACE ("(%p)->(%p %u)\n", This, pActual, fSpyed);
448 static PVOID WINAPI IMallocSpy_fnPreGetSize(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
450 ICOM_THIS (_MallocSpy, iface);
451 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
455 static ULONG WINAPI IMallocSpy_fnPostGetSize(LPMALLOCSPY iface, ULONG cbActual, BOOL fSpyed)
457 ICOM_THIS (_MallocSpy, iface);
458 TRACE ("(%p)->(%lu %u)\n", This, cbActual, fSpyed);
462 static PVOID WINAPI IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
464 ICOM_THIS (_MallocSpy, iface);
465 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
469 static int WINAPI IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed, int fActual)
471 ICOM_THIS (_MallocSpy, iface);
472 TRACE ("(%p)->(%p %u %u)\n", This, pRequest, fSpyed, fActual);
476 static void WINAPI IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface)
478 ICOM_THIS (_MallocSpy, iface);
479 TRACE ("(%p)->()\n", This);
482 static void WINAPI IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface)
484 ICOM_THIS (_MallocSpy, iface);
485 TRACE ("(%p)->()\n", This);
488 static void MallocSpyDumpLeaks() {
489 TRACE("leaks: %lu\n", Malloc32.SpyedAllocationsLeft);
492 static ICOM_VTABLE(IMallocSpy) VT_IMallocSpy =
494 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
495 IMallocSpy_fnQueryInterface,
497 IMallocSpy_fnRelease,
498 IMallocSpy_fnPreAlloc,
499 IMallocSpy_fnPostAlloc,
500 IMallocSpy_fnPreFree,
501 IMallocSpy_fnPostFree,
502 IMallocSpy_fnPreRealloc,
503 IMallocSpy_fnPostRealloc,
504 IMallocSpy_fnPreGetSize,
505 IMallocSpy_fnPostGetSize,
506 IMallocSpy_fnPreDidAlloc,
507 IMallocSpy_fnPostDidAlloc,
508 IMallocSpy_fnPreHeapMinimize,
509 IMallocSpy_fnPostHeapMinimize
512 /******************************************************************************
513 * CoGetMalloc [OLE32.@]
518 HRESULT WINAPI CoGetMalloc(DWORD dwMemContext, LPMALLOC *lpMalloc)
520 *lpMalloc = (LPMALLOC)&Malloc32;
524 /***********************************************************************
525 * CoTaskMemAlloc [OLE32.@]
527 * pointer to newly allocated block
529 LPVOID WINAPI CoTaskMemAlloc(ULONG size)
531 return IMalloc_Alloc((LPMALLOC)&Malloc32,size);
533 /***********************************************************************
534 * CoTaskMemFree [OLE32.@]
536 VOID WINAPI CoTaskMemFree(LPVOID ptr)
538 IMalloc_Free((LPMALLOC)&Malloc32, ptr);
541 /***********************************************************************
542 * CoTaskMemRealloc [OLE32.@]
544 * pointer to newly allocated block
546 LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, ULONG size)
548 return IMalloc_Realloc((LPMALLOC)&Malloc32, pvOld, size);
551 /***********************************************************************
552 * CoRegisterMallocSpy [OLE32.@]
555 * if a mallocspy is already registered, we cant do it again since
556 * only the spy knows, how to free a memory block
558 HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy)
561 HRESULT hres = E_INVALIDARG;
565 /* HACK TO ACTIVATE OUT SPY */
566 if (pMallocSpy == (LPVOID)-1) pMallocSpy =(IMallocSpy*)&MallocSpy;
568 if(Malloc32.pSpy) return CO_E_OBJISREG;
570 EnterCriticalSection(&IMalloc32_SpyCS);
572 if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy, &IID_IMallocSpy, (LPVOID*)&pSpy))) {
573 Malloc32.pSpy = pSpy;
577 LeaveCriticalSection(&IMalloc32_SpyCS);
582 /***********************************************************************
583 * CoRevokeMallocSpy [OLE32.@]
586 * we can't rewoke a malloc spy as long as memory blocks allocated with
587 * the spy are active since only the spy knows how to free them
589 HRESULT WINAPI CoRevokeMallocSpy(void)
594 EnterCriticalSection(&IMalloc32_SpyCS);
596 /* if it's our spy it's time to dump the leaks */
597 if (Malloc32.pSpy == (IMallocSpy*)&MallocSpy) {
598 MallocSpyDumpLeaks();
601 if (Malloc32.SpyedAllocationsLeft) {
602 TRACE("SpyReleasePending with %lu allocations left\n", Malloc32.SpyedAllocationsLeft);
603 Malloc32.SpyReleasePending = TRUE;
604 hres = E_ACCESSDENIED;
606 IMallocSpy_Release(Malloc32.pSpy);
607 Malloc32.pSpy = NULL;
609 LeaveCriticalSection(&IMalloc32_SpyCS);
614 /******************************************************************************
615 * IsValidInterface [OLE32.@]
618 * True, if the passed pointer is a valid interface
620 BOOL WINAPI IsValidInterface(
621 LPUNKNOWN punk /* [in] interface to be tested */
624 IsBadReadPtr(punk,4) ||
625 IsBadReadPtr(punk->lpVtbl,4) ||
626 IsBadReadPtr(punk->lpVtbl->QueryInterface,9) ||
627 IsBadCodePtr((FARPROC)punk->lpVtbl->QueryInterface)