1 /*
2 * basic interfaces
3 *
4 * Copyright 1997 Marcus Meissner
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "config.h"
22
23 #include <ctype.h>
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #define COBJMACROS
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winuser.h"
34 #include "ole2.h"
35 #include "winerror.h"
36
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(olemalloc);
40
41 /******************************************************************************
42 * IMalloc32 implementation
43 *
44 * NOTES
45 * For supporting CoRegisterMallocSpy the IMalloc implementation must know if
46 * a given memory block was allocated with a spy active.
47 *
48 *****************************************************************************/
49 /* set the vtable later */
50 static const IMallocVtbl VT_IMalloc32;
51
52 typedef struct {
53 const IMallocVtbl *lpVtbl;
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*/
60 } _Malloc32;
61
62 /* this is the static object instance */
63 static _Malloc32 Malloc32 = {&VT_IMalloc32, 0, NULL, 0, 0, NULL, 0};
64
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 =
68 {
69 0, 0, &IMalloc32_SpyCS,
70 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
71 0, 0, { (DWORD_PTR)(__FILE__ ": IMalloc32_SpyCS") }
72 };
73 static CRITICAL_SECTION IMalloc32_SpyCS = { &critsect_debug, -1, 0, 0, 0, 0 };
74
75 /* resize the old table */
76 static int SetSpyedBlockTableLength ( DWORD NewLength )
77 {
78 LPVOID *NewSpyedBlocks;
79
80 if (!Malloc32.SpyedBlocks) NewSpyedBlocks = LocalAlloc(LMEM_ZEROINIT, NewLength * sizeof(PVOID));
81 else NewSpyedBlocks = LocalReAlloc(Malloc32.SpyedBlocks, NewLength * sizeof(PVOID), LMEM_ZEROINIT);
82 if (NewSpyedBlocks) {
83 Malloc32.SpyedBlocks = NewSpyedBlocks;
84 Malloc32.SpyedBlockTableLength = NewLength;
85 }
86
87 return NewSpyedBlocks != NULL;
88 }
89
90 /* add a location to the table */
91 static int AddMemoryLocation(LPVOID * pMem)
92 {
93 LPVOID * Current;
94
95 /* allocate the table if not already allocated */
96 if (!Malloc32.SpyedBlockTableLength) {
97 if (!SetSpyedBlockTableLength(0x1000)) return 0;
98 }
99
100 /* find a free location */
101 Current = Malloc32.SpyedBlocks;
102 while (*Current) {
103 Current++;
104 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) {
105 /* no more space in table, grow it */
106 DWORD old_length = Malloc32.SpyedBlockTableLength;
107 if (!SetSpyedBlockTableLength( Malloc32.SpyedBlockTableLength + 0x1000 )) return 0;
108 Current = Malloc32.SpyedBlocks + old_length;
109 }
110 };
111
112 /* put the location in our table */
113 *Current = pMem;
114 Malloc32.SpyedAllocationsLeft++;
115 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
116 return 1;
117 }
118
119 static int RemoveMemoryLocation(LPCVOID pMem)
120 {
121 LPVOID * Current;
122
123 /* allocate the table if not already allocated */
124 if (!Malloc32.SpyedBlockTableLength) {
125 if (!SetSpyedBlockTableLength(0x1000)) return 0;
126 }
127
128 Current = Malloc32.SpyedBlocks;
129
130 /* find the location */
131 while (*Current != pMem) {
132 Current++;
133 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) return 0; /* not found */
134 }
135
136 /* location found */
137 Malloc32.SpyedAllocationsLeft--;
138 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
139 *Current = NULL;
140 return 1;
141 }
142
143 /******************************************************************************
144 * IMalloc32_QueryInterface [VTABLE]
145 */
146 static HRESULT WINAPI IMalloc_fnQueryInterface(LPMALLOC iface,REFIID refiid,LPVOID *obj) {
147
148 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
149
150 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMalloc,refiid)) {
151 *obj = &Malloc32;
152 return S_OK;
153 }
154 return E_NOINTERFACE;
155 }
156
157 /******************************************************************************
158 * IMalloc32_AddRefRelease [VTABLE]
159 */
160 static ULONG WINAPI IMalloc_fnAddRefRelease (LPMALLOC iface) {
161 return 1;
162 }
163
164 /******************************************************************************
165 * IMalloc32_Alloc [VTABLE]
166 */
167 static LPVOID WINAPI IMalloc_fnAlloc(LPMALLOC iface, DWORD cb) {
168
169 LPVOID addr;
170
171 TRACE("(%d)\n",cb);
172
173 if(Malloc32.pSpy) {
174 DWORD preAllocResult;
175
176 EnterCriticalSection(&IMalloc32_SpyCS);
177 preAllocResult = IMallocSpy_PreAlloc(Malloc32.pSpy, cb);
178 if ((cb != 0) && (preAllocResult == 0)) {
179 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
180 TRACE("returning null\n");
181 LeaveCriticalSection(&IMalloc32_SpyCS);
182 return NULL;
183 }
184 }
185
186 addr = HeapAlloc(GetProcessHeap(),0,cb);
187
188 if(Malloc32.pSpy) {
189 addr = IMallocSpy_PostAlloc(Malloc32.pSpy, addr);
190 if (addr) AddMemoryLocation(addr);
191 LeaveCriticalSection(&IMalloc32_SpyCS);
192 }
193
194 TRACE("--(%p)\n",addr);
195 return addr;
196 }
197
198 /******************************************************************************
199 * IMalloc32_Realloc [VTABLE]
200 */
201 static LPVOID WINAPI IMalloc_fnRealloc(LPMALLOC iface,LPVOID pv,DWORD cb) {
202
203 LPVOID pNewMemory;
204
205 TRACE("(%p,%d)\n",pv,cb);
206
207 if(Malloc32.pSpy) {
208 LPVOID pRealMemory;
209 BOOL fSpyed;
210
211 EnterCriticalSection(&IMalloc32_SpyCS);
212 fSpyed = RemoveMemoryLocation(pv);
213 cb = IMallocSpy_PreRealloc(Malloc32.pSpy, pv, cb, &pRealMemory, fSpyed);
214
215 /* check if can release the spy */
216 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
217 IMallocSpy_Release(Malloc32.pSpy);
218 Malloc32.SpyReleasePending = FALSE;
219 Malloc32.pSpy = NULL;
220 }
221
222 if (0==cb) {
223 /* PreRealloc can force Realloc to fail */
224 LeaveCriticalSection(&IMalloc32_SpyCS);
225 return NULL;
226 }
227 pv = pRealMemory;
228 }
229
230 if (!pv) pNewMemory = HeapAlloc(GetProcessHeap(),0,cb);
231 else if (cb) pNewMemory = HeapReAlloc(GetProcessHeap(),0,pv,cb);
232 else {
233 HeapFree(GetProcessHeap(),0,pv);
234 pNewMemory = NULL;
235 }
236
237 if(Malloc32.pSpy) {
238 pNewMemory = IMallocSpy_PostRealloc(Malloc32.pSpy, pNewMemory, TRUE);
239 if (pNewMemory) AddMemoryLocation(pNewMemory);
240 LeaveCriticalSection(&IMalloc32_SpyCS);
241 }
242
243 TRACE("--(%p)\n",pNewMemory);
244 return pNewMemory;
245 }
246
247 /******************************************************************************
248 * IMalloc32_Free [VTABLE]
249 */
250 static VOID WINAPI IMalloc_fnFree(LPMALLOC iface,LPVOID pv) {
251
252 BOOL fSpyed = 0;
253
254 TRACE("(%p)\n",pv);
255
256 if(Malloc32.pSpy) {
257 EnterCriticalSection(&IMalloc32_SpyCS);
258 fSpyed = RemoveMemoryLocation(pv);
259 pv = IMallocSpy_PreFree(Malloc32.pSpy, pv, fSpyed);
260 }
261
262 HeapFree(GetProcessHeap(),0,pv);
263
264 if(Malloc32.pSpy) {
265 IMallocSpy_PostFree(Malloc32.pSpy, fSpyed);
266
267 /* check if can release the spy */
268 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
269 IMallocSpy_Release(Malloc32.pSpy);
270 Malloc32.SpyReleasePending = FALSE;
271 Malloc32.pSpy = NULL;
272 }
273
274 LeaveCriticalSection(&IMalloc32_SpyCS);
275 }
276 }
277
278 /******************************************************************************
279 * IMalloc32_GetSize [VTABLE]
280 *
281 * NOTES
282 * FIXME returns:
283 * win95: size allocated (4 byte boundarys)
284 * win2k: size originally requested !!! (allocated on 8 byte boundarys)
285 */
286 static DWORD WINAPI IMalloc_fnGetSize(LPMALLOC iface,LPVOID pv) {
287
288 DWORD cb;
289 BOOL fSpyed = 0;
290
291 TRACE("(%p)\n",pv);
292
293 if(Malloc32.pSpy) {
294 EnterCriticalSection(&IMalloc32_SpyCS);
295 pv = IMallocSpy_PreGetSize(Malloc32.pSpy, pv, fSpyed);
296 }
297
298 cb = HeapSize(GetProcessHeap(),0,pv);
299
300 if(Malloc32.pSpy) {
301 cb = IMallocSpy_PostGetSize(Malloc32.pSpy, cb, fSpyed);
302 LeaveCriticalSection(&IMalloc32_SpyCS);
303 }
304
305 return cb;
306 }
307
308 /******************************************************************************
309 * IMalloc32_DidAlloc [VTABLE]
310 */
311 static INT WINAPI IMalloc_fnDidAlloc(LPMALLOC iface,LPVOID pv) {
312
313 BOOL fSpyed = 0;
314 int didAlloc;
315
316 TRACE("(%p)\n",pv);
317
318 if(Malloc32.pSpy) {
319 EnterCriticalSection(&IMalloc32_SpyCS);
320 pv = IMallocSpy_PreDidAlloc(Malloc32.pSpy, pv, fSpyed);
321 }
322
323 didAlloc = -1;
324
325 if(Malloc32.pSpy) {
326 didAlloc = IMallocSpy_PostDidAlloc(Malloc32.pSpy, pv, fSpyed, didAlloc);
327 LeaveCriticalSection(&IMalloc32_SpyCS);
328 }
329 return didAlloc;
330 }
331
332 /******************************************************************************
333 * IMalloc32_HeapMinimize [VTABLE]
334 */
335 static VOID WINAPI IMalloc_fnHeapMinimize(LPMALLOC iface) {
336 TRACE("()\n");
337
338 if(Malloc32.pSpy) {
339 EnterCriticalSection(&IMalloc32_SpyCS);
340 IMallocSpy_PreHeapMinimize(Malloc32.pSpy);
341 }
342
343 if(Malloc32.pSpy) {
344 IMallocSpy_PostHeapMinimize(Malloc32.pSpy);
345 LeaveCriticalSection(&IMalloc32_SpyCS);
346 }
347 }
348
349 static const IMallocVtbl VT_IMalloc32 =
350 {
351 IMalloc_fnQueryInterface,
352 IMalloc_fnAddRefRelease,
353 IMalloc_fnAddRefRelease,
354 IMalloc_fnAlloc,
355 IMalloc_fnRealloc,
356 IMalloc_fnFree,
357 IMalloc_fnGetSize,
358 IMalloc_fnDidAlloc,
359 IMalloc_fnHeapMinimize
360 };
361
362 /******************************************************************************
363 * IMallocSpy implementation
364 *****************************************************************************/
365
366 /* set the vtable later */
367 static const IMallocSpyVtbl VT_IMallocSpy;
368
369 typedef struct {
370 const IMallocSpyVtbl *lpVtbl;
371 LONG ref;
372 } _MallocSpy;
373
374 /* this is the static object instance */
375 static _MallocSpy MallocSpy = {&VT_IMallocSpy, 0};
376
377 /******************************************************************************
378 * IMalloc32_QueryInterface [VTABLE]
379 */
380 static HRESULT WINAPI IMallocSpy_fnQueryInterface(LPMALLOCSPY iface,REFIID refiid,LPVOID *obj)
381 {
382
383 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
384
385 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMallocSpy,refiid)) {
386 *obj = &MallocSpy;
387 return S_OK;
388 }
389 return E_NOINTERFACE;
390 }
391
392 /******************************************************************************
393 * IMalloc32_AddRef [VTABLE]
394 */
395 static ULONG WINAPI IMallocSpy_fnAddRef (LPMALLOCSPY iface)
396 {
397
398 _MallocSpy *This = (_MallocSpy *)iface;
399 ULONG ref = InterlockedIncrement(&This->ref);
400
401 TRACE ("(%p)->(count=%u)\n", This, ref - 1);
402
403 return ref;
404 }
405
406 /******************************************************************************
407 * IMalloc32_AddRelease [VTABLE]
408 *
409 * NOTES
410 * Our MallocSpy is static. If the count reaches 0 we dump the leaks
411 */
412 static ULONG WINAPI IMallocSpy_fnRelease (LPMALLOCSPY iface)
413 {
414
415 _MallocSpy *This = (_MallocSpy *)iface;
416 ULONG ref = InterlockedDecrement(&This->ref);
417
418 TRACE ("(%p)->(count=%u)\n", This, ref + 1);
419
420 if (!ref) {
421 /* our allocation list MUST be empty here */
422 }
423 return ref;
424 }
425
426 static ULONG WINAPI IMallocSpy_fnPreAlloc(LPMALLOCSPY iface, ULONG cbRequest)
427 {
428 _MallocSpy *This = (_MallocSpy *)iface;
429 TRACE ("(%p)->(%u)\n", This, cbRequest);
430 return cbRequest;
431 }
432 static PVOID WINAPI IMallocSpy_fnPostAlloc(LPMALLOCSPY iface, void* pActual)
433 {
434 _MallocSpy *This = (_MallocSpy *)iface;
435 TRACE ("(%p)->(%p)\n", This, pActual);
436 return pActual;
437 }
438
439 static PVOID WINAPI IMallocSpy_fnPreFree(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
440 {
441 _MallocSpy *This = (_MallocSpy *)iface;
442 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
443 return pRequest;
444 }
445 static void WINAPI IMallocSpy_fnPostFree(LPMALLOCSPY iface, BOOL fSpyed)
446 {
447 _MallocSpy *This = (_MallocSpy *)iface;
448 TRACE ("(%p)->(%u)\n", This, fSpyed);
449 }
450
451 static ULONG WINAPI IMallocSpy_fnPreRealloc(LPMALLOCSPY iface, void* pRequest, ULONG cbRequest, void** ppNewRequest, BOOL fSpyed)
452 {
453 _MallocSpy *This = (_MallocSpy *)iface;
454 TRACE ("(%p)->(%p %u %u)\n", This, pRequest, cbRequest, fSpyed);
455 *ppNewRequest = pRequest;
456 return cbRequest;
457 }
458
459 static PVOID WINAPI IMallocSpy_fnPostRealloc(LPMALLOCSPY iface, void* pActual, BOOL fSpyed)
460 {
461 _MallocSpy *This = (_MallocSpy *)iface;
462 TRACE ("(%p)->(%p %u)\n", This, pActual, fSpyed);
463 return pActual;
464 }
465
466 static PVOID WINAPI IMallocSpy_fnPreGetSize(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
467 {
468 _MallocSpy *This = (_MallocSpy *)iface;
469 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
470 return pRequest;
471 }
472
473 static ULONG WINAPI IMallocSpy_fnPostGetSize(LPMALLOCSPY iface, ULONG cbActual, BOOL fSpyed)
474 {
475 _MallocSpy *This = (_MallocSpy *)iface;
476 TRACE ("(%p)->(%u %u)\n", This, cbActual, fSpyed);
477 return cbActual;
478 }
479
480 static PVOID WINAPI IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
481 {
482 _MallocSpy *This = (_MallocSpy *)iface;
483 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
484 return pRequest;
485 }
486
487 static int WINAPI IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed, int fActual)
488 {
489 _MallocSpy *This = (_MallocSpy *)iface;
490 TRACE ("(%p)->(%p %u %u)\n", This, pRequest, fSpyed, fActual);
491 return fActual;
492 }
493
494 static void WINAPI IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface)
495 {
496 _MallocSpy *This = (_MallocSpy *)iface;
497 TRACE ("(%p)->()\n", This);
498 }
499
500 static void WINAPI IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface)
501 {
502 _MallocSpy *This = (_MallocSpy *)iface;
503 TRACE ("(%p)->()\n", This);
504 }
505
506 static void MallocSpyDumpLeaks(void) {
507 TRACE("leaks: %u\n", Malloc32.SpyedAllocationsLeft);
508 }
509
510 static const IMallocSpyVtbl VT_IMallocSpy =
511 {
512 IMallocSpy_fnQueryInterface,
513 IMallocSpy_fnAddRef,
514 IMallocSpy_fnRelease,
515 IMallocSpy_fnPreAlloc,
516 IMallocSpy_fnPostAlloc,
517 IMallocSpy_fnPreFree,
518 IMallocSpy_fnPostFree,
519 IMallocSpy_fnPreRealloc,
520 IMallocSpy_fnPostRealloc,
521 IMallocSpy_fnPreGetSize,
522 IMallocSpy_fnPostGetSize,
523 IMallocSpy_fnPreDidAlloc,
524 IMallocSpy_fnPostDidAlloc,
525 IMallocSpy_fnPreHeapMinimize,
526 IMallocSpy_fnPostHeapMinimize
527 };
528
529 /******************************************************************************
530 * CoGetMalloc [OLE32.@]
531 *
532 * Retrieves the current IMalloc interface for the process.
533 *
534 * PARAMS
535 * dwMemContext [I]
536 * lpMalloc [O] Address where memory allocator object will be stored.
537 *
538 * RETURNS
539 * Success: S_OK.
540 * Failure: HRESULT code.
541 */
542 HRESULT WINAPI CoGetMalloc(DWORD dwMemContext, LPMALLOC *lpMalloc)
543 {
544 *lpMalloc = (LPMALLOC)&Malloc32;
545 return S_OK;
546 }
547
548 /***********************************************************************
549 * CoTaskMemAlloc [OLE32.@]
550 *
551 * Allocates memory using the current process memory allocator.
552 *
553 * PARAMS
554 * size [I] Size of the memory block to allocate.
555 *
556 * RETURNS
557 * Success: Pointer to newly allocated memory block.
558 * Failure: NULL.
559 */
560 LPVOID WINAPI CoTaskMemAlloc(ULONG size)
561 {
562 return IMalloc_Alloc((LPMALLOC)&Malloc32,size);
563 }
564
565 /***********************************************************************
566 * CoTaskMemFree [OLE32.@]
567 *
568 * Frees memory allocated from the current process memory allocator.
569 *
570 * PARAMS
571 * ptr [I] Memory block to free.
572 *
573 * RETURNS
574 * Nothing.
575 */
576 VOID WINAPI CoTaskMemFree(LPVOID ptr)
577 {
578 IMalloc_Free((LPMALLOC)&Malloc32, ptr);
579 }
580
581 /***********************************************************************
582 * CoTaskMemRealloc [OLE32.@]
583 *
584 * Allocates memory using the current process memory allocator.
585 *
586 * PARAMS
587 * pvOld [I] Pointer to old memory block.
588 * size [I] Size of the new memory block.
589 *
590 * RETURNS
591 * Success: Pointer to newly allocated memory block.
592 * Failure: NULL.
593 */
594 LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, ULONG size)
595 {
596 return IMalloc_Realloc((LPMALLOC)&Malloc32, pvOld, size);
597 }
598
599 /***********************************************************************
600 * CoRegisterMallocSpy [OLE32.@]
601 *
602 * Registers an object that receives notifications on memory allocations and
603 * frees.
604 *
605 * PARAMS
606 * pMallocSpy [I] New spy object.
607 *
608 * RETURNS
609 * Success: S_OK.
610 * Failure: HRESULT code.
611 *
612 * NOTES
613 * if a mallocspy is already registered, we can't do it again since
614 * only the spy knows, how to free a memory block
615 */
616 HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy)
617 {
618 IMallocSpy* pSpy;
619 HRESULT hres = E_INVALIDARG;
620
621 TRACE("\n");
622
623 /* HACK TO ACTIVATE OUT SPY */
624 if (pMallocSpy == (LPVOID)-1) pMallocSpy =(IMallocSpy*)&MallocSpy;
625
626 if(Malloc32.pSpy) return CO_E_OBJISREG;
627
628 EnterCriticalSection(&IMalloc32_SpyCS);
629
630 if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy, &IID_IMallocSpy, (LPVOID*)&pSpy))) {
631 Malloc32.pSpy = pSpy;
632 hres = S_OK;
633 }
634
635 LeaveCriticalSection(&IMalloc32_SpyCS);
636
637 return hres;
638 }
639
640 /***********************************************************************
641 * CoRevokeMallocSpy [OLE32.@]
642 *
643 * Revokes a previously registered object that receives notifications on memory
644 * allocations and frees.
645 *
646 * PARAMS
647 * pMallocSpy [I] New spy object.
648 *
649 * RETURNS
650 * Success: S_OK.
651 * Failure: HRESULT code.
652 *
653 * NOTES
654 * we can't revoke a malloc spy as long as memory blocks allocated with
655 * the spy are active since only the spy knows how to free them
656 */
657 HRESULT WINAPI CoRevokeMallocSpy(void)
658 {
659 HRESULT hres = S_OK;
660 TRACE("\n");
661
662 EnterCriticalSection(&IMalloc32_SpyCS);
663
664 /* if it's our spy it's time to dump the leaks */
665 if (Malloc32.pSpy == (IMallocSpy*)&MallocSpy) {
666 MallocSpyDumpLeaks();
667 }
668
669 if (Malloc32.SpyedAllocationsLeft) {
670 TRACE("SpyReleasePending with %u allocations left\n", Malloc32.SpyedAllocationsLeft);
671 Malloc32.SpyReleasePending = TRUE;
672 hres = E_ACCESSDENIED;
673 } else {
674 IMallocSpy_Release(Malloc32.pSpy);
675 Malloc32.pSpy = NULL;
676 }
677 LeaveCriticalSection(&IMalloc32_SpyCS);
678
679 return S_OK;
680 }
681
682 /******************************************************************************
683 * IsValidInterface [OLE32.@]
684 *
685 * Determines whether a pointer is a valid interface.
686 *
687 * PARAMS
688 * punk [I] Interface to be tested.
689 *
690 * RETURNS
691 * TRUE, if the passed pointer is a valid interface, or FALSE otherwise.
692 */
693 BOOL WINAPI IsValidInterface(LPUNKNOWN punk)
694 {
695 return !(
696 IsBadReadPtr(punk,4) ||
697 IsBadReadPtr(punk->lpVtbl,4) ||
698 IsBadReadPtr(punk->lpVtbl->QueryInterface,9) ||
699 IsBadCodePtr((FARPROC)punk->lpVtbl->QueryInterface)
700 );
701 }
702
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.