Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/combase/malloc.c
4389 views
1
/*
2
* Copyright 1997 Marcus Meissner
3
*
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.
8
*
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.
13
*
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
17
*/
18
19
#define COBJMACROS
20
21
#include "oleauto.h"
22
23
#include "wine/debug.h"
24
25
WINE_DEFAULT_DEBUG_CHANNEL(olemalloc);
26
27
static const IMallocVtbl allocator_vtbl;
28
29
struct allocator
30
{
31
IMalloc IMalloc_iface;
32
IMallocSpy *spy;
33
DWORD spyed_allocations;
34
BOOL spy_release_pending; /* CoRevokeMallocSpy called with spyed allocations left */
35
void **blocks;
36
DWORD blocks_length;
37
};
38
39
static struct allocator allocator = { .IMalloc_iface.lpVtbl = &allocator_vtbl };
40
41
static CRITICAL_SECTION allocspy_cs;
42
static CRITICAL_SECTION_DEBUG allocspy_cs_debug =
43
{
44
0, 0, &allocspy_cs,
45
{ &allocspy_cs_debug.ProcessLocksList, &allocspy_cs_debug.ProcessLocksList },
46
0, 0, { (DWORD_PTR)(__FILE__ ": allocspy_cs") }
47
};
48
static CRITICAL_SECTION allocspy_cs = { &allocspy_cs_debug, -1, 0, 0, 0, 0 };
49
50
static BOOL mallocspy_grow(DWORD length)
51
{
52
void **blocks;
53
54
if (!allocator.blocks) blocks = LocalAlloc(LMEM_ZEROINIT, length * sizeof(void *));
55
else blocks = LocalReAlloc(allocator.blocks, length * sizeof(void *), LMEM_ZEROINIT | LMEM_MOVEABLE);
56
if (blocks)
57
{
58
allocator.blocks = blocks;
59
allocator.blocks_length = length;
60
}
61
62
return blocks != NULL;
63
}
64
65
static void mallocspy_add_mem(void *mem)
66
{
67
void **current;
68
69
if (!mem || (!allocator.blocks_length && !mallocspy_grow(0x1000)))
70
return;
71
72
/* Find a free location */
73
current = allocator.blocks;
74
while (*current)
75
{
76
current++;
77
if (current >= allocator.blocks + allocator.blocks_length)
78
{
79
DWORD old_length = allocator.blocks_length;
80
if (!mallocspy_grow(allocator.blocks_length + 0x1000))
81
return;
82
current = allocator.blocks + old_length;
83
}
84
}
85
86
*current = mem;
87
allocator.spyed_allocations++;
88
}
89
90
static void** mallocspy_is_allocation_spyed(const void *mem)
91
{
92
void **current = allocator.blocks;
93
94
while (*current != mem)
95
{
96
current++;
97
if (current >= allocator.blocks + allocator.blocks_length)
98
return NULL;
99
}
100
101
return current;
102
}
103
104
static BOOL mallocspy_remove_spyed_memory(const void *mem)
105
{
106
void **current;
107
108
if (!allocator.blocks_length)
109
return FALSE;
110
111
if (!(current = mallocspy_is_allocation_spyed(mem)))
112
return FALSE;
113
114
allocator.spyed_allocations--;
115
*current = NULL;
116
return TRUE;
117
}
118
119
static HRESULT WINAPI allocator_QueryInterface(IMalloc *iface, REFIID riid, void **obj)
120
{
121
TRACE("%s, %p.\n", debugstr_guid(riid), obj);
122
123
if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMalloc, riid))
124
{
125
*obj = &allocator.IMalloc_iface;
126
return S_OK;
127
}
128
129
return E_NOINTERFACE;
130
}
131
132
static ULONG WINAPI allocator_AddRef(IMalloc *iface)
133
{
134
return 2;
135
}
136
137
static ULONG WINAPI allocator_Release(IMalloc *iface)
138
{
139
return 1;
140
}
141
142
static void * WINAPI allocator_Alloc(IMalloc *iface, SIZE_T cb)
143
{
144
void *addr;
145
146
TRACE("%Id.\n", cb);
147
148
if (allocator.spy)
149
{
150
SIZE_T preAllocResult;
151
152
EnterCriticalSection(&allocspy_cs);
153
preAllocResult = IMallocSpy_PreAlloc(allocator.spy, cb);
154
if (cb && !preAllocResult)
155
{
156
/* PreAlloc can force Alloc to fail, but not if cb == 0 */
157
TRACE("returning null\n");
158
LeaveCriticalSection(&allocspy_cs);
159
return NULL;
160
}
161
}
162
163
addr = HeapAlloc(GetProcessHeap(), 0, cb);
164
165
if (allocator.spy)
166
{
167
addr = IMallocSpy_PostAlloc(allocator.spy, addr);
168
mallocspy_add_mem(addr);
169
LeaveCriticalSection(&allocspy_cs);
170
}
171
172
TRACE("%p.\n",addr);
173
return addr;
174
}
175
176
static void * WINAPI allocator_Realloc(IMalloc *iface, void *pv, SIZE_T cb)
177
{
178
void *addr;
179
180
TRACE("%p, %Id.\n", pv, cb);
181
182
if (allocator.spy)
183
{
184
void *real_mem;
185
BOOL spyed;
186
187
EnterCriticalSection(&allocspy_cs);
188
spyed = mallocspy_remove_spyed_memory(pv);
189
cb = IMallocSpy_PreRealloc(allocator.spy, pv, cb, &real_mem, spyed);
190
191
/* check if can release the spy */
192
if (allocator.spy_release_pending && !allocator.spyed_allocations)
193
{
194
IMallocSpy_Release(allocator.spy);
195
allocator.spy_release_pending = FALSE;
196
allocator.spy = NULL;
197
LeaveCriticalSection(&allocspy_cs);
198
}
199
200
if (!cb)
201
{
202
/* PreRealloc can force Realloc to fail */
203
if (allocator.spy)
204
LeaveCriticalSection(&allocspy_cs);
205
return NULL;
206
}
207
208
pv = real_mem;
209
}
210
211
if (!pv) addr = HeapAlloc(GetProcessHeap(), 0, cb);
212
else if (cb) addr = HeapReAlloc(GetProcessHeap(), 0, pv, cb);
213
else
214
{
215
HeapFree(GetProcessHeap(), 0, pv);
216
addr = NULL;
217
}
218
219
if (allocator.spy)
220
{
221
addr = IMallocSpy_PostRealloc(allocator.spy, addr, TRUE);
222
mallocspy_add_mem(addr);
223
LeaveCriticalSection(&allocspy_cs);
224
}
225
226
TRACE("%p.\n", addr);
227
return addr;
228
}
229
230
static void WINAPI allocator_Free(IMalloc *iface, void *mem)
231
{
232
BOOL spyed_block = FALSE, spy_active = FALSE;
233
234
TRACE("%p.\n", mem);
235
236
if (!mem)
237
return;
238
239
if (allocator.spy)
240
{
241
EnterCriticalSection(&allocspy_cs);
242
spyed_block = mallocspy_remove_spyed_memory(mem);
243
spy_active = TRUE;
244
mem = IMallocSpy_PreFree(allocator.spy, mem, spyed_block);
245
}
246
247
HeapFree(GetProcessHeap(), 0, mem);
248
249
if (spy_active)
250
{
251
IMallocSpy_PostFree(allocator.spy, spyed_block);
252
253
/* check if can release the spy */
254
if (allocator.spy_release_pending && !allocator.spyed_allocations)
255
{
256
IMallocSpy_Release(allocator.spy);
257
allocator.spy_release_pending = FALSE;
258
allocator.spy = NULL;
259
}
260
261
LeaveCriticalSection(&allocspy_cs);
262
}
263
}
264
265
/******************************************************************************
266
* NOTES
267
* FIXME returns:
268
* win95: size allocated (4 byte boundaries)
269
* win2k: size originally requested !!! (allocated on 8 byte boundaries)
270
*/
271
static SIZE_T WINAPI allocator_GetSize(IMalloc *iface, void *mem)
272
{
273
BOOL spyed_block = FALSE, spy_active = FALSE;
274
SIZE_T size;
275
276
TRACE("%p.\n", mem);
277
278
if (!mem)
279
return (SIZE_T)-1;
280
281
if (allocator.spy)
282
{
283
EnterCriticalSection(&allocspy_cs);
284
spyed_block = !!mallocspy_is_allocation_spyed(mem);
285
spy_active = TRUE;
286
mem = IMallocSpy_PreGetSize(allocator.spy, mem, spyed_block);
287
}
288
289
size = HeapSize(GetProcessHeap(), 0, mem);
290
291
if (spy_active)
292
{
293
size = IMallocSpy_PostGetSize(allocator.spy, size, spyed_block);
294
LeaveCriticalSection(&allocspy_cs);
295
}
296
297
return size;
298
}
299
300
static INT WINAPI allocator_DidAlloc(IMalloc *iface, void *mem)
301
{
302
BOOL spyed_block = FALSE, spy_active = FALSE;
303
int did_alloc;
304
305
TRACE("%p.\n", mem);
306
307
if (!mem)
308
return -1;
309
310
if (allocator.spy)
311
{
312
EnterCriticalSection(&allocspy_cs);
313
spyed_block = !!mallocspy_is_allocation_spyed(mem);
314
spy_active = TRUE;
315
mem = IMallocSpy_PreDidAlloc(allocator.spy, mem, spyed_block);
316
}
317
318
did_alloc = HeapValidate(GetProcessHeap(), 0, mem);
319
320
if (spy_active)
321
{
322
did_alloc = IMallocSpy_PostDidAlloc(allocator.spy, mem, spyed_block, did_alloc);
323
LeaveCriticalSection(&allocspy_cs);
324
}
325
326
return did_alloc;
327
}
328
329
static void WINAPI allocator_HeapMinimize(IMalloc *iface)
330
{
331
BOOL spy_active = FALSE;
332
333
TRACE("\n");
334
335
if (allocator.spy)
336
{
337
EnterCriticalSection(&allocspy_cs);
338
spy_active = TRUE;
339
IMallocSpy_PreHeapMinimize(allocator.spy);
340
}
341
342
if (spy_active)
343
{
344
IMallocSpy_PostHeapMinimize(allocator.spy);
345
LeaveCriticalSection(&allocspy_cs);
346
}
347
}
348
349
static const IMallocVtbl allocator_vtbl =
350
{
351
allocator_QueryInterface,
352
allocator_AddRef,
353
allocator_Release,
354
allocator_Alloc,
355
allocator_Realloc,
356
allocator_Free,
357
allocator_GetSize,
358
allocator_DidAlloc,
359
allocator_HeapMinimize
360
};
361
362
/******************************************************************************
363
* CoGetMalloc (combase.@)
364
*/
365
HRESULT WINAPI CoGetMalloc(DWORD context, IMalloc **imalloc)
366
{
367
if (context != MEMCTX_TASK)
368
{
369
*imalloc = NULL;
370
return E_INVALIDARG;
371
}
372
373
*imalloc = &allocator.IMalloc_iface;
374
375
return S_OK;
376
}
377
378
/***********************************************************************
379
* CoTaskMemAlloc (combase.@)
380
*/
381
void * WINAPI CoTaskMemAlloc(SIZE_T size)
382
{
383
return IMalloc_Alloc(&allocator.IMalloc_iface, size);
384
}
385
386
/***********************************************************************
387
* CoTaskMemFree (combase.@)
388
*/
389
void WINAPI CoTaskMemFree(void *ptr)
390
{
391
IMalloc_Free(&allocator.IMalloc_iface, ptr);
392
}
393
394
/***********************************************************************
395
* CoTaskMemRealloc (combase.@)
396
*/
397
void * WINAPI CoTaskMemRealloc(void *ptr, SIZE_T size)
398
{
399
return IMalloc_Realloc(&allocator.IMalloc_iface, ptr, size);
400
}
401
402
/***********************************************************************
403
* CoRegisterMallocSpy (combase.@)
404
*/
405
HRESULT WINAPI CoRegisterMallocSpy(IMallocSpy *spy)
406
{
407
HRESULT hr = E_INVALIDARG;
408
409
TRACE("%p.\n", spy);
410
411
if (!spy) return E_INVALIDARG;
412
413
EnterCriticalSection(&allocspy_cs);
414
415
if (allocator.spy)
416
hr = CO_E_OBJISREG;
417
else if (SUCCEEDED(IMallocSpy_QueryInterface(spy, &IID_IMallocSpy, (void **)&spy)))
418
{
419
allocator.spy = spy;
420
hr = S_OK;
421
}
422
423
LeaveCriticalSection(&allocspy_cs);
424
425
return hr;
426
}
427
428
/***********************************************************************
429
* CoRevokeMallocSpy (combase.@)
430
*/
431
HRESULT WINAPI CoRevokeMallocSpy(void)
432
{
433
HRESULT hr = S_OK;
434
435
TRACE("\n");
436
437
EnterCriticalSection(&allocspy_cs);
438
439
if (!allocator.spy)
440
hr = CO_E_OBJNOTREG;
441
else if (allocator.spyed_allocations)
442
{
443
allocator.spy_release_pending = TRUE;
444
hr = E_ACCESSDENIED;
445
}
446
else
447
{
448
IMallocSpy_Release(allocator.spy);
449
allocator.spy = NULL;
450
}
451
452
LeaveCriticalSection(&allocspy_cs);
453
454
return hr;
455
}
456
457