ReactOS  0.4.15-dev-1018-g0695ecb
ifs.c
Go to the documentation of this file.
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 
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 {
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 */
66 {
67  0, 0, &IMalloc32_SpyCS,
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 */
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;
83  }
84 
85  return NewSpyedBlocks != NULL;
86 }
87 
88 /* add a location to the table */
90 {
91  LPVOID * Current;
92 
93  /* allocate the table if not already allocated */
95  return FALSE;
96 
97  /* find a free location */
98  Current = Malloc32.SpyedBlocks;
99  while (*Current) {
100  Current++;
102  /* no more space in table, grow it */
103  DWORD old_length = Malloc32.SpyedBlockTableLength;
105  return FALSE;
106  Current = Malloc32.SpyedBlocks + old_length;
107  }
108  };
109 
110  /* put the location in our table */
111  *Current = pMem;
113  /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
114  return TRUE;
115 }
116 
117 static void** mallocspy_is_allocation_spyed(const void *mem)
118 {
119  void **current = Malloc32.SpyedBlocks;
120 
121  while (*current != mem)
122  {
123  current++;
125  return NULL;
126  }
127 
128  return current;
129 }
130 
132 {
133  LPVOID * Current;
134 
135  /* allocate the table if not already allocated */
137  return FALSE;
138 
139  if (!(Current = mallocspy_is_allocation_spyed(pMem)))
140  return FALSE;
141 
142  /* location found */
144  /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
145  *Current = NULL;
146  return TRUE;
147 }
148 
149 /******************************************************************************
150  * IMalloc32_QueryInterface [VTABLE]
151  */
152 static HRESULT WINAPI IMalloc_fnQueryInterface(IMalloc *iface, REFIID refiid, void **obj)
153 {
154  TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
155 
156  if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMalloc,refiid)) {
157  *obj = &Malloc32;
158  return S_OK;
159  }
160  return E_NOINTERFACE;
161 }
162 
163 /******************************************************************************
164  * IMalloc32_AddRefRelease [VTABLE]
165  */
167 {
168  return 1;
169 }
170 
171 /******************************************************************************
172  * IMalloc32_Alloc [VTABLE]
173  */
174 static void * WINAPI IMalloc_fnAlloc(IMalloc *iface, SIZE_T cb)
175 {
176  void *addr;
177 
178  TRACE("(%ld)\n",cb);
179 
180  if(Malloc32.pSpy) {
181  SIZE_T preAllocResult;
182 
184  preAllocResult = IMallocSpy_PreAlloc(Malloc32.pSpy, cb);
185  if ((cb != 0) && (preAllocResult == 0)) {
186  /* PreAlloc can force Alloc to fail, but not if cb == 0 */
187  TRACE("returning null\n");
189  return NULL;
190  }
191  }
192 
194 
195  if(Malloc32.pSpy) {
196  addr = IMallocSpy_PostAlloc(Malloc32.pSpy, addr);
199  }
200 
201  TRACE("--(%p)\n",addr);
202  return addr;
203 }
204 
205 /******************************************************************************
206  * IMalloc32_Realloc [VTABLE]
207  */
208 static void * WINAPI IMalloc_fnRealloc(IMalloc *iface, void *pv, SIZE_T cb)
209 {
210  void *pNewMemory;
211 
212  TRACE("(%p,%ld)\n",pv,cb);
213 
214  if(Malloc32.pSpy) {
215  void *pRealMemory;
216  BOOL fSpyed;
217 
219  fSpyed = RemoveMemoryLocation(pv);
220  cb = IMallocSpy_PreRealloc(Malloc32.pSpy, pv, cb, &pRealMemory, fSpyed);
221 
222  /* check if can release the spy */
224  IMallocSpy_Release(Malloc32.pSpy);
226  Malloc32.pSpy = NULL;
228  }
229 
230  if (0==cb) {
231  /* PreRealloc can force Realloc to fail */
232  if (Malloc32.pSpy)
234  return NULL;
235  }
236 
237  pv = pRealMemory;
238  }
239 
240  if (!pv) pNewMemory = HeapAlloc(GetProcessHeap(),0,cb);
241  else if (cb) pNewMemory = HeapReAlloc(GetProcessHeap(),0,pv,cb);
242  else {
243  HeapFree(GetProcessHeap(),0,pv);
244  pNewMemory = NULL;
245  }
246 
247  if(Malloc32.pSpy) {
248  pNewMemory = IMallocSpy_PostRealloc(Malloc32.pSpy, pNewMemory, TRUE);
249  if (pNewMemory) AddMemoryLocation(pNewMemory);
251  }
252 
253  TRACE("--(%p)\n",pNewMemory);
254  return pNewMemory;
255 }
256 
257 /******************************************************************************
258  * IMalloc32_Free [VTABLE]
259  */
260 static void WINAPI IMalloc_fnFree(IMalloc *iface, void *pv)
261 {
262  BOOL fSpyed = FALSE;
263 
264  TRACE("(%p)\n",pv);
265 
266  if(!pv)
267  return;
268 
269  if(Malloc32.pSpy) {
271  fSpyed = RemoveMemoryLocation(pv);
272  pv = IMallocSpy_PreFree(Malloc32.pSpy, pv, fSpyed);
273  }
274 
275  HeapFree(GetProcessHeap(),0,pv);
276 
277  if(Malloc32.pSpy) {
278  IMallocSpy_PostFree(Malloc32.pSpy, fSpyed);
279 
280  /* check if can release the spy */
282  IMallocSpy_Release(Malloc32.pSpy);
284  Malloc32.pSpy = NULL;
285  }
286 
288  }
289 }
290 
291 /******************************************************************************
292  * IMalloc32_GetSize [VTABLE]
293  *
294  * NOTES
295  * FIXME returns:
296  * win95: size allocated (4 byte boundarys)
297  * win2k: size originally requested !!! (allocated on 8 byte boundarys)
298  */
300 {
301  BOOL spyed_block = FALSE, spy_active = FALSE;
302  SIZE_T size;
303 
304  TRACE("(%p)\n", mem);
305 
306  if (!mem)
307  return (SIZE_T)-1;
308 
309  if (Malloc32.pSpy)
310  {
312  spyed_block = !!mallocspy_is_allocation_spyed(mem);
313  spy_active = TRUE;
314  mem = IMallocSpy_PreGetSize(Malloc32.pSpy, mem, spyed_block);
315  }
316 
317  size = HeapSize(GetProcessHeap(), 0, mem);
318 
319  if (spy_active)
320  {
321  size = IMallocSpy_PostGetSize(Malloc32.pSpy, size, spyed_block);
323  }
324  return size;
325 }
326 
327 /******************************************************************************
328  * IMalloc32_DidAlloc [VTABLE]
329  */
330 static INT WINAPI IMalloc_fnDidAlloc(IMalloc *iface, void *mem)
331 {
332  BOOL spyed_block = FALSE, spy_active = FALSE;
333  int did_alloc;
334 
335  TRACE("(%p)\n", mem);
336 
337  if (!mem)
338  return -1;
339 
340  if (Malloc32.pSpy)
341  {
343  spyed_block = !!mallocspy_is_allocation_spyed(mem);
344  spy_active = TRUE;
345  mem = IMallocSpy_PreDidAlloc(Malloc32.pSpy, mem, spyed_block);
346  }
347 
348  did_alloc = HeapValidate(GetProcessHeap(), 0, mem);
349 
350  if (spy_active)
351  {
352  did_alloc = IMallocSpy_PostDidAlloc(Malloc32.pSpy, mem, spyed_block, did_alloc);
354  }
355 
356  return did_alloc;
357 }
358 
359 /******************************************************************************
360  * IMalloc32_HeapMinimize [VTABLE]
361  */
363 {
364  TRACE("()\n");
365 
366  if(Malloc32.pSpy) {
368  IMallocSpy_PreHeapMinimize(Malloc32.pSpy);
369  }
370 
371  if(Malloc32.pSpy) {
372  IMallocSpy_PostHeapMinimize(Malloc32.pSpy);
374  }
375 }
376 
377 static const IMallocVtbl VT_IMalloc32 =
378 {
388 };
389 
390 /******************************************************************************
391  * CoGetMalloc [OLE32.@]
392  *
393  * Retrieves the current IMalloc interface for the process.
394  *
395  * PARAMS
396  * context [I] Should always be MEMCTX_TASK.
397  * imalloc [O] Address where memory allocator object will be stored.
398  *
399  * RETURNS
400  * Success: S_OK.
401  * Failure: HRESULT code.
402  */
404 {
405  if (context != MEMCTX_TASK) {
406  *imalloc = NULL;
407  return E_INVALIDARG;
408  }
409 
410  *imalloc = &Malloc32.IMalloc_iface;
411  return S_OK;
412 }
413 
414 /***********************************************************************
415  * CoTaskMemAlloc [OLE32.@]
416  *
417  * Allocates memory using the current process memory allocator.
418  *
419  * PARAMS
420  * size [I] Size of the memory block to allocate.
421  *
422  * RETURNS
423  * Success: Pointer to newly allocated memory block.
424  * Failure: NULL.
425  */
427 {
428  return IMalloc_Alloc(&Malloc32.IMalloc_iface,size);
429 }
430 
431 /***********************************************************************
432  * CoTaskMemFree [OLE32.@]
433  *
434  * Frees memory allocated from the current process memory allocator.
435  *
436  * PARAMS
437  * ptr [I] Memory block to free.
438  *
439  * RETURNS
440  * Nothing.
441  */
443 {
444  IMalloc_Free(&Malloc32.IMalloc_iface, ptr);
445 }
446 
447 /***********************************************************************
448  * CoTaskMemRealloc [OLE32.@]
449  *
450  * Allocates memory using the current process memory allocator.
451  *
452  * PARAMS
453  * pvOld [I] Pointer to old memory block.
454  * size [I] Size of the new memory block.
455  *
456  * RETURNS
457  * Success: Pointer to newly allocated memory block.
458  * Failure: NULL.
459  */
461 {
462  return IMalloc_Realloc(&Malloc32.IMalloc_iface, pvOld, size);
463 }
464 
465 /***********************************************************************
466  * CoRegisterMallocSpy [OLE32.@]
467  *
468  * Registers an object that receives notifications on memory allocations and
469  * frees.
470  *
471  * PARAMS
472  * pMallocSpy [I] New spy object.
473  *
474  * RETURNS
475  * Success: S_OK.
476  * Failure: HRESULT code.
477  *
478  * NOTES
479  * if a mallocspy is already registered, we can't do it again since
480  * only the spy knows, how to free a memory block
481  */
483 {
484  IMallocSpy* pSpy;
486 
487  TRACE("%p\n", pMallocSpy);
488 
489  if(!pMallocSpy) return E_INVALIDARG;
490 
492 
493  if (Malloc32.pSpy)
495  else if (SUCCEEDED(IMallocSpy_QueryInterface(pMallocSpy, &IID_IMallocSpy, (void**)&pSpy))) {
496  Malloc32.pSpy = pSpy;
497  hres = S_OK;
498  }
499 
501 
502  return hres;
503 }
504 
505 /***********************************************************************
506  * CoRevokeMallocSpy [OLE32.@]
507  *
508  * Revokes a previously registered object that receives notifications on memory
509  * allocations and frees.
510  *
511  * PARAMS
512  * pMallocSpy [I] New spy object.
513  *
514  * RETURNS
515  * Success: S_OK.
516  * Failure: HRESULT code.
517  *
518  * NOTES
519  * we can't revoke a malloc spy as long as memory blocks allocated with
520  * the spy are active since only the spy knows how to free them
521  */
523 {
524  HRESULT hres = S_OK;
525  TRACE("\n");
526 
528 
529  if (!Malloc32.pSpy)
531  else if (Malloc32.SpyedAllocationsLeft) {
532  TRACE("SpyReleasePending with %u allocations left\n", Malloc32.SpyedAllocationsLeft);
535  } else {
536  IMallocSpy_Release(Malloc32.pSpy);
537  Malloc32.pSpy = NULL;
538  }
540 
541  return hres;
542 }
543 
544 /******************************************************************************
545  * IsValidInterface [OLE32.@]
546  *
547  * Determines whether a pointer is a valid interface.
548  *
549  * PARAMS
550  * punk [I] Interface to be tested.
551  *
552  * RETURNS
553  * TRUE, if the passed pointer is a valid interface, or FALSE otherwise.
554  */
556 {
557  return !(
558  IsBadReadPtr(punk,4) ||
559  IsBadReadPtr(punk->lpVtbl,4) ||
560  IsBadReadPtr(punk->lpVtbl->QueryInterface,9) ||
561  IsBadCodePtr((FARPROC)punk->lpVtbl->QueryInterface)
562  );
563 }
#define E_ACCESSDENIED
Definition: winerror.h:2849
LPVOID * SpyedBlocks
Definition: ifs.c:56
#define REFIID
Definition: guiddef.h:118
#define E_NOINTERFACE
Definition: winerror.h:2364
BOOL SpyReleasePending
Definition: ifs.c:55
VOID WINAPI CoTaskMemFree(LPVOID ptr)
Definition: ifs.c:442
#define DWORD_PTR
Definition: treelist.c:76
Definition: http.c:7094
#define TRUE
Definition: types.h:120
static void *WINAPI IMalloc_fnAlloc(IMalloc *iface, SIZE_T cb)
Definition: ifs.c:174
static INT WINAPI IMalloc_fnDidAlloc(IMalloc *iface, void *mem)
Definition: ifs.c:330
static BOOL RemoveMemoryLocation(LPCVOID pMem)
Definition: ifs.c:131
static void *WINAPI IMalloc_fnRealloc(IMalloc *iface, void *pv, SIZE_T cb)
Definition: ifs.c:208
BOOL WINAPI HeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem)
Definition: heapmem.c:156
IMalloc IMalloc_iface
Definition: ifs.c:51
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
Definition: ifs.c:50
SIZE_T WINAPI HeapSize(HANDLE, DWORD, LPCVOID)
int32_t INT
Definition: typedefs.h:58
static CRITICAL_SECTION IMalloc32_SpyCS
Definition: ifs.c:64
static USHORT USHORT * NewLength
BOOL NTAPI IsBadCodePtr(FARPROC lpfn)
Definition: except.c:874
HRESULT WINAPI CoGetMalloc(DWORD context, IMalloc **imalloc)
Definition: ifs.c:403
#define FALSE
Definition: types.h:117
unsigned int BOOL
Definition: ntddk_ex.h:94
HRESULT WINAPI CoRevokeMallocSpy(void)
Definition: ifs.c:522
static LPUNKNOWN
Definition: ndr_ole.c:49
static ULONG WINAPI IMalloc_fnAddRefRelease(IMalloc *iface)
Definition: ifs.c:166
static PVOID ptr
Definition: dispmode.c:27
WINE_DEFAULT_DEBUG_CHANNEL(olemalloc)
#define E_INVALIDARG
Definition: ddrawi.h:101
smooth NULL
Definition: ftsmooth.c:416
static const IMallocVtbl VT_IMalloc32
Definition: ifs.c:48
#define debugstr_guid
Definition: kernel32.h:35
static void ** mallocspy_is_allocation_spyed(const void *mem)
Definition: ifs.c:117
DWORD dummy
Definition: ifs.c:52
static void WINAPI IMalloc_fnHeapMinimize(IMalloc *iface)
Definition: ifs.c:362
#define TRACE(s)
Definition: solgame.cpp:4
GLsizeiptr size
Definition: glext.h:5919
HRESULT hres
Definition: protocol.c:465
#define GetProcessHeap()
Definition: compat.h:484
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
#define LMEM_ZEROINIT
Definition: winbase.h:356
LONG HRESULT
Definition: typedefs.h:79
#define CO_E_OBJNOTREG
Definition: winerror.h:2814
const GUID IID_IUnknown
BOOL WINAPI IsValidInterface(LPUNKNOWN punk)
Definition: ifs.c:555
#define WINAPI
Definition: msvc.h:6
#define LMEM_MOVEABLE
Definition: winbase.h:350
unsigned long DWORD
Definition: ntddk_ex.h:95
interface IMallocSpy * LPMALLOCSPY
Definition: objfwd.h:13
GLenum const GLvoid * addr
Definition: glext.h:9621
DWORD SpyedBlockTableLength
Definition: ifs.c:57
static BOOL SetSpyedBlockTableLength(DWORD NewLength)
Definition: ifs.c:74
static void WINAPI IMalloc_fnFree(IMalloc *iface, void *pv)
Definition: ifs.c:260
LIST_ENTRY ProcessLocksList
Definition: winbase.h:861
IMallocSpy * pSpy
Definition: ifs.c:53
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define S_OK
Definition: intsafe.h:59
HLOCAL NTAPI LocalReAlloc(HLOCAL hMem, SIZE_T dwBytes, UINT uFlags)
Definition: heapmem.c:1608
static _Malloc32 Malloc32
Definition: ifs.c:61
#define HeapReAlloc
Definition: compat.h:482
BOOL WINAPI IsBadReadPtr(IN LPCVOID lp, IN UINT_PTR ucb)
Definition: except.c:807
DWORD SpyedAllocationsLeft
Definition: ifs.c:54
HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy)
Definition: ifs.c:482
static HRESULT WINAPI IMalloc_fnQueryInterface(IMalloc *iface, REFIID refiid, void **obj)
Definition: ifs.c:152
static HMODULE MODULEINFO DWORD cb
Definition: module.c:32
Definition: mem.c:156
CONST void * LPCVOID
Definition: windef.h:191
unsigned int ULONG
Definition: retypes.h:1
LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, SIZE_T size)
Definition: ifs.c:460
HLOCAL NTAPI LocalAlloc(UINT uFlags, SIZE_T dwBytes)
Definition: heapmem.c:1373
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
static CRITICAL_SECTION_DEBUG critsect_debug
Definition: ifs.c:65
static SIZE_T WINAPI IMalloc_fnGetSize(IMalloc *iface, void *mem)
Definition: ifs.c:299
LPVOID WINAPI CoTaskMemAlloc(SIZE_T size)
Definition: ifs.c:426
#define HeapFree(x, y, z)
Definition: compat.h:483
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:95
int(* FARPROC)()
Definition: compat.h:36
#define CO_E_OBJISREG
Definition: winerror.h:2815
#define SUCCEEDED(hr)
Definition: intsafe.h:57
struct task_struct * current
Definition: linux.c:32
static BOOL AddMemoryLocation(LPVOID *pMem)
Definition: ifs.c:89