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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 const IMallocVtbl VT_IMalloc32
;
53 IMalloc IMalloc_iface
;
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 DWORD SpyedBlockTableLength
;/* size of the table*/
62 /* this is the static object instance */
63 static _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, { (DWORD_PTR
)(__FILE__
": IMalloc32_SpyCS") }
73 static CRITICAL_SECTION IMalloc32_SpyCS
= { &critsect_debug
, -1, 0, 0, 0, 0 };
75 /* resize the old table */
76 static BOOL
SetSpyedBlockTableLength ( DWORD NewLength
)
78 LPVOID
*NewSpyedBlocks
;
80 if (!Malloc32
.SpyedBlocks
) NewSpyedBlocks
= LocalAlloc(LMEM_ZEROINIT
, NewLength
* sizeof(PVOID
));
81 else NewSpyedBlocks
= LocalReAlloc(Malloc32
.SpyedBlocks
, NewLength
* sizeof(PVOID
), LMEM_ZEROINIT
| LMEM_MOVEABLE
);
83 Malloc32
.SpyedBlocks
= NewSpyedBlocks
;
84 Malloc32
.SpyedBlockTableLength
= NewLength
;
87 return NewSpyedBlocks
!= NULL
;
90 /* add a location to the table */
91 static BOOL
AddMemoryLocation(LPVOID
* pMem
)
95 /* allocate the table if not already allocated */
96 if (!Malloc32
.SpyedBlockTableLength
&& !SetSpyedBlockTableLength(0x1000))
99 /* find a free location */
100 Current
= Malloc32
.SpyedBlocks
;
103 if (Current
>= Malloc32
.SpyedBlocks
+ Malloc32
.SpyedBlockTableLength
) {
104 /* no more space in table, grow it */
105 DWORD old_length
= Malloc32
.SpyedBlockTableLength
;
106 if (!SetSpyedBlockTableLength( Malloc32
.SpyedBlockTableLength
+ 0x1000))
108 Current
= Malloc32
.SpyedBlocks
+ old_length
;
112 /* put the location in our table */
114 Malloc32
.SpyedAllocationsLeft
++;
115 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
119 static BOOL
RemoveMemoryLocation(LPCVOID pMem
)
123 /* allocate the table if not already allocated */
124 if (!Malloc32
.SpyedBlockTableLength
&& !SetSpyedBlockTableLength(0x1000))
127 Current
= Malloc32
.SpyedBlocks
;
129 /* find the location */
130 while (*Current
!= pMem
) {
132 if (Current
>= Malloc32
.SpyedBlocks
+ Malloc32
.SpyedBlockTableLength
)
133 return FALSE
; /* not found */
137 Malloc32
.SpyedAllocationsLeft
--;
138 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
143 /******************************************************************************
144 * IMalloc32_QueryInterface [VTABLE]
146 static HRESULT WINAPI
IMalloc_fnQueryInterface(IMalloc
*iface
, REFIID refiid
, void **obj
)
148 TRACE("(%s,%p)\n",debugstr_guid(refiid
),obj
);
150 if (IsEqualIID(&IID_IUnknown
,refiid
) || IsEqualIID(&IID_IMalloc
,refiid
)) {
154 return E_NOINTERFACE
;
157 /******************************************************************************
158 * IMalloc32_AddRefRelease [VTABLE]
160 static ULONG WINAPI
IMalloc_fnAddRefRelease(IMalloc
*iface
)
165 /******************************************************************************
166 * IMalloc32_Alloc [VTABLE]
168 static void * WINAPI
IMalloc_fnAlloc(IMalloc
*iface
, SIZE_T cb
)
175 SIZE_T preAllocResult
;
177 EnterCriticalSection(&IMalloc32_SpyCS
);
178 preAllocResult
= IMallocSpy_PreAlloc(Malloc32
.pSpy
, cb
);
179 if ((cb
!= 0) && (preAllocResult
== 0)) {
180 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
181 TRACE("returning null\n");
182 LeaveCriticalSection(&IMalloc32_SpyCS
);
187 addr
= HeapAlloc(GetProcessHeap(),0,cb
);
190 addr
= IMallocSpy_PostAlloc(Malloc32
.pSpy
, addr
);
191 if (addr
) AddMemoryLocation(addr
);
192 LeaveCriticalSection(&IMalloc32_SpyCS
);
195 TRACE("--(%p)\n",addr
);
199 /******************************************************************************
200 * IMalloc32_Realloc [VTABLE]
202 static void * WINAPI
IMalloc_fnRealloc(IMalloc
*iface
, void *pv
, SIZE_T cb
)
206 TRACE("(%p,%ld)\n",pv
,cb
);
212 EnterCriticalSection(&IMalloc32_SpyCS
);
213 fSpyed
= RemoveMemoryLocation(pv
);
214 cb
= IMallocSpy_PreRealloc(Malloc32
.pSpy
, pv
, cb
, &pRealMemory
, fSpyed
);
216 /* check if can release the spy */
217 if(Malloc32
.SpyReleasePending
&& !Malloc32
.SpyedAllocationsLeft
) {
218 IMallocSpy_Release(Malloc32
.pSpy
);
219 Malloc32
.SpyReleasePending
= FALSE
;
220 Malloc32
.pSpy
= NULL
;
221 LeaveCriticalSection(&IMalloc32_SpyCS
);
225 /* PreRealloc can force Realloc to fail */
227 LeaveCriticalSection(&IMalloc32_SpyCS
);
234 if (!pv
) pNewMemory
= HeapAlloc(GetProcessHeap(),0,cb
);
235 else if (cb
) pNewMemory
= HeapReAlloc(GetProcessHeap(),0,pv
,cb
);
237 HeapFree(GetProcessHeap(),0,pv
);
242 pNewMemory
= IMallocSpy_PostRealloc(Malloc32
.pSpy
, pNewMemory
, TRUE
);
243 if (pNewMemory
) AddMemoryLocation(pNewMemory
);
244 LeaveCriticalSection(&IMalloc32_SpyCS
);
247 TRACE("--(%p)\n",pNewMemory
);
251 /******************************************************************************
252 * IMalloc32_Free [VTABLE]
254 static void WINAPI
IMalloc_fnFree(IMalloc
*iface
, void *pv
)
264 EnterCriticalSection(&IMalloc32_SpyCS
);
265 fSpyed
= RemoveMemoryLocation(pv
);
266 pv
= IMallocSpy_PreFree(Malloc32
.pSpy
, pv
, fSpyed
);
269 HeapFree(GetProcessHeap(),0,pv
);
272 IMallocSpy_PostFree(Malloc32
.pSpy
, fSpyed
);
274 /* check if can release the spy */
275 if(Malloc32
.SpyReleasePending
&& !Malloc32
.SpyedAllocationsLeft
) {
276 IMallocSpy_Release(Malloc32
.pSpy
);
277 Malloc32
.SpyReleasePending
= FALSE
;
278 Malloc32
.pSpy
= NULL
;
281 LeaveCriticalSection(&IMalloc32_SpyCS
);
285 /******************************************************************************
286 * IMalloc32_GetSize [VTABLE]
290 * win95: size allocated (4 byte boundarys)
291 * win2k: size originally requested !!! (allocated on 8 byte boundarys)
293 static SIZE_T WINAPI
IMalloc_fnGetSize(IMalloc
*iface
, void *pv
)
301 EnterCriticalSection(&IMalloc32_SpyCS
);
302 pv
= IMallocSpy_PreGetSize(Malloc32
.pSpy
, pv
, fSpyed
);
305 cb
= HeapSize(GetProcessHeap(),0,pv
);
308 cb
= IMallocSpy_PostGetSize(Malloc32
.pSpy
, cb
, fSpyed
);
309 LeaveCriticalSection(&IMalloc32_SpyCS
);
315 /******************************************************************************
316 * IMalloc32_DidAlloc [VTABLE]
318 static INT WINAPI
IMalloc_fnDidAlloc(IMalloc
*iface
, void *pv
)
326 EnterCriticalSection(&IMalloc32_SpyCS
);
327 pv
= IMallocSpy_PreDidAlloc(Malloc32
.pSpy
, pv
, fSpyed
);
333 didAlloc
= IMallocSpy_PostDidAlloc(Malloc32
.pSpy
, pv
, fSpyed
, didAlloc
);
334 LeaveCriticalSection(&IMalloc32_SpyCS
);
339 /******************************************************************************
340 * IMalloc32_HeapMinimize [VTABLE]
342 static void WINAPI
IMalloc_fnHeapMinimize(IMalloc
*iface
)
347 EnterCriticalSection(&IMalloc32_SpyCS
);
348 IMallocSpy_PreHeapMinimize(Malloc32
.pSpy
);
352 IMallocSpy_PostHeapMinimize(Malloc32
.pSpy
);
353 LeaveCriticalSection(&IMalloc32_SpyCS
);
357 static const IMallocVtbl VT_IMalloc32
=
359 IMalloc_fnQueryInterface
,
360 IMalloc_fnAddRefRelease
,
361 IMalloc_fnAddRefRelease
,
367 IMalloc_fnHeapMinimize
370 /******************************************************************************
371 * CoGetMalloc [OLE32.@]
373 * Retrieves the current IMalloc interface for the process.
376 * context [I] Should always be MEMCTX_TASK.
377 * imalloc [O] Address where memory allocator object will be stored.
381 * Failure: HRESULT code.
383 HRESULT WINAPI
CoGetMalloc(DWORD context
, IMalloc
**imalloc
)
385 if (context
!= MEMCTX_TASK
) {
390 *imalloc
= &Malloc32
.IMalloc_iface
;
394 /***********************************************************************
395 * CoTaskMemAlloc [OLE32.@]
397 * Allocates memory using the current process memory allocator.
400 * size [I] Size of the memory block to allocate.
403 * Success: Pointer to newly allocated memory block.
406 LPVOID WINAPI
CoTaskMemAlloc(SIZE_T size
)
408 return IMalloc_Alloc(&Malloc32
.IMalloc_iface
,size
);
411 /***********************************************************************
412 * CoTaskMemFree [OLE32.@]
414 * Frees memory allocated from the current process memory allocator.
417 * ptr [I] Memory block to free.
422 VOID WINAPI
CoTaskMemFree(LPVOID ptr
)
424 IMalloc_Free(&Malloc32
.IMalloc_iface
, ptr
);
427 /***********************************************************************
428 * CoTaskMemRealloc [OLE32.@]
430 * Allocates memory using the current process memory allocator.
433 * pvOld [I] Pointer to old memory block.
434 * size [I] Size of the new memory block.
437 * Success: Pointer to newly allocated memory block.
440 LPVOID WINAPI
CoTaskMemRealloc(LPVOID pvOld
, SIZE_T size
)
442 return IMalloc_Realloc(&Malloc32
.IMalloc_iface
, pvOld
, size
);
445 /***********************************************************************
446 * CoRegisterMallocSpy [OLE32.@]
448 * Registers an object that receives notifications on memory allocations and
452 * pMallocSpy [I] New spy object.
456 * Failure: HRESULT code.
459 * if a mallocspy is already registered, we can't do it again since
460 * only the spy knows, how to free a memory block
462 HRESULT WINAPI
CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy
)
465 HRESULT hres
= E_INVALIDARG
;
467 TRACE("%p\n", pMallocSpy
);
469 if(!pMallocSpy
) return E_INVALIDARG
;
471 EnterCriticalSection(&IMalloc32_SpyCS
);
474 hres
= CO_E_OBJISREG
;
475 else if (SUCCEEDED(IMallocSpy_QueryInterface(pMallocSpy
, &IID_IMallocSpy
, (void**)&pSpy
))) {
476 Malloc32
.pSpy
= pSpy
;
480 LeaveCriticalSection(&IMalloc32_SpyCS
);
485 /***********************************************************************
486 * CoRevokeMallocSpy [OLE32.@]
488 * Revokes a previously registered object that receives notifications on memory
489 * allocations and frees.
492 * pMallocSpy [I] New spy object.
496 * Failure: HRESULT code.
499 * we can't revoke a malloc spy as long as memory blocks allocated with
500 * the spy are active since only the spy knows how to free them
502 HRESULT WINAPI
CoRevokeMallocSpy(void)
507 EnterCriticalSection(&IMalloc32_SpyCS
);
510 hres
= CO_E_OBJNOTREG
;
511 else if (Malloc32
.SpyedAllocationsLeft
) {
512 TRACE("SpyReleasePending with %u allocations left\n", Malloc32
.SpyedAllocationsLeft
);
513 Malloc32
.SpyReleasePending
= TRUE
;
514 hres
= E_ACCESSDENIED
;
516 IMallocSpy_Release(Malloc32
.pSpy
);
517 Malloc32
.pSpy
= NULL
;
519 LeaveCriticalSection(&IMalloc32_SpyCS
);
524 /******************************************************************************
525 * IsValidInterface [OLE32.@]
527 * Determines whether a pointer is a valid interface.
530 * punk [I] Interface to be tested.
533 * TRUE, if the passed pointer is a valid interface, or FALSE otherwise.
535 BOOL WINAPI
IsValidInterface(LPUNKNOWN punk
)
538 IsBadReadPtr(punk
,4) ||
539 IsBadReadPtr(punk
->lpVtbl
,4) ||
540 IsBadReadPtr(punk
->lpVtbl
->QueryInterface
,9) ||
541 IsBadCodePtr((FARPROC
)punk
->lpVtbl
->QueryInterface
)