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