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
23 WINE_DEFAULT_DEBUG_CHANNEL(olemalloc
);
25 /******************************************************************************
26 * IMalloc32 implementation
29 * For supporting CoRegisterMallocSpy the IMalloc implementation must know if
30 * a given memory block was allocated with a spy active.
32 *****************************************************************************/
33 /* set the vtable later */
34 static const IMallocVtbl VT_IMalloc32
;
37 IMalloc IMalloc_iface
;
38 DWORD dummy
; /* nothing, we are static */
39 IMallocSpy
* pSpy
; /* the spy when active */
40 DWORD SpyedAllocationsLeft
; /* number of spyed allocations left */
41 BOOL SpyReleasePending
; /* CoRevokeMallocSpy called with spyed allocations left*/
42 LPVOID
* SpyedBlocks
; /* root of the table */
43 DWORD SpyedBlockTableLength
;/* size of the table*/
46 /* this is the static object instance */
47 static _Malloc32 Malloc32
= {{&VT_IMalloc32
}, 0, NULL
, 0, 0, NULL
, 0};
49 /* with a spy active all calls from pre to post methods are threadsave */
50 static CRITICAL_SECTION IMalloc32_SpyCS
;
51 static CRITICAL_SECTION_DEBUG critsect_debug
=
53 0, 0, &IMalloc32_SpyCS
,
54 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
55 0, 0, { (DWORD_PTR
)(__FILE__
": IMalloc32_SpyCS") }
57 static CRITICAL_SECTION IMalloc32_SpyCS
= { &critsect_debug
, -1, 0, 0, 0, 0 };
59 /* resize the old table */
60 static BOOL
SetSpyedBlockTableLength ( DWORD NewLength
)
62 LPVOID
*NewSpyedBlocks
;
64 if (!Malloc32
.SpyedBlocks
) NewSpyedBlocks
= LocalAlloc(LMEM_ZEROINIT
, NewLength
* sizeof(PVOID
));
65 else NewSpyedBlocks
= LocalReAlloc(Malloc32
.SpyedBlocks
, NewLength
* sizeof(PVOID
), LMEM_ZEROINIT
| LMEM_MOVEABLE
);
67 Malloc32
.SpyedBlocks
= NewSpyedBlocks
;
68 Malloc32
.SpyedBlockTableLength
= NewLength
;
71 return NewSpyedBlocks
!= NULL
;
74 /* add a location to the table */
75 static BOOL
AddMemoryLocation(LPVOID
* pMem
)
79 /* allocate the table if not already allocated */
80 if (!Malloc32
.SpyedBlockTableLength
&& !SetSpyedBlockTableLength(0x1000))
83 /* find a free location */
84 Current
= Malloc32
.SpyedBlocks
;
87 if (Current
>= Malloc32
.SpyedBlocks
+ Malloc32
.SpyedBlockTableLength
) {
88 /* no more space in table, grow it */
89 DWORD old_length
= Malloc32
.SpyedBlockTableLength
;
90 if (!SetSpyedBlockTableLength( Malloc32
.SpyedBlockTableLength
+ 0x1000))
92 Current
= Malloc32
.SpyedBlocks
+ old_length
;
96 /* put the location in our table */
98 Malloc32
.SpyedAllocationsLeft
++;
99 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
103 static BOOL
RemoveMemoryLocation(LPCVOID pMem
)
107 /* allocate the table if not already allocated */
108 if (!Malloc32
.SpyedBlockTableLength
&& !SetSpyedBlockTableLength(0x1000))
111 Current
= Malloc32
.SpyedBlocks
;
113 /* find the location */
114 while (*Current
!= pMem
) {
116 if (Current
>= Malloc32
.SpyedBlocks
+ Malloc32
.SpyedBlockTableLength
)
117 return FALSE
; /* not found */
121 Malloc32
.SpyedAllocationsLeft
--;
122 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
127 /******************************************************************************
128 * IMalloc32_QueryInterface [VTABLE]
130 static HRESULT WINAPI
IMalloc_fnQueryInterface(LPMALLOC iface
,REFIID refiid
,LPVOID
*obj
) {
132 TRACE("(%s,%p)\n",debugstr_guid(refiid
),obj
);
134 if (IsEqualIID(&IID_IUnknown
,refiid
) || IsEqualIID(&IID_IMalloc
,refiid
)) {
138 return E_NOINTERFACE
;
141 /******************************************************************************
142 * IMalloc32_AddRefRelease [VTABLE]
144 static ULONG WINAPI
IMalloc_fnAddRefRelease (LPMALLOC iface
) {
148 /******************************************************************************
149 * IMalloc32_Alloc [VTABLE]
151 static LPVOID WINAPI
IMalloc_fnAlloc(LPMALLOC iface
, SIZE_T cb
) {
158 DWORD preAllocResult
;
160 EnterCriticalSection(&IMalloc32_SpyCS
);
161 preAllocResult
= IMallocSpy_PreAlloc(Malloc32
.pSpy
, cb
);
162 if ((cb
!= 0) && (preAllocResult
== 0)) {
163 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
164 TRACE("returning null\n");
165 LeaveCriticalSection(&IMalloc32_SpyCS
);
170 addr
= HeapAlloc(GetProcessHeap(),0,cb
);
173 addr
= IMallocSpy_PostAlloc(Malloc32
.pSpy
, addr
);
174 if (addr
) AddMemoryLocation(addr
);
175 LeaveCriticalSection(&IMalloc32_SpyCS
);
178 TRACE("--(%p)\n",addr
);
182 /******************************************************************************
183 * IMalloc32_Realloc [VTABLE]
185 static LPVOID WINAPI
IMalloc_fnRealloc(LPMALLOC iface
,LPVOID pv
,SIZE_T cb
) {
189 TRACE("(%p,%d)\n",pv
,cb
);
195 EnterCriticalSection(&IMalloc32_SpyCS
);
196 fSpyed
= RemoveMemoryLocation(pv
);
197 cb
= IMallocSpy_PreRealloc(Malloc32
.pSpy
, pv
, cb
, &pRealMemory
, fSpyed
);
199 /* check if can release the spy */
200 if(Malloc32
.SpyReleasePending
&& !Malloc32
.SpyedAllocationsLeft
) {
201 IMallocSpy_Release(Malloc32
.pSpy
);
202 Malloc32
.SpyReleasePending
= FALSE
;
203 Malloc32
.pSpy
= NULL
;
204 LeaveCriticalSection(&IMalloc32_SpyCS
);
208 /* PreRealloc can force Realloc to fail */
210 LeaveCriticalSection(&IMalloc32_SpyCS
);
217 if (!pv
) pNewMemory
= HeapAlloc(GetProcessHeap(),0,cb
);
218 else if (cb
) pNewMemory
= HeapReAlloc(GetProcessHeap(),0,pv
,cb
);
220 HeapFree(GetProcessHeap(),0,pv
);
225 pNewMemory
= IMallocSpy_PostRealloc(Malloc32
.pSpy
, pNewMemory
, TRUE
);
226 if (pNewMemory
) AddMemoryLocation(pNewMemory
);
227 LeaveCriticalSection(&IMalloc32_SpyCS
);
230 TRACE("--(%p)\n",pNewMemory
);
234 /******************************************************************************
235 * IMalloc32_Free [VTABLE]
237 static VOID WINAPI
IMalloc_fnFree(LPMALLOC iface
,LPVOID pv
) {
244 EnterCriticalSection(&IMalloc32_SpyCS
);
245 fSpyed
= RemoveMemoryLocation(pv
);
246 pv
= IMallocSpy_PreFree(Malloc32
.pSpy
, pv
, fSpyed
);
249 HeapFree(GetProcessHeap(),0,pv
);
252 IMallocSpy_PostFree(Malloc32
.pSpy
, fSpyed
);
254 /* check if can release the spy */
255 if(Malloc32
.SpyReleasePending
&& !Malloc32
.SpyedAllocationsLeft
) {
256 IMallocSpy_Release(Malloc32
.pSpy
);
257 Malloc32
.SpyReleasePending
= FALSE
;
258 Malloc32
.pSpy
= NULL
;
261 LeaveCriticalSection(&IMalloc32_SpyCS
);
265 /******************************************************************************
266 * IMalloc32_GetSize [VTABLE]
270 * win95: size allocated (4 byte boundarys)
271 * win2k: size originally requested !!! (allocated on 8 byte boundarys)
273 static SIZE_T WINAPI
IMalloc_fnGetSize(LPMALLOC iface
,LPVOID pv
) {
281 EnterCriticalSection(&IMalloc32_SpyCS
);
282 pv
= IMallocSpy_PreGetSize(Malloc32
.pSpy
, pv
, fSpyed
);
285 cb
= HeapSize(GetProcessHeap(),0,pv
);
288 cb
= IMallocSpy_PostGetSize(Malloc32
.pSpy
, cb
, fSpyed
);
289 LeaveCriticalSection(&IMalloc32_SpyCS
);
295 /******************************************************************************
296 * IMalloc32_DidAlloc [VTABLE]
298 static INT WINAPI
IMalloc_fnDidAlloc(LPMALLOC iface
,LPVOID pv
) {
306 EnterCriticalSection(&IMalloc32_SpyCS
);
307 pv
= IMallocSpy_PreDidAlloc(Malloc32
.pSpy
, pv
, fSpyed
);
313 didAlloc
= IMallocSpy_PostDidAlloc(Malloc32
.pSpy
, pv
, fSpyed
, didAlloc
);
314 LeaveCriticalSection(&IMalloc32_SpyCS
);
319 /******************************************************************************
320 * IMalloc32_HeapMinimize [VTABLE]
322 static VOID WINAPI
IMalloc_fnHeapMinimize(LPMALLOC iface
) {
326 EnterCriticalSection(&IMalloc32_SpyCS
);
327 IMallocSpy_PreHeapMinimize(Malloc32
.pSpy
);
331 IMallocSpy_PostHeapMinimize(Malloc32
.pSpy
);
332 LeaveCriticalSection(&IMalloc32_SpyCS
);
336 static const IMallocVtbl VT_IMalloc32
=
338 IMalloc_fnQueryInterface
,
339 IMalloc_fnAddRefRelease
,
340 IMalloc_fnAddRefRelease
,
346 IMalloc_fnHeapMinimize
349 /******************************************************************************
350 * CoGetMalloc [OLE32.@]
352 * Retrieves the current IMalloc interface for the process.
356 * lpMalloc [O] Address where memory allocator object will be stored.
360 * Failure: HRESULT code.
362 HRESULT WINAPI
CoGetMalloc(DWORD dwMemContext
, LPMALLOC
*lpMalloc
)
364 *lpMalloc
= &Malloc32
.IMalloc_iface
;
368 /***********************************************************************
369 * CoTaskMemAlloc [OLE32.@]
371 * Allocates memory using the current process memory allocator.
374 * size [I] Size of the memory block to allocate.
377 * Success: Pointer to newly allocated memory block.
380 LPVOID WINAPI
CoTaskMemAlloc(ULONG size
)
382 return IMalloc_Alloc(&Malloc32
.IMalloc_iface
,size
);
385 /***********************************************************************
386 * CoTaskMemFree [OLE32.@]
388 * Frees memory allocated from the current process memory allocator.
391 * ptr [I] Memory block to free.
396 VOID WINAPI
CoTaskMemFree(LPVOID ptr
)
398 IMalloc_Free(&Malloc32
.IMalloc_iface
, ptr
);
401 /***********************************************************************
402 * CoTaskMemRealloc [OLE32.@]
404 * Allocates memory using the current process memory allocator.
407 * pvOld [I] Pointer to old memory block.
408 * size [I] Size of the new memory block.
411 * Success: Pointer to newly allocated memory block.
414 LPVOID WINAPI
CoTaskMemRealloc(LPVOID pvOld
, ULONG size
)
416 return IMalloc_Realloc(&Malloc32
.IMalloc_iface
, pvOld
, size
);
419 /***********************************************************************
420 * CoRegisterMallocSpy [OLE32.@]
422 * Registers an object that receives notifications on memory allocations and
426 * pMallocSpy [I] New spy object.
430 * Failure: HRESULT code.
433 * if a mallocspy is already registered, we can't do it again since
434 * only the spy knows, how to free a memory block
436 HRESULT WINAPI
CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy
)
439 HRESULT hres
= E_INVALIDARG
;
443 if(Malloc32
.pSpy
) return CO_E_OBJISREG
;
445 EnterCriticalSection(&IMalloc32_SpyCS
);
447 if (SUCCEEDED(IMallocSpy_QueryInterface(pMallocSpy
, &IID_IMallocSpy
, (void**)&pSpy
))) {
448 Malloc32
.pSpy
= pSpy
;
452 LeaveCriticalSection(&IMalloc32_SpyCS
);
457 /***********************************************************************
458 * CoRevokeMallocSpy [OLE32.@]
460 * Revokes a previously registered object that receives notifications on memory
461 * allocations and frees.
464 * pMallocSpy [I] New spy object.
468 * Failure: HRESULT code.
471 * we can't revoke a malloc spy as long as memory blocks allocated with
472 * the spy are active since only the spy knows how to free them
474 HRESULT WINAPI
CoRevokeMallocSpy(void)
479 EnterCriticalSection(&IMalloc32_SpyCS
);
481 if (Malloc32
.SpyedAllocationsLeft
) {
482 TRACE("SpyReleasePending with %u allocations left\n", Malloc32
.SpyedAllocationsLeft
);
483 Malloc32
.SpyReleasePending
= TRUE
;
484 hres
= E_ACCESSDENIED
;
486 IMallocSpy_Release(Malloc32
.pSpy
);
487 Malloc32
.pSpy
= NULL
;
489 LeaveCriticalSection(&IMalloc32_SpyCS
);
494 /******************************************************************************
495 * IsValidInterface [OLE32.@]
497 * Determines whether a pointer is a valid interface.
500 * punk [I] Interface to be tested.
503 * TRUE, if the passed pointer is a valid interface, or FALSE otherwise.
505 BOOL WINAPI
IsValidInterface(LPUNKNOWN punk
)
508 IsBadReadPtr(punk
,4) ||
509 IsBadReadPtr(punk
->lpVtbl
,4) ||
510 IsBadReadPtr(punk
->lpVtbl
->QueryInterface
,9) ||
511 IsBadCodePtr((FARPROC
)punk
->lpVtbl
->QueryInterface
)