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