2 * Copyright 1997 Marcus Meissner
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(olemalloc
);
27 static const IMallocVtbl allocator_vtbl
;
31 IMalloc IMalloc_iface
;
33 DWORD spyed_allocations
;
34 BOOL spy_release_pending
; /* CoRevokeMallocSpy called with spyed allocations left */
39 static struct allocator allocator
= { .IMalloc_iface
.lpVtbl
= &allocator_vtbl
};
41 static CRITICAL_SECTION allocspy_cs
;
42 static CRITICAL_SECTION_DEBUG allocspy_cs_debug
=
45 { &allocspy_cs_debug
.ProcessLocksList
, &allocspy_cs_debug
.ProcessLocksList
},
46 0, 0, { (DWORD_PTR
)(__FILE__
": allocspy_cs") }
48 static CRITICAL_SECTION allocspy_cs
= { &allocspy_cs_debug
, -1, 0, 0, 0, 0 };
50 static BOOL
mallocspy_grow(DWORD length
)
54 if (!allocator
.blocks
) blocks
= LocalAlloc(LMEM_ZEROINIT
, length
* sizeof(void *));
55 else blocks
= LocalReAlloc(allocator
.blocks
, length
* sizeof(void *), LMEM_ZEROINIT
| LMEM_MOVEABLE
);
58 allocator
.blocks
= blocks
;
59 allocator
.blocks_length
= length
;
62 return blocks
!= NULL
;
65 static void mallocspy_add_mem(void *mem
)
69 if (!mem
|| (!allocator
.blocks_length
&& !mallocspy_grow(0x1000)))
72 /* Find a free location */
73 current
= allocator
.blocks
;
77 if (current
>= allocator
.blocks
+ allocator
.blocks_length
)
79 DWORD old_length
= allocator
.blocks_length
;
80 if (!mallocspy_grow(allocator
.blocks_length
+ 0x1000))
82 current
= allocator
.blocks
+ old_length
;
87 allocator
.spyed_allocations
++;
90 static void** mallocspy_is_allocation_spyed(const void *mem
)
92 void **current
= allocator
.blocks
;
94 while (*current
!= mem
)
97 if (current
>= allocator
.blocks
+ allocator
.blocks_length
)
104 static BOOL
mallocspy_remove_spyed_memory(const void *mem
)
108 if (!allocator
.blocks_length
)
111 if (!(current
= mallocspy_is_allocation_spyed(mem
)))
114 allocator
.spyed_allocations
--;
119 static HRESULT WINAPI
allocator_QueryInterface(IMalloc
*iface
, REFIID riid
, void **obj
)
121 TRACE("%s, %p.\n", debugstr_guid(riid
), obj
);
123 if (IsEqualIID(&IID_IUnknown
, riid
) || IsEqualIID(&IID_IMalloc
, riid
))
125 *obj
= &allocator
.IMalloc_iface
;
129 return E_NOINTERFACE
;
132 static ULONG WINAPI
allocator_AddRef(IMalloc
*iface
)
137 static ULONG WINAPI
allocator_Release(IMalloc
*iface
)
142 static void * WINAPI
allocator_Alloc(IMalloc
*iface
, SIZE_T cb
)
150 SIZE_T preAllocResult
;
152 EnterCriticalSection(&allocspy_cs
);
153 preAllocResult
= IMallocSpy_PreAlloc(allocator
.spy
, cb
);
154 if (cb
&& !preAllocResult
)
156 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
157 TRACE("returning null\n");
158 LeaveCriticalSection(&allocspy_cs
);
163 addr
= HeapAlloc(GetProcessHeap(), 0, cb
);
167 addr
= IMallocSpy_PostAlloc(allocator
.spy
, addr
);
168 mallocspy_add_mem(addr
);
169 LeaveCriticalSection(&allocspy_cs
);
176 static void * WINAPI
allocator_Realloc(IMalloc
*iface
, void *pv
, SIZE_T cb
)
180 TRACE("%p, %Id.\n", pv
, cb
);
187 EnterCriticalSection(&allocspy_cs
);
188 spyed
= mallocspy_remove_spyed_memory(pv
);
189 cb
= IMallocSpy_PreRealloc(allocator
.spy
, pv
, cb
, &real_mem
, spyed
);
191 /* check if can release the spy */
192 if (allocator
.spy_release_pending
&& !allocator
.spyed_allocations
)
194 IMallocSpy_Release(allocator
.spy
);
195 allocator
.spy_release_pending
= FALSE
;
196 allocator
.spy
= NULL
;
197 LeaveCriticalSection(&allocspy_cs
);
202 /* PreRealloc can force Realloc to fail */
204 LeaveCriticalSection(&allocspy_cs
);
211 if (!pv
) addr
= HeapAlloc(GetProcessHeap(), 0, cb
);
212 else if (cb
) addr
= HeapReAlloc(GetProcessHeap(), 0, pv
, cb
);
215 HeapFree(GetProcessHeap(), 0, pv
);
221 addr
= IMallocSpy_PostRealloc(allocator
.spy
, addr
, TRUE
);
222 mallocspy_add_mem(addr
);
223 LeaveCriticalSection(&allocspy_cs
);
226 TRACE("%p.\n", addr
);
230 static void WINAPI
allocator_Free(IMalloc
*iface
, void *mem
)
232 BOOL spyed_block
= FALSE
, spy_active
= FALSE
;
241 EnterCriticalSection(&allocspy_cs
);
242 spyed_block
= mallocspy_remove_spyed_memory(mem
);
244 mem
= IMallocSpy_PreFree(allocator
.spy
, mem
, spyed_block
);
247 HeapFree(GetProcessHeap(), 0, mem
);
251 IMallocSpy_PostFree(allocator
.spy
, spyed_block
);
253 /* check if can release the spy */
254 if (allocator
.spy_release_pending
&& !allocator
.spyed_allocations
)
256 IMallocSpy_Release(allocator
.spy
);
257 allocator
.spy_release_pending
= FALSE
;
258 allocator
.spy
= NULL
;
261 LeaveCriticalSection(&allocspy_cs
);
265 /******************************************************************************
268 * win95: size allocated (4 byte boundaries)
269 * win2k: size originally requested !!! (allocated on 8 byte boundaries)
271 static SIZE_T WINAPI
allocator_GetSize(IMalloc
*iface
, void *mem
)
273 BOOL spyed_block
= FALSE
, spy_active
= FALSE
;
283 EnterCriticalSection(&allocspy_cs
);
284 spyed_block
= !!mallocspy_is_allocation_spyed(mem
);
286 mem
= IMallocSpy_PreGetSize(allocator
.spy
, mem
, spyed_block
);
289 size
= HeapSize(GetProcessHeap(), 0, mem
);
293 size
= IMallocSpy_PostGetSize(allocator
.spy
, size
, spyed_block
);
294 LeaveCriticalSection(&allocspy_cs
);
300 static INT WINAPI
allocator_DidAlloc(IMalloc
*iface
, void *mem
)
302 BOOL spyed_block
= FALSE
, spy_active
= FALSE
;
312 EnterCriticalSection(&allocspy_cs
);
313 spyed_block
= !!mallocspy_is_allocation_spyed(mem
);
315 mem
= IMallocSpy_PreDidAlloc(allocator
.spy
, mem
, spyed_block
);
318 did_alloc
= HeapValidate(GetProcessHeap(), 0, mem
);
322 did_alloc
= IMallocSpy_PostDidAlloc(allocator
.spy
, mem
, spyed_block
, did_alloc
);
323 LeaveCriticalSection(&allocspy_cs
);
329 static void WINAPI
allocator_HeapMinimize(IMalloc
*iface
)
331 BOOL spy_active
= FALSE
;
337 EnterCriticalSection(&allocspy_cs
);
339 IMallocSpy_PreHeapMinimize(allocator
.spy
);
344 IMallocSpy_PostHeapMinimize(allocator
.spy
);
345 LeaveCriticalSection(&allocspy_cs
);
349 static const IMallocVtbl allocator_vtbl
=
351 allocator_QueryInterface
,
359 allocator_HeapMinimize
362 /******************************************************************************
363 * CoGetMalloc (combase.@)
365 HRESULT WINAPI
CoGetMalloc(DWORD context
, IMalloc
**imalloc
)
367 if (context
!= MEMCTX_TASK
)
373 *imalloc
= &allocator
.IMalloc_iface
;
378 /***********************************************************************
379 * CoTaskMemAlloc (combase.@)
381 void * WINAPI
CoTaskMemAlloc(SIZE_T size
)
383 return IMalloc_Alloc(&allocator
.IMalloc_iface
, size
);
386 /***********************************************************************
387 * CoTaskMemFree (combase.@)
389 void WINAPI
CoTaskMemFree(void *ptr
)
391 IMalloc_Free(&allocator
.IMalloc_iface
, ptr
);
394 /***********************************************************************
395 * CoTaskMemRealloc (combase.@)
397 void * WINAPI
CoTaskMemRealloc(void *ptr
, SIZE_T size
)
399 return IMalloc_Realloc(&allocator
.IMalloc_iface
, ptr
, size
);
402 /***********************************************************************
403 * CoRegisterMallocSpy (combase.@)
405 HRESULT WINAPI
CoRegisterMallocSpy(IMallocSpy
*spy
)
407 HRESULT hr
= E_INVALIDARG
;
411 if (!spy
) return E_INVALIDARG
;
413 EnterCriticalSection(&allocspy_cs
);
417 else if (SUCCEEDED(IMallocSpy_QueryInterface(spy
, &IID_IMallocSpy
, (void **)&spy
)))
423 LeaveCriticalSection(&allocspy_cs
);
428 /***********************************************************************
429 * CoRevokeMallocSpy (combase.@)
431 HRESULT WINAPI
CoRevokeMallocSpy(void)
437 EnterCriticalSection(&allocspy_cs
);
441 else if (allocator
.spyed_allocations
)
443 allocator
.spy_release_pending
= TRUE
;
448 IMallocSpy_Release(allocator
.spy
);
449 allocator
.spy
= NULL
;
452 LeaveCriticalSection(&allocspy_cs
);