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