mfreadwrite/reader: Add missing allocation check (Coverity).
[wine/zf.git] / dlls / combase / malloc.c
blob2be03ae1e31a4d9f2110a861fcebb6bff8a78cbb
1 /*
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
19 #define COBJMACROS
21 #include "oleauto.h"
23 #include "wine/debug.h"
24 #include "wine/heap.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(olemalloc);
28 static const IMallocVtbl allocator_vtbl;
30 struct allocator
32 IMalloc IMalloc_iface;
33 IMallocSpy *spy;
34 DWORD spyed_allocations;
35 BOOL spy_release_pending; /* CoRevokeMallocSpy called with spyed allocations left */
36 void **blocks;
37 DWORD blocks_length;
40 static struct allocator allocator = { .IMalloc_iface.lpVtbl = &allocator_vtbl };
42 static CRITICAL_SECTION allocspy_cs;
43 static CRITICAL_SECTION_DEBUG allocspy_cs_debug =
45 0, 0, &allocspy_cs,
46 { &allocspy_cs_debug.ProcessLocksList, &allocspy_cs_debug.ProcessLocksList },
47 0, 0, { (DWORD_PTR)(__FILE__ ": allocspy_cs") }
49 static CRITICAL_SECTION allocspy_cs = { &allocspy_cs_debug, -1, 0, 0, 0, 0 };
51 static BOOL mallocspy_grow(DWORD length)
53 void **blocks;
55 if (!allocator.blocks) blocks = LocalAlloc(LMEM_ZEROINIT, length * sizeof(void *));
56 else blocks = LocalReAlloc(allocator.blocks, length * sizeof(void *), LMEM_ZEROINIT | LMEM_MOVEABLE);
57 if (blocks)
59 allocator.blocks = blocks;
60 allocator.blocks_length = length;
63 return blocks != NULL;
66 static void mallocspy_add_mem(void *mem)
68 void **current;
70 if (!mem || (!allocator.blocks_length && !mallocspy_grow(0x1000)))
71 return;
73 /* Find a free location */
74 current = allocator.blocks;
75 while (*current)
77 current++;
78 if (current >= allocator.blocks + allocator.blocks_length)
80 DWORD old_length = allocator.blocks_length;
81 if (!mallocspy_grow(allocator.blocks_length + 0x1000))
82 return;
83 current = allocator.blocks + old_length;
87 *current = mem;
88 allocator.spyed_allocations++;
91 static void** mallocspy_is_allocation_spyed(const void *mem)
93 void **current = allocator.blocks;
95 while (*current != mem)
97 current++;
98 if (current >= allocator.blocks + allocator.blocks_length)
99 return NULL;
102 return current;
105 static BOOL mallocspy_remove_spyed_memory(const void *mem)
107 void **current;
109 if (!allocator.blocks_length)
110 return FALSE;
112 if (!(current = mallocspy_is_allocation_spyed(mem)))
113 return FALSE;
115 allocator.spyed_allocations--;
116 *current = NULL;
117 return TRUE;
120 static HRESULT WINAPI allocator_QueryInterface(IMalloc *iface, REFIID riid, void **obj)
122 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
124 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMalloc, riid))
126 *obj = &allocator.IMalloc_iface;
127 return S_OK;
130 return E_NOINTERFACE;
133 static ULONG WINAPI allocator_AddRef(IMalloc *iface)
135 return 2;
138 static ULONG WINAPI allocator_Release(IMalloc *iface)
140 return 1;
143 static void * WINAPI allocator_Alloc(IMalloc *iface, SIZE_T cb)
145 void *addr;
147 TRACE("%ld.\n", cb);
149 if (allocator.spy)
151 SIZE_T preAllocResult;
153 EnterCriticalSection(&allocspy_cs);
154 preAllocResult = IMallocSpy_PreAlloc(allocator.spy, cb);
155 if (cb && !preAllocResult)
157 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
158 TRACE("returning null\n");
159 LeaveCriticalSection(&allocspy_cs);
160 return NULL;
164 addr = HeapAlloc(GetProcessHeap(), 0, cb);
166 if (allocator.spy)
168 addr = IMallocSpy_PostAlloc(allocator.spy, addr);
169 mallocspy_add_mem(addr);
170 LeaveCriticalSection(&allocspy_cs);
173 TRACE("%p.\n",addr);
174 return addr;
177 static void * WINAPI allocator_Realloc(IMalloc *iface, void *pv, SIZE_T cb)
179 void *addr;
181 TRACE("%p, %ld.\n",pv,cb);
183 if (allocator.spy)
185 void *real_mem;
186 BOOL spyed;
188 EnterCriticalSection(&allocspy_cs);
189 spyed = mallocspy_remove_spyed_memory(pv);
190 cb = IMallocSpy_PreRealloc(allocator.spy, pv, cb, &real_mem, spyed);
192 /* check if can release the spy */
193 if (allocator.spy_release_pending && !allocator.spyed_allocations)
195 IMallocSpy_Release(allocator.spy);
196 allocator.spy_release_pending = FALSE;
197 allocator.spy = NULL;
198 LeaveCriticalSection(&allocspy_cs);
201 if (!cb)
203 /* PreRealloc can force Realloc to fail */
204 if (allocator.spy)
205 LeaveCriticalSection(&allocspy_cs);
206 return NULL;
209 pv = real_mem;
212 if (!pv) addr = HeapAlloc(GetProcessHeap(), 0, cb);
213 else if (cb) addr = HeapReAlloc(GetProcessHeap(), 0, pv, cb);
214 else
216 HeapFree(GetProcessHeap(), 0, pv);
217 addr = NULL;
220 if (allocator.spy)
222 addr = IMallocSpy_PostRealloc(allocator.spy, addr, TRUE);
223 mallocspy_add_mem(addr);
224 LeaveCriticalSection(&allocspy_cs);
227 TRACE("%p.\n", addr);
228 return addr;
231 static void WINAPI allocator_Free(IMalloc *iface, void *mem)
233 BOOL spyed_block = FALSE, spy_active = FALSE;
235 TRACE("%p.\n", mem);
237 if (!mem)
238 return;
240 if (allocator.spy)
242 EnterCriticalSection(&allocspy_cs);
243 spyed_block = mallocspy_remove_spyed_memory(mem);
244 spy_active = TRUE;
245 mem = IMallocSpy_PreFree(allocator.spy, mem, spyed_block);
248 HeapFree(GetProcessHeap(), 0, mem);
250 if (spy_active)
252 IMallocSpy_PostFree(allocator.spy, spyed_block);
254 /* check if can release the spy */
255 if (allocator.spy_release_pending && !allocator.spyed_allocations)
257 IMallocSpy_Release(allocator.spy);
258 allocator.spy_release_pending = FALSE;
259 allocator.spy = NULL;
262 LeaveCriticalSection(&allocspy_cs);
266 /******************************************************************************
267 * NOTES
268 * FIXME returns:
269 * win95: size allocated (4 byte boundaries)
270 * win2k: size originally requested !!! (allocated on 8 byte boundaries)
272 static SIZE_T WINAPI allocator_GetSize(IMalloc *iface, void *mem)
274 BOOL spyed_block = FALSE, spy_active = FALSE;
275 SIZE_T size;
277 TRACE("%p.\n", mem);
279 if (!mem)
280 return (SIZE_T)-1;
282 if (allocator.spy)
284 EnterCriticalSection(&allocspy_cs);
285 spyed_block = !!mallocspy_is_allocation_spyed(mem);
286 spy_active = TRUE;
287 mem = IMallocSpy_PreGetSize(allocator.spy, mem, spyed_block);
290 size = HeapSize(GetProcessHeap(), 0, mem);
292 if (spy_active)
294 size = IMallocSpy_PostGetSize(allocator.spy, size, spyed_block);
295 LeaveCriticalSection(&allocspy_cs);
298 return size;
301 static INT WINAPI allocator_DidAlloc(IMalloc *iface, void *mem)
303 BOOL spyed_block = FALSE, spy_active = FALSE;
304 int did_alloc;
306 TRACE("%p.\n", mem);
308 if (!mem)
309 return -1;
311 if (allocator.spy)
313 EnterCriticalSection(&allocspy_cs);
314 spyed_block = !!mallocspy_is_allocation_spyed(mem);
315 spy_active = TRUE;
316 mem = IMallocSpy_PreDidAlloc(allocator.spy, mem, spyed_block);
319 did_alloc = HeapValidate(GetProcessHeap(), 0, mem);
321 if (spy_active)
323 did_alloc = IMallocSpy_PostDidAlloc(allocator.spy, mem, spyed_block, did_alloc);
324 LeaveCriticalSection(&allocspy_cs);
327 return did_alloc;
330 static void WINAPI allocator_HeapMinimize(IMalloc *iface)
332 BOOL spy_active = FALSE;
334 TRACE("\n");
336 if (allocator.spy)
338 EnterCriticalSection(&allocspy_cs);
339 spy_active = TRUE;
340 IMallocSpy_PreHeapMinimize(allocator.spy);
343 if (spy_active)
345 IMallocSpy_PostHeapMinimize(allocator.spy);
346 LeaveCriticalSection(&allocspy_cs);
350 static const IMallocVtbl allocator_vtbl =
352 allocator_QueryInterface,
353 allocator_AddRef,
354 allocator_Release,
355 allocator_Alloc,
356 allocator_Realloc,
357 allocator_Free,
358 allocator_GetSize,
359 allocator_DidAlloc,
360 allocator_HeapMinimize
363 /******************************************************************************
364 * CoGetMalloc (combase.@)
366 HRESULT WINAPI CoGetMalloc(DWORD context, IMalloc **imalloc)
368 if (context != MEMCTX_TASK)
370 *imalloc = NULL;
371 return E_INVALIDARG;
374 *imalloc = &allocator.IMalloc_iface;
376 return S_OK;
379 /***********************************************************************
380 * CoTaskMemAlloc (combase.@)
382 void * WINAPI CoTaskMemAlloc(SIZE_T size)
384 return IMalloc_Alloc(&allocator.IMalloc_iface, size);
387 /***********************************************************************
388 * CoTaskMemFree (combase.@)
390 void WINAPI CoTaskMemFree(void *ptr)
392 IMalloc_Free(&allocator.IMalloc_iface, ptr);
395 /***********************************************************************
396 * CoTaskMemRealloc (combase.@)
398 void * WINAPI CoTaskMemRealloc(void *ptr, SIZE_T size)
400 return IMalloc_Realloc(&allocator.IMalloc_iface, ptr, size);
403 /***********************************************************************
404 * CoRegisterMallocSpy (combase.@)
406 HRESULT WINAPI CoRegisterMallocSpy(IMallocSpy *spy)
408 HRESULT hr = E_INVALIDARG;
410 TRACE("%p.\n", spy);
412 if (!spy) return E_INVALIDARG;
414 EnterCriticalSection(&allocspy_cs);
416 if (allocator.spy)
417 hr = CO_E_OBJISREG;
418 else if (SUCCEEDED(IMallocSpy_QueryInterface(spy, &IID_IMallocSpy, (void **)&spy)))
420 allocator.spy = spy;
421 hr = S_OK;
424 LeaveCriticalSection(&allocspy_cs);
426 return hr;
429 /***********************************************************************
430 * CoRevokeMallocSpy (combase.@)
432 HRESULT WINAPI CoRevokeMallocSpy(void)
434 HRESULT hr = S_OK;
436 TRACE("\n");
438 EnterCriticalSection(&allocspy_cs);
440 if (!allocator.spy)
441 hr = CO_E_OBJNOTREG;
442 else if (allocator.spyed_allocations)
444 allocator.spy_release_pending = TRUE;
445 hr = E_ACCESSDENIED;
447 else
449 IMallocSpy_Release(allocator.spy);
450 allocator.spy = NULL;
453 LeaveCriticalSection(&allocspy_cs);
455 return hr;