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