xref: /reactos/dll/win32/ole32/ifs.c (revision 019f21ee)
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 <ctype.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26 
27 #define COBJMACROS
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(olemalloc);
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 static const IMallocVtbl VT_IMalloc32;
49 
50 typedef struct {
51         IMalloc IMalloc_iface;
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         DWORD SpyedBlockTableLength;/* size of the table*/
58 } _Malloc32;
59 
60 /* this is the static object instance */
61 static _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, { (DWORD_PTR)(__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 BOOL SetSpyedBlockTableLength ( DWORD NewLength )
75 {
76 	LPVOID *NewSpyedBlocks;
77 
78 	if (!Malloc32.SpyedBlocks) NewSpyedBlocks = LocalAlloc(LMEM_ZEROINIT, NewLength * sizeof(PVOID));
79 	else NewSpyedBlocks = LocalReAlloc(Malloc32.SpyedBlocks, NewLength * sizeof(PVOID), LMEM_ZEROINIT | LMEM_MOVEABLE);
80 	if (NewSpyedBlocks) {
81 		Malloc32.SpyedBlocks = NewSpyedBlocks;
82 		Malloc32.SpyedBlockTableLength = NewLength;
83 	}
84 
85 	return NewSpyedBlocks != NULL;
86 }
87 
88 /* add a location to the table */
89 static BOOL AddMemoryLocation(LPVOID * pMem)
90 {
91         LPVOID * Current;
92 
93 	/* allocate the table if not already allocated */
94         if (!Malloc32.SpyedBlockTableLength && !SetSpyedBlockTableLength(0x1000))
95             return FALSE;
96 
97 	/* find a free location */
98 	Current = Malloc32.SpyedBlocks;
99 	while (*Current) {
100             Current++;
101 	    if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) {
102 	        /* no more space in table, grow it */
103                 DWORD old_length = Malloc32.SpyedBlockTableLength;
104                 if (!SetSpyedBlockTableLength( Malloc32.SpyedBlockTableLength + 0x1000))
105                     return FALSE;
106                 Current = Malloc32.SpyedBlocks + old_length;
107 	    }
108 	};
109 
110 	/* put the location in our table */
111 	*Current = pMem;
112         Malloc32.SpyedAllocationsLeft++;
113 	/*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
114         return TRUE;
115 }
116 
117 static BOOL RemoveMemoryLocation(LPCVOID pMem)
118 {
119         LPVOID * Current;
120 
121 	/* allocate the table if not already allocated */
122         if (!Malloc32.SpyedBlockTableLength && !SetSpyedBlockTableLength(0x1000))
123             return FALSE;
124 
125 	Current = Malloc32.SpyedBlocks;
126 
127 	/* find the location */
128 	while (*Current != pMem) {
129             Current++;
130             if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength)
131                 return FALSE; /* not found  */
132 	}
133 
134 	/* location found */
135         Malloc32.SpyedAllocationsLeft--;
136 	/*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
137 	*Current = NULL;
138         return TRUE;
139 }
140 
141 /******************************************************************************
142  *	IMalloc32_QueryInterface	[VTABLE]
143  */
144 static HRESULT WINAPI IMalloc_fnQueryInterface(IMalloc *iface, REFIID refiid, void **obj)
145 {
146 	TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
147 
148 	if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMalloc,refiid)) {
149 		*obj = &Malloc32;
150 		return S_OK;
151 	}
152 	return E_NOINTERFACE;
153 }
154 
155 /******************************************************************************
156  *	IMalloc32_AddRefRelease		[VTABLE]
157  */
158 static ULONG WINAPI IMalloc_fnAddRefRelease(IMalloc *iface)
159 {
160 	return 1;
161 }
162 
163 /******************************************************************************
164  *	IMalloc32_Alloc 		[VTABLE]
165  */
166 static void * WINAPI IMalloc_fnAlloc(IMalloc *iface, SIZE_T cb)
167 {
168 	void *addr;
169 
170 	TRACE("(%ld)\n",cb);
171 
172 	if(Malloc32.pSpy) {
173 	    SIZE_T preAllocResult;
174 
175 	    EnterCriticalSection(&IMalloc32_SpyCS);
176 	    preAllocResult = IMallocSpy_PreAlloc(Malloc32.pSpy, cb);
177 	    if ((cb != 0) && (preAllocResult == 0)) {
178 		/* PreAlloc can force Alloc to fail, but not if cb == 0 */
179 		TRACE("returning null\n");
180 		LeaveCriticalSection(&IMalloc32_SpyCS);
181 		return NULL;
182 	    }
183 	}
184 
185 	addr = HeapAlloc(GetProcessHeap(),0,cb);
186 
187 	if(Malloc32.pSpy) {
188 	    addr = IMallocSpy_PostAlloc(Malloc32.pSpy, addr);
189 	    if (addr) AddMemoryLocation(addr);
190 	    LeaveCriticalSection(&IMalloc32_SpyCS);
191 	}
192 
193 	TRACE("--(%p)\n",addr);
194 	return addr;
195 }
196 
197 /******************************************************************************
198  * IMalloc32_Realloc [VTABLE]
199  */
200 static void * WINAPI IMalloc_fnRealloc(IMalloc *iface, void *pv, SIZE_T cb)
201 {
202 	void *pNewMemory;
203 
204 	TRACE("(%p,%ld)\n",pv,cb);
205 
206 	if(Malloc32.pSpy) {
207 	    void *pRealMemory;
208 	    BOOL fSpyed;
209 
210 	    EnterCriticalSection(&IMalloc32_SpyCS);
211             fSpyed = RemoveMemoryLocation(pv);
212             cb = IMallocSpy_PreRealloc(Malloc32.pSpy, pv, cb, &pRealMemory, fSpyed);
213 
214 	    /* check if can release the spy */
215 	    if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
216 	        IMallocSpy_Release(Malloc32.pSpy);
217 		Malloc32.SpyReleasePending = FALSE;
218 		Malloc32.pSpy = NULL;
219 		LeaveCriticalSection(&IMalloc32_SpyCS);
220 	    }
221 
222 	    if (0==cb) {
223 		/* PreRealloc can force Realloc to fail */
224 		if (Malloc32.pSpy)
225 		    LeaveCriticalSection(&IMalloc32_SpyCS);
226 		return NULL;
227 	    }
228 
229 	    pv = pRealMemory;
230 	}
231 
232         if (!pv) pNewMemory = HeapAlloc(GetProcessHeap(),0,cb);
233 	else if (cb) pNewMemory = HeapReAlloc(GetProcessHeap(),0,pv,cb);
234 	else {
235 	    HeapFree(GetProcessHeap(),0,pv);
236 	    pNewMemory = NULL;
237 	}
238 
239 	if(Malloc32.pSpy) {
240 	    pNewMemory = IMallocSpy_PostRealloc(Malloc32.pSpy, pNewMemory, TRUE);
241 	    if (pNewMemory) AddMemoryLocation(pNewMemory);
242             LeaveCriticalSection(&IMalloc32_SpyCS);
243 	}
244 
245 	TRACE("--(%p)\n",pNewMemory);
246 	return pNewMemory;
247 }
248 
249 /******************************************************************************
250  * IMalloc32_Free [VTABLE]
251  */
252 static void WINAPI IMalloc_fnFree(IMalloc *iface, void *pv)
253 {
254         BOOL fSpyed = FALSE;
255 
256 	TRACE("(%p)\n",pv);
257 
258 	if(!pv)
259 	    return;
260 
261 	if(Malloc32.pSpy) {
262             EnterCriticalSection(&IMalloc32_SpyCS);
263             fSpyed = RemoveMemoryLocation(pv);
264 	    pv = IMallocSpy_PreFree(Malloc32.pSpy, pv, fSpyed);
265 	}
266 
267 	HeapFree(GetProcessHeap(),0,pv);
268 
269 	if(Malloc32.pSpy) {
270 	    IMallocSpy_PostFree(Malloc32.pSpy, fSpyed);
271 
272 	    /* check if can release the spy */
273 	    if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
274 	        IMallocSpy_Release(Malloc32.pSpy);
275 		Malloc32.SpyReleasePending = FALSE;
276 		Malloc32.pSpy = NULL;
277 	    }
278 
279 	    LeaveCriticalSection(&IMalloc32_SpyCS);
280         }
281 }
282 
283 /******************************************************************************
284  * IMalloc32_GetSize [VTABLE]
285  *
286  * NOTES
287  *  FIXME returns:
288  *      win95:  size allocated (4 byte boundarys)
289  *      win2k:  size originally requested !!! (allocated on 8 byte boundarys)
290  */
291 static SIZE_T WINAPI IMalloc_fnGetSize(IMalloc *iface, void *pv)
292 {
293         SIZE_T cb;
294         BOOL fSpyed = FALSE;
295 
296 	TRACE("(%p)\n",pv);
297 
298 	if(Malloc32.pSpy) {
299             EnterCriticalSection(&IMalloc32_SpyCS);
300 	    pv = IMallocSpy_PreGetSize(Malloc32.pSpy, pv, fSpyed);
301 	}
302 
303 	cb = HeapSize(GetProcessHeap(),0,pv);
304 
305 	if(Malloc32.pSpy) {
306 	    cb = IMallocSpy_PostGetSize(Malloc32.pSpy, cb, fSpyed);
307 	    LeaveCriticalSection(&IMalloc32_SpyCS);
308 	}
309 
310 	return cb;
311 }
312 
313 /******************************************************************************
314  * IMalloc32_DidAlloc [VTABLE]
315  */
316 static INT WINAPI IMalloc_fnDidAlloc(IMalloc *iface, void *pv)
317 {
318         BOOL fSpyed = FALSE;
319 	int didAlloc;
320 
321 	TRACE("(%p)\n",pv);
322 
323 	if(Malloc32.pSpy) {
324             EnterCriticalSection(&IMalloc32_SpyCS);
325 	    pv = IMallocSpy_PreDidAlloc(Malloc32.pSpy, pv, fSpyed);
326 	}
327 
328 	didAlloc = -1;
329 
330 	if(Malloc32.pSpy) {
331 	    didAlloc = IMallocSpy_PostDidAlloc(Malloc32.pSpy, pv, fSpyed, didAlloc);
332             LeaveCriticalSection(&IMalloc32_SpyCS);
333 	}
334 	return didAlloc;
335 }
336 
337 /******************************************************************************
338  * IMalloc32_HeapMinimize [VTABLE]
339  */
340 static void WINAPI IMalloc_fnHeapMinimize(IMalloc *iface)
341 {
342 	TRACE("()\n");
343 
344 	if(Malloc32.pSpy) {
345             EnterCriticalSection(&IMalloc32_SpyCS);
346 	    IMallocSpy_PreHeapMinimize(Malloc32.pSpy);
347 	}
348 
349 	if(Malloc32.pSpy) {
350 	    IMallocSpy_PostHeapMinimize(Malloc32.pSpy);
351             LeaveCriticalSection(&IMalloc32_SpyCS);
352 	}
353 }
354 
355 static const IMallocVtbl VT_IMalloc32 =
356 {
357 	IMalloc_fnQueryInterface,
358 	IMalloc_fnAddRefRelease,
359 	IMalloc_fnAddRefRelease,
360 	IMalloc_fnAlloc,
361 	IMalloc_fnRealloc,
362 	IMalloc_fnFree,
363 	IMalloc_fnGetSize,
364 	IMalloc_fnDidAlloc,
365 	IMalloc_fnHeapMinimize
366 };
367 
368 /******************************************************************************
369  *		CoGetMalloc	[OLE32.@]
370  *
371  * Retrieves the current IMalloc interface for the process.
372  *
373  * PARAMS
374  *  context [I] Should always be MEMCTX_TASK.
375  *  imalloc [O] Address where memory allocator object will be stored.
376  *
377  * RETURNS
378  *	Success: S_OK.
379  *  Failure: HRESULT code.
380  */
381 HRESULT WINAPI CoGetMalloc(DWORD context, IMalloc **imalloc)
382 {
383     if (context != MEMCTX_TASK) {
384         *imalloc = NULL;
385         return E_INVALIDARG;
386     }
387 
388     *imalloc = &Malloc32.IMalloc_iface;
389     return S_OK;
390 }
391 
392 /***********************************************************************
393  *           CoTaskMemAlloc     [OLE32.@]
394  *
395  * Allocates memory using the current process memory allocator.
396  *
397  * PARAMS
398  *  size [I] Size of the memory block to allocate.
399  *
400  * RETURNS
401  * 	Success: Pointer to newly allocated memory block.
402  *  Failure: NULL.
403  */
404 LPVOID WINAPI CoTaskMemAlloc(SIZE_T size)
405 {
406         return IMalloc_Alloc(&Malloc32.IMalloc_iface,size);
407 }
408 
409 /***********************************************************************
410  *           CoTaskMemFree      [OLE32.@]
411  *
412  * Frees memory allocated from the current process memory allocator.
413  *
414  * PARAMS
415  *  ptr [I] Memory block to free.
416  *
417  * RETURNS
418  *  Nothing.
419  */
420 VOID WINAPI CoTaskMemFree(LPVOID ptr)
421 {
422         IMalloc_Free(&Malloc32.IMalloc_iface, ptr);
423 }
424 
425 /***********************************************************************
426  *           CoTaskMemRealloc   [OLE32.@]
427  *
428  * Allocates memory using the current process memory allocator.
429  *
430  * PARAMS
431  *  pvOld [I] Pointer to old memory block.
432  *  size  [I] Size of the new memory block.
433  *
434  * RETURNS
435  * 	Success: Pointer to newly allocated memory block.
436  *  Failure: NULL.
437  */
438 LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, SIZE_T size)
439 {
440         return IMalloc_Realloc(&Malloc32.IMalloc_iface, pvOld, size);
441 }
442 
443 /***********************************************************************
444  *           CoRegisterMallocSpy        [OLE32.@]
445  *
446  * Registers an object that receives notifications on memory allocations and
447  * frees.
448  *
449  * PARAMS
450  *  pMallocSpy [I] New spy object.
451  *
452  * RETURNS
453  *  Success: S_OK.
454  *  Failure: HRESULT code.
455  *
456  * NOTES
457  *  if a mallocspy is already registered, we can't do it again since
458  *  only the spy knows, how to free a memory block
459  */
460 HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy)
461 {
462 	IMallocSpy* pSpy;
463         HRESULT hres = E_INVALIDARG;
464 
465 	TRACE("%p\n", pMallocSpy);
466 
467 	if(!pMallocSpy) return E_INVALIDARG;
468 
469         EnterCriticalSection(&IMalloc32_SpyCS);
470 
471 	if (Malloc32.pSpy)
472 	    hres = CO_E_OBJISREG;
473 	else if (SUCCEEDED(IMallocSpy_QueryInterface(pMallocSpy, &IID_IMallocSpy, (void**)&pSpy))) {
474 	    Malloc32.pSpy = pSpy;
475 	    hres = S_OK;
476 	}
477 
478 	LeaveCriticalSection(&IMalloc32_SpyCS);
479 
480 	return hres;
481 }
482 
483 /***********************************************************************
484  *           CoRevokeMallocSpy  [OLE32.@]
485  *
486  * Revokes a previously registered object that receives notifications on memory
487  * allocations and frees.
488  *
489  * PARAMS
490  *  pMallocSpy [I] New spy object.
491  *
492  * RETURNS
493  *  Success: S_OK.
494  *  Failure: HRESULT code.
495  *
496  * NOTES
497  *  we can't revoke a malloc spy as long as memory blocks allocated with
498  *  the spy are active since only the spy knows how to free them
499  */
500 HRESULT WINAPI CoRevokeMallocSpy(void)
501 {
502 	HRESULT hres = S_OK;
503 	TRACE("\n");
504 
505         EnterCriticalSection(&IMalloc32_SpyCS);
506 
507 	if (!Malloc32.pSpy)
508 	    hres = CO_E_OBJNOTREG;
509 	else if (Malloc32.SpyedAllocationsLeft) {
510             TRACE("SpyReleasePending with %u allocations left\n", Malloc32.SpyedAllocationsLeft);
511 	    Malloc32.SpyReleasePending = TRUE;
512 	    hres = E_ACCESSDENIED;
513 	} else {
514 	    IMallocSpy_Release(Malloc32.pSpy);
515 	    Malloc32.pSpy = NULL;
516         }
517 	LeaveCriticalSection(&IMalloc32_SpyCS);
518 
519 	return hres;
520 }
521 
522 /******************************************************************************
523  *		IsValidInterface	[OLE32.@]
524  *
525  * Determines whether a pointer is a valid interface.
526  *
527  * PARAMS
528  *  punk [I] Interface to be tested.
529  *
530  * RETURNS
531  *  TRUE, if the passed pointer is a valid interface, or FALSE otherwise.
532  */
533 BOOL WINAPI IsValidInterface(LPUNKNOWN punk)
534 {
535 	return !(
536 		IsBadReadPtr(punk,4)					||
537 		IsBadReadPtr(punk->lpVtbl,4)				||
538 		IsBadReadPtr(punk->lpVtbl->QueryInterface,9)	||
539 		IsBadCodePtr((FARPROC)punk->lpVtbl->QueryInterface)
540 	);
541 }
542