Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1210 lines
25 KiB

  1. /*
  2. * gllocal.c
  3. *
  4. * Implementation of global and local heaps
  5. *
  6. * Copyright (C) 1994 Microsoft Corporation
  7. */
  8. #include "_apipch.h"
  9. #define _GLLOCAL_C
  10. #ifdef MAC
  11. #include "ole2ui.h"
  12. #include <utilmac.h>
  13. #include <mapiprof.h>
  14. #ifdef GetPrivateProfileInt
  15. #undef GetPrivateProfileInt
  16. #undef GetPrivateProfileString
  17. #endif
  18. #define GetPrivateProfileInt MAPIGetPrivateProfileInt
  19. #define GetPrivateProfileString MAPIGetPrivateProfileString
  20. #endif // MAC
  21. // #include "glheap.h"
  22. #ifdef MAC
  23. #pragma code_seg("glheap", "fixed, preload")
  24. #else
  25. #ifdef OLD_STUFF
  26. #pragma SEGMENT(glheap)
  27. #endif // OLD_STUFF
  28. #endif
  29. #ifdef DEBUG
  30. #define STATIC
  31. #else
  32. #define STATIC static
  33. #endif
  34. // Local Heap Debug Implementation --------------------------------------------
  35. #ifdef DEBUG
  36. static TCHAR szDebugIni[] = TEXT("WABDBG.INI");
  37. static TCHAR szSectionHeap[] = TEXT("Memory Management");
  38. static TCHAR szKeyUseVirtual[] = TEXT("VirtualMemory");
  39. static TCHAR szKeyAssertLeaks[] = TEXT("AssertLeaks");
  40. static TCHAR szKeyDumpLeaks[] = TEXT("DumpLeaks");
  41. static TCHAR szKeyFillMem[] = TEXT("FillMemory");
  42. static TCHAR szKeyFillByte[] = TEXT("FillByte");
  43. // Artificial Errors for local heaps
  44. BOOL FForceFailure(HLH hlh, UINT cb);
  45. static TCHAR szAESectionHeap[] = TEXT("Local Heap Failures");
  46. static TCHAR szAEKeyFailStart[] = TEXT("AllocsToFirstFailure");
  47. static TCHAR szAEKeyFailInterval[] = TEXT("FailureInterval");
  48. static TCHAR szAEKeyFailBufSize[] = TEXT("FailureSize");
  49. #ifdef HEAPMON
  50. static TCHAR szKeyHeapMon[] = TEXT("MonitorHeap");
  51. #ifdef MAC
  52. static TCHAR szHeapMonDLL[] = TEXT("GLHM");
  53. #else
  54. static TCHAR szHeapMonDLL[] = TEXT("GLHMON32.DLL");
  55. #endif
  56. static char szHeapMonEntry[] = "HeapMonitor";
  57. static char szGetSymNameEntry[] = "GetSymbolName";
  58. #endif
  59. // Virtual Memory Support --------------------------------------------
  60. //
  61. // The VM Allocators do not currently work on:
  62. // AMD64
  63. // MAC
  64. //
  65. #if defined(MAC) || defined(_AMD64_) || defined(_IA64_)
  66. #define VMAlloc(cb) 0
  67. #define VMAllocEx(cb, ul) 0
  68. #define VMRealloc(pv, cb) 0
  69. #define VMReallocEx(pv, cb, ul) 0
  70. #define VMFree(pv)
  71. #define VMFreeEx(pv, ul)
  72. #define VMGetSize(pv) 0
  73. #define VMGetSizeEx(pv, ul) 0
  74. #endif
  75. #if defined(WIN32) && !defined(MAC)
  76. #define LH_EnterCriticalSection(hlh) EnterCriticalSection(&hlh->cs)
  77. #define LH_LeaveCriticalSection(hlh) LeaveCriticalSection(&hlh->cs)
  78. #else
  79. #define LH_EnterCriticalSection(hlh)
  80. #define LH_LeaveCriticalSection(hlh)
  81. #endif
  82. #ifdef HEAPMON
  83. /*
  84. - FRegisterHeap
  85. -
  86. * Purpose:
  87. * If the user wants to monitor the Heap, then load the DLL with
  88. * the HeapMonitor UI.
  89. */
  90. BOOL FRegisterHeap(PLH plh)
  91. {
  92. HINSTANCE hInst;
  93. LPHEAPMONPROC pfnHeapMon;
  94. LPGETSYMNAMEPROC pfnGetSymName;
  95. plh->hInstHeapMon = 0;
  96. plh->pfnGetSymName = NULL;
  97. hInst = LoadLibrary(szHeapMonDLL);
  98. if (!hInst)
  99. {
  100. DebugTrace(TEXT("FRegisterHeap: Failed to LoadLibrary GLHMON32.DLL.\n"));
  101. goto ret;
  102. }
  103. pfnHeapMon = (LPHEAPMONPROC)GetProcAddress(hInst, szHeapMonEntry);
  104. if (!pfnHeapMon)
  105. {
  106. DebugTrace(TEXT("FRegisterHeap: Failed to GetProcAddress of HeapMonitor.\n"));
  107. FreeLibrary(hInst);
  108. goto ret;
  109. }
  110. pfnGetSymName = (LPGETSYMNAMEPROC)GetProcAddress(hInst, szGetSymNameEntry);
  111. if (!pfnGetSymName)
  112. {
  113. DebugTrace(TEXT("FRegisterHeap: Failed to GetProcAddress of GetSymName.\n"));
  114. }
  115. plh->hInstHeapMon = hInst;
  116. if (!pfnHeapMon(plh, HEAPMON_LOAD))
  117. {
  118. DebugTrace(TEXT("FRegisterHeap: Call to HeapMonitor failed.\n"));
  119. plh->hInstHeapMon = 0;
  120. goto ret;
  121. }
  122. plh->pfnHeapMon = pfnHeapMon;
  123. plh->pfnGetSymName = pfnGetSymName;
  124. ret:
  125. return (plh->hInstHeapMon ? TRUE : FALSE);
  126. }
  127. void UnRegisterHeap(HLH hlh)
  128. {
  129. if (hlh->pfnHeapMon)
  130. hlh->pfnHeapMon(hlh, HEAPMON_UNLOAD);
  131. }
  132. #endif // HEAPMON
  133. /*
  134. - LH_ReportLeak
  135. -
  136. * Purpose:
  137. * To report individual memory leaks through DebugTrace and the
  138. * LH_LeakHook breakpoint function.
  139. */
  140. void LH_ReportLeak(HLH hlh, PLHBLK plhblk)
  141. {
  142. DebugTrace(TEXT("Memory leak '%s' in %s @ %08lX, Allocation #%ld, Size: %ld\n"),
  143. plhblk->szName[0] ? plhblk->szName : TEXT("NONAME"),
  144. hlh->szHeapName, PlhblkToPv(plhblk),
  145. plhblk->ulAllocNum, CbPlhblkClient(plhblk));
  146. #if defined(WIN32) && defined(_X86_) && defined(LEAK_TEST)
  147. {
  148. int i;
  149. for (i = 0; i < NCALLERS && plhblk->pfnCallers[i]; i++)
  150. {
  151. char szSymbol[256];
  152. char szModule[64];
  153. DWORD dwDisp;
  154. BOOL fGotSym = FALSE;
  155. szSymbol[0] = 0;
  156. szModule[0] = 0;
  157. if (hlh->pfnGetSymName)
  158. if (hlh->pfnGetSymName((DWORD) plhblk->pfnCallers[i], szModule,
  159. szSymbol, &dwDisp))
  160. fGotSym = TRUE;
  161. if (fGotSym)
  162. {
  163. DebugTrace(TEXT("[%d] %s %s"), i, szModule, szSymbol);
  164. if (dwDisp)
  165. DebugTrace(TEXT("+%ld"), dwDisp);
  166. DebugTrace(TEXT("\n"));
  167. }
  168. else
  169. DebugTrace(TEXT("[%d] %s %08lX \n"), i, szModule, plhblk->pfnCallers[i]);
  170. DBGMEM_LeakHook(plhblk->pfnCallers[i]);
  171. }
  172. }
  173. #endif
  174. }
  175. /*
  176. - LH_DumpLeaks
  177. -
  178. * Purpose:
  179. * Gets called at LH_Close time to report any memory leaks against
  180. * this heap. There are 3 reporting fascilities used by this routine:
  181. *
  182. * => Breakpoint hooking (via LH_LeakHook)
  183. * => Asserts (via TrapSz)
  184. * => Debug trace tags (via DebugTrace)
  185. *
  186. * The Debug Trace is the default method if no others are specified
  187. * or if the others are in-appropriate for the given platform.
  188. */
  189. void LH_DumpLeaks(HLH hlh)
  190. {
  191. PLHBLK plhblk;
  192. BOOL fDump = !!(hlh->ulFlags & HEAP_DUMP_LEAKS);
  193. BOOL fAssert = !!(hlh->ulFlags & HEAP_ASSERT_LEAKS);
  194. int cLeaks = 0;
  195. for (plhblk = hlh->plhblkHead; plhblk; plhblk = plhblk->plhblkNext)
  196. {
  197. if (fDump)
  198. LH_ReportLeak(hlh, plhblk);
  199. cLeaks++;
  200. }
  201. if (cLeaks)
  202. {
  203. #if defined(WIN16) || (defined(WIN32) && defined(_X86_))
  204. if (fAssert)
  205. {
  206. TrapSz3( TEXT("GLHEAP detected %d memory leak%s in Heap: %s"),
  207. cLeaks, (cLeaks == 1 ? szEmpty : TEXT("s")), hlh->szHeapName);
  208. }
  209. else
  210. DebugTrace(TEXT("GLHEAP detected %d memory leak%s in Heap: %s\n"),
  211. cLeaks, (cLeaks == 1 ? szEmpty : TEXT("s")), hlh->szHeapName);
  212. #else
  213. DebugTrace(TEXT("GLHEAP detected %d memory leak%s in Heap: %s\n"),
  214. cLeaks, (cLeaks == 1 ? szEmpty : TEXT("s")), hlh->szHeapName);
  215. #endif
  216. }
  217. }
  218. BOOL LH_ValidatePlhblk(HLH hlh, PLHBLK plhblk, char ** pszReason)
  219. {
  220. if (IsBadWritePtr(plhblk, sizeof(LHBLK)))
  221. {
  222. *pszReason = "Block header cannot be written to";
  223. goto err;
  224. }
  225. if (plhblk->hlh != hlh)
  226. {
  227. *pszReason = "Block header does not have correct pointer back to heap";
  228. goto err;
  229. }
  230. if (plhblk->plhblkNext)
  231. {
  232. if (IsBadWritePtr(plhblk->plhblkNext, sizeof(LHBLK)))
  233. {
  234. *pszReason = "Block header has invalid next link pointer";
  235. goto err;
  236. }
  237. if (plhblk->plhblkNext->plhblkPrev != plhblk)
  238. {
  239. *pszReason = "Block header points to a next block which doesn't "
  240. "point back to it";
  241. goto err;
  242. }
  243. }
  244. if (plhblk->plhblkPrev)
  245. {
  246. if (IsBadWritePtr(plhblk->plhblkPrev, sizeof(LHBLK))) {
  247. *pszReason = "Block header has invalid prev link pointer";
  248. goto err;
  249. }
  250. if (plhblk->plhblkPrev->plhblkNext != plhblk)
  251. {
  252. *pszReason = "Block header points to a prev block which doesn't "
  253. "point back to it";
  254. goto err;
  255. }
  256. }
  257. else if (hlh->plhblkHead != plhblk)
  258. {
  259. *pszReason = "Block header has a zero prev link but the heap doesn't "
  260. "believe it is the first block";
  261. goto err;
  262. }
  263. if (plhblk->ulAllocNum > hlh->ulAllocNum)
  264. {
  265. *pszReason = "Block header has an invalid internal allocation number";
  266. goto err;
  267. }
  268. return TRUE;
  269. err:
  270. return FALSE;
  271. }
  272. // $MAC - Need WINAPI
  273. BOOL
  274. #ifdef MAC
  275. WINAPI
  276. #endif
  277. LH_DidAlloc(HLH hlh, LPVOID pv)
  278. {
  279. PLHBLK plhblk;
  280. char * pszReason;
  281. BOOL fDidAlloc = FALSE;
  282. for (plhblk = hlh->plhblkHead; plhblk; plhblk = plhblk->plhblkNext)
  283. {
  284. AssertSz2(LH_ValidatePlhblk(hlh, plhblk, &pszReason),
  285. TEXT("Block header (plhblk=%08lX) is invalid\n%s"),
  286. plhblk, pszReason);
  287. if (PlhblkToPv(plhblk) == pv)
  288. {
  289. fDidAlloc = TRUE;
  290. break;
  291. }
  292. }
  293. return fDidAlloc;
  294. }
  295. BOOL LH_ValidatePv(HLH hlh, LPVOID pv, char * pszFunc)
  296. {
  297. PLHBLK plhblk;
  298. char * pszReason;
  299. plhblk = PvToPlhblk(hlh, pv);
  300. if (!plhblk)
  301. {
  302. TrapSz3( TEXT("%s detected a memory block (%08lX) which was either not ")
  303. TEXT("allocated in heap '%s' or has already been freed."),
  304. pszFunc, pv, hlh->szHeapName);
  305. return(FALSE);
  306. }
  307. if (LH_ValidatePlhblk(hlh, plhblk, &pszReason))
  308. return(TRUE);
  309. TrapSz4( TEXT("%s detected an invalid memory block (%08lX) in heap '%s'. %s."),
  310. pszFunc, pv, hlh->szHeapName, pszReason);
  311. return FALSE;
  312. }
  313. /*
  314. - PlhblkEnqueue
  315. -
  316. * Purpose:
  317. * To add a newly allocated block to the allocation list hanging
  318. * off the heap. We do an InsertSorted because the HeapMonitor
  319. * will need to reference the allocations ordered by their
  320. * location in the heap. Since the monitor will walk the heap
  321. * often, it is more efficient to do the sort up front.
  322. */
  323. void PlhblkEnqueue(PLHBLK plhblk)
  324. {
  325. PLHBLK plhblkCurr = NULL;
  326. PLHBLK plhblkNext = plhblk->hlh->plhblkHead;
  327. while (plhblkNext)
  328. {
  329. if (plhblkNext > plhblk)
  330. break;
  331. plhblkCurr = plhblkNext;
  332. plhblkNext = plhblkCurr->plhblkNext;
  333. }
  334. if (plhblkNext)
  335. {
  336. plhblk->plhblkNext = plhblkNext;
  337. plhblk->plhblkPrev = plhblkCurr;
  338. plhblkNext->plhblkPrev = plhblk;
  339. }
  340. else
  341. {
  342. plhblk->plhblkNext = NULL;
  343. plhblk->plhblkPrev = plhblkCurr;
  344. }
  345. if (plhblkCurr)
  346. plhblkCurr->plhblkNext = plhblk;
  347. else
  348. plhblk->hlh->plhblkHead = plhblk;
  349. }
  350. /*
  351. - PlhblkDequeue
  352. -
  353. * Purpose:
  354. * To remove a freed block from the list of allocations hanging
  355. * off the heap.
  356. */
  357. void PlhblkDequeue(PLHBLK plhblk)
  358. {
  359. if (plhblk->plhblkNext)
  360. plhblk->plhblkNext->plhblkPrev = plhblk->plhblkPrev;
  361. if (plhblk->plhblkPrev)
  362. plhblk->plhblkPrev->plhblkNext = plhblk->plhblkNext;
  363. else
  364. plhblk->hlh->plhblkHead = plhblk->plhblkNext;
  365. }
  366. /*
  367. - HexByteToBin
  368. -
  369. * Purpose:
  370. * Takes a hex string and converts the 2 msd's to a byte, ignoring
  371. * the remaining digits. This function assumes the string is
  372. * formatted as: 0xnn, otherwise it simply returns 0x00.
  373. */
  374. BYTE HexByteToBin(LPSTR sz)
  375. {
  376. int i, n[2], nT;
  377. if (*sz++ != '0')
  378. return 0x00;
  379. nT = *sz++;
  380. if (nT != 'x' && nT != 'X')
  381. return 0x00;
  382. for (i = 0; i < 2; i++)
  383. {
  384. nT = *sz++;
  385. if (nT >= '0' && nT <= '9')
  386. n[i] = nT - '0';
  387. else if (nT >= 'A' && nT <= 'F')
  388. n[i] = nT - 'A' + 10;
  389. else if (nT >= 'a' && nT <= 'f')
  390. n[i] = nT - 'a' + 10;
  391. else
  392. return (BYTE)0x00;
  393. }
  394. n[0] <<= 4;
  395. return (BYTE)((BYTE)n[0] | (BYTE)n[1]);
  396. }
  397. HLH WINAPI LH_Open(DWORD dwMaxHeap)
  398. {
  399. _HLH _hlhData = 0;
  400. _HLH _hlhBlks = 0;
  401. PLH plh = NULL;
  402. UINT cch = 0;
  403. UINT uiT = 0;
  404. TCHAR szFillByte[8];
  405. LPSTR lpFillByte = NULL;
  406. ULONG cbVirtual = 0;
  407. // The first thing we must do is create a heap that we will
  408. // allocate our Allocation Blocks on. We also allocate our
  409. // debug Heap object on this heap.
  410. _hlhBlks = _LH_Open(dwMaxHeap);
  411. if (!_hlhBlks)
  412. {
  413. DebugTrace(TEXT("LH_Open: Failed to create new heap!\n"));
  414. goto ret;
  415. }
  416. // Allocate the thing we hand back to the caller on this new heap.
  417. plh = _LH_Alloc(_hlhBlks, sizeof(LH));
  418. if (!plh)
  419. {
  420. DebugTrace(TEXT("LH_Alloc: Failed to allocate heap handle!\n"));
  421. _LH_Close(_hlhBlks);
  422. _hlhBlks = 0;
  423. goto ret;
  424. }
  425. // Initialize all the goodies we store in this thing.
  426. // Hook this heap into the global list of heaps we've
  427. // created in this context.
  428. memset(plh, 0, sizeof(LH));
  429. plh->pfnSetName = (LPLHSETNAME)LH_SetNameFn;
  430. plh->_hlhBlks = _hlhBlks;
  431. plh->ulFlags = HEAP_LOCAL;
  432. #if defined(WIN32) && !defined(MAC)
  433. InitializeCriticalSection(&plh->cs);
  434. #endif
  435. // VirtualMemory default is FALSE
  436. cbVirtual = GetPrivateProfileInt(szSectionHeap, szKeyUseVirtual, 0,
  437. szDebugIni);
  438. if (cbVirtual)
  439. {
  440. plh->ulFlags |= HEAP_USE_VIRTUAL;
  441. // We always want virtual allocations on MIPS and PPC to be 4-byte
  442. // aligned, because all our code assumes that the beginning of an
  443. // allocation is aligned on machine word boundaries. On other
  444. // platforms, changing this behavior is non-fatal, but on MIPS and
  445. // PPC we'll get alignment faults everywhere.
  446. #if !defined(_MIPS_) && !defined(_PPC_)
  447. if (cbVirtual == 4)
  448. #endif
  449. plh->ulFlags |= HEAP_USE_VIRTUAL_4;
  450. }
  451. // DumpLeaks default is TRUE
  452. if (GetPrivateProfileInt(szSectionHeap, szKeyDumpLeaks, 1, szDebugIni))
  453. plh->ulFlags |= HEAP_DUMP_LEAKS;
  454. // AssertLeaks default is FALSE
  455. if (GetPrivateProfileInt(szSectionHeap, szKeyAssertLeaks, 0, szDebugIni))
  456. plh->ulFlags |= HEAP_ASSERT_LEAKS;
  457. // FillMem default is TRUE
  458. if (GetPrivateProfileInt(szSectionHeap, szKeyFillMem, 1, szDebugIni))
  459. plh->ulFlags |= HEAP_FILL_MEM;
  460. if (plh->ulFlags & HEAP_FILL_MEM)
  461. {
  462. cch = GetPrivateProfileString(
  463. szSectionHeap,
  464. szKeyFillByte,
  465. szEmpty,
  466. szFillByte,
  467. CharSizeOf(szFillByte)-1,
  468. szDebugIni);
  469. }
  470. // Set the memory fill character.
  471. lpFillByte = ConvertWtoA(szFillByte);
  472. plh->chFill = (BYTE)(cch ? HexByteToBin(lpFillByte) : chDefaultFill);
  473. LocalFreeAndNull(&lpFillByte);
  474. //
  475. // Set up artificial failures. If anything is set in our ini file, then
  476. // HEAP_FAILURES_ENABLED gets set.
  477. //
  478. uiT = GetPrivateProfileInt(szAESectionHeap, szAEKeyFailStart, 0, szDebugIni);
  479. if (uiT)
  480. {
  481. plh->ulFlags |= HEAP_FAILURES_ENABLED;
  482. plh->ulFailStart = (ULONG) uiT;
  483. plh->ulFailInterval =
  484. (ULONG) GetPrivateProfileInt(szAESectionHeap, szAEKeyFailInterval, 0, szDebugIni);
  485. plh->uiFailBufSize =
  486. GetPrivateProfileInt(szAESectionHeap, szAEKeyFailBufSize, 0, szDebugIni);
  487. }
  488. #ifdef HEAPMON
  489. // If the user wants Heap Monitor UI, the spin a thread to manage a
  490. // DialogBox that can display the status of the heap at all times.
  491. if (GetPrivateProfileInt(szSectionHeap, szKeyHeapMon, 0, szDebugIni))
  492. if (FRegisterHeap(plh))
  493. plh->ulFlags |= HEAP_HEAP_MONITOR;
  494. #endif
  495. // If we are not using virtual memory allocators, then we
  496. // create another heap to allocate the users data in.
  497. if (!(plh->ulFlags & HEAP_USE_VIRTUAL))
  498. {
  499. _hlhData = _LH_Open(dwMaxHeap);
  500. if (!_hlhData)
  501. {
  502. DebugTrace(TEXT("LH_Alloc: Failed to allocate heap handle!\n"));
  503. _LH_Close(_hlhBlks);
  504. plh = NULL;
  505. goto ret;
  506. }
  507. plh->_hlhData = _hlhData;
  508. }
  509. #ifndef _WIN64
  510. LH_SetHeapName1(plh, TEXT("LH %08lX"), plh);
  511. #else
  512. LH_SetHeapName1(plh, TEXT("LH %p"), plh);
  513. #endif // _WIN64
  514. ret:
  515. return (HLH)plh;
  516. }
  517. void WINAPI LH_Close(HLH hlh)
  518. {
  519. _HLH _hlhData = hlh->_hlhData;
  520. _HLH _hlhBlks = hlh->_hlhBlks;
  521. // Dump memory leaks if we're supposed to.
  522. if (hlh->ulFlags & HEAP_DUMP_LEAKS)
  523. LH_DumpLeaks(hlh);
  524. // Destroy the HeapMonitor thread and un-load the DLL
  525. #ifdef HEAPMON
  526. UnRegisterHeap(hlh);
  527. if ((hlh->ulFlags & HEAP_HEAP_MONITOR) && hlh->hInstHeapMon)
  528. FreeLibrary(hlh->hInstHeapMon);
  529. #endif
  530. #if defined(WIN32) && !defined(MAC)
  531. DeleteCriticalSection(&hlh->cs);
  532. #endif
  533. // Clean-up and leave. Closing frees leaks, so we're cool!
  534. if (!(hlh->ulFlags & HEAP_USE_VIRTUAL) && _hlhData)
  535. _LH_Close(_hlhData);
  536. if (_hlhBlks)
  537. {
  538. _LH_Free (_hlhBlks, hlh);
  539. _LH_Close(_hlhBlks);
  540. }
  541. }
  542. LPVOID WINAPI LH_Alloc(HLH hlh, UINT cb)
  543. {
  544. PLHBLK plhblk = NULL;
  545. LPVOID pvAlloc = NULL;
  546. // Note: To be consistent with other (e.g. system) allocators,
  547. // we have to return a valid allocation if cb == 0. So, we
  548. // allow a cb of 0 to actually be allocated. (See bug 3556 in
  549. // the sqlguest:exchange database.)
  550. LH_EnterCriticalSection(hlh);
  551. if (hlh->ulFlags & HEAP_FAILURES_ENABLED)
  552. {
  553. if (FForceFailure(hlh, cb))
  554. {
  555. DebugTrace(TEXT("LH_Alloc: Artificial Failure\n"));
  556. pvAlloc = NULL;
  557. hlh->ulAllocNum++;
  558. goto out;
  559. }
  560. }
  561. if (hlh->ulFlags & HEAP_USE_VIRTUAL_4)
  562. pvAlloc = VMAllocEx(cb, 4);
  563. else if (hlh->ulFlags & HEAP_USE_VIRTUAL)
  564. pvAlloc = VMAllocEx(cb, 1);
  565. else if (cb > UINT_MAX)
  566. plhblk = 0;
  567. else
  568. #ifndef _WIN64
  569. pvAlloc = _LH_Alloc(hlh->_hlhData, (UINT)cb);
  570. #else
  571. {
  572. Assert(hlh->_hlhData);
  573. Assert(cb);
  574. Assert(HeapValidate(hlh->_hlhData, 0, NULL));
  575. pvAlloc = _LH_Alloc(hlh->_hlhData, (UINT)cb);
  576. }
  577. #endif
  578. if (pvAlloc)
  579. {
  580. plhblk = (PLHBLK)_LH_Alloc(hlh->_hlhBlks, sizeof(LHBLK));
  581. if (plhblk)
  582. {
  583. plhblk->hlh = hlh;
  584. plhblk->szName[0] = 0;
  585. plhblk->ulSize = cb;
  586. plhblk->ulAllocNum = ++hlh->ulAllocNum;
  587. plhblk->pv = pvAlloc;
  588. PlhblkEnqueue(plhblk);
  589. #if defined(WIN32) && defined(_X86_) && defined(LEAK_TEST)
  590. GetCallStack((DWORD *)plhblk->pfnCallers, 0, NCALLERS);
  591. #endif
  592. if (hlh->ulFlags & HEAP_FILL_MEM)
  593. memset(pvAlloc, hlh->chFill, (size_t)cb);
  594. }
  595. else
  596. {
  597. if (hlh->ulFlags & HEAP_USE_VIRTUAL_4)
  598. VMFreeEx(pvAlloc, 4);
  599. else if (hlh->ulFlags & HEAP_USE_VIRTUAL)
  600. VMFreeEx(pvAlloc, 1);
  601. else
  602. _LH_Free(hlh->_hlhData, pvAlloc);
  603. pvAlloc = NULL;
  604. }
  605. }
  606. out:
  607. LH_LeaveCriticalSection(hlh);
  608. return pvAlloc;
  609. }
  610. LPVOID WINAPI LH_Realloc(HLH hlh, LPVOID pv, UINT cb)
  611. {
  612. LPVOID pvNew = NULL;
  613. LH_EnterCriticalSection(hlh);
  614. if (pv == 0)
  615. pvNew = LH_Alloc(hlh, cb);
  616. else if (cb == 0)
  617. LH_Free(hlh, pv);
  618. else if (LH_ValidatePv(hlh, pv, "LH_Realloc"))
  619. {
  620. PLHBLK plhblk = PvToPlhblk(hlh, pv);
  621. UINT cbOld = (UINT)CbPlhblkClient(plhblk);
  622. PlhblkDequeue(plhblk);
  623. if (cb > cbOld &&
  624. ((hlh->ulFlags & HEAP_FAILURES_ENABLED) && FForceFailure(hlh, cb)))
  625. {
  626. hlh->ulAllocNum++;
  627. pvNew = 0;
  628. DebugTrace(TEXT("LH_Realloc: Artificial Failure\n"));
  629. } else if (hlh->ulFlags & HEAP_USE_VIRTUAL_4)
  630. pvNew = VMReallocEx(pv, cb, 4);
  631. else if (hlh->ulFlags & HEAP_USE_VIRTUAL)
  632. pvNew = VMReallocEx(pv, cb, 1);
  633. else if (cb > UINT_MAX)
  634. pvNew = 0;
  635. else
  636. pvNew = _LH_Realloc(hlh->_hlhData, pv, (UINT)cb);
  637. PlhblkEnqueue(plhblk);
  638. if (pvNew)
  639. {
  640. hlh->ulAllocNum++;
  641. plhblk->pv = pvNew;
  642. plhblk->ulSize = cb;
  643. if (cb > cbOld)
  644. memset((LPBYTE)pvNew + cbOld, hlh->chFill, cb - cbOld);
  645. }
  646. }
  647. LH_LeaveCriticalSection(hlh);
  648. return pvNew;
  649. }
  650. void WINAPI LH_Free(HLH hlh, LPVOID pv)
  651. {
  652. PLHBLK plhblk;
  653. LH_EnterCriticalSection(hlh);
  654. if (pv && LH_ValidatePv(hlh, pv, "LH_Free"))
  655. {
  656. plhblk = PvToPlhblk(hlh, pv);
  657. PlhblkDequeue(plhblk);
  658. memset(pv, 0xDC, (size_t)CbPlhblkClient(plhblk));
  659. if (hlh->ulFlags & HEAP_USE_VIRTUAL_4)
  660. VMFreeEx(pv, 4);
  661. else if (hlh->ulFlags & HEAP_USE_VIRTUAL)
  662. VMFreeEx(pv, 1);
  663. else
  664. _LH_Free(hlh->_hlhData, pv);
  665. _LH_Free(hlh->_hlhBlks, plhblk);
  666. }
  667. LH_LeaveCriticalSection(hlh);
  668. }
  669. UINT WINAPI LH_GetSize(HLH hlh, LPVOID pv)
  670. {
  671. UINT cb = 0;
  672. LH_EnterCriticalSection(hlh);
  673. if (LH_ValidatePv(hlh, pv, "LH_GetSize"))
  674. {
  675. if (hlh->ulFlags & HEAP_USE_VIRTUAL_4)
  676. cb = (UINT)VMGetSizeEx(pv, 4);
  677. else if (hlh->ulFlags & HEAP_USE_VIRTUAL)
  678. cb = (UINT)VMGetSizeEx(pv, 1);
  679. else
  680. cb = (UINT) _LH_GetSize(hlh->_hlhData, pv);
  681. }
  682. LH_LeaveCriticalSection(hlh);
  683. return cb;
  684. }
  685. void __cdecl LH_SetHeapNameFn(HLH hlh, TCHAR *pszFormat, ...)
  686. {
  687. TCHAR sz[512];
  688. va_list vl;
  689. va_start(vl, pszFormat);
  690. wvnsprintf(sz, ARRAYSIZE(sz), pszFormat, vl);
  691. va_end(vl);
  692. StrCpyN(hlh->szHeapName,
  693. sz,
  694. CharSizeOf(hlh->szHeapName));
  695. }
  696. void __cdecl EXPORT_16 LH_SetNameFn(HLH hlh, LPVOID pv, TCHAR *pszFormat, ...)
  697. {
  698. TCHAR sz[512];
  699. PLHBLK plhblk;
  700. va_list vl;
  701. plhblk = PvToPlhblk(hlh, pv);
  702. if (plhblk)
  703. {
  704. va_start(vl, pszFormat);
  705. wvnsprintf(sz, ARRAYSIZE(sz), pszFormat, vl);
  706. va_end(vl);
  707. StrCpyN(plhblk->szName, sz, CharSizeOf(plhblk->szName));
  708. }
  709. }
  710. // $MAC - Need WINAPI
  711. TCHAR *
  712. #ifdef MAC
  713. WINAPI
  714. #endif
  715. LH_GetName(HLH hlh, LPVOID pv)
  716. {
  717. PLHBLK plhblk;
  718. plhblk = PvToPlhblk(hlh, pv);
  719. if (plhblk)
  720. return(plhblk->szName);
  721. return(szEmpty);
  722. }
  723. BOOL FForceFailure(HLH hlh, UINT cb)
  724. {
  725. //
  726. // First, see if we're past our start of failures point
  727. //
  728. if (hlh->ulFailStart && (hlh->ulFailStart <= hlh->ulAllocNum))
  729. {
  730. //
  731. // If so, then are we at an interval where we should return errors?
  732. //
  733. if ((hlh->ulFailInterval)
  734. && ((hlh->ulAllocNum - hlh->ulFailStart)%hlh->ulFailInterval) == 0)
  735. {
  736. //
  737. // return that we should fail here
  738. //
  739. return TRUE;
  740. }
  741. //
  742. // Check to see if the alloc size is greater than allowed
  743. //
  744. if (hlh->uiFailBufSize && cb >= hlh->uiFailBufSize)
  745. return TRUE;
  746. }
  747. //
  748. // Otherwise, no error is returned for this alloc
  749. //
  750. return FALSE;
  751. }
  752. /*
  753. - PvToPlhblk
  754. -
  755. * Purpose:
  756. * Finds the LHBLK for this allocation in the heap's active list.
  757. */
  758. PLHBLK PvToPlhblk(HLH hlh, LPVOID pv)
  759. {
  760. PLHBLK plhblk;
  761. LH_EnterCriticalSection(hlh);
  762. plhblk = hlh->plhblkHead;
  763. while (plhblk)
  764. {
  765. if (plhblk->pv == pv)
  766. break;
  767. plhblk = plhblk->plhblkNext;
  768. }
  769. LH_LeaveCriticalSection(hlh);
  770. return plhblk;
  771. }
  772. #endif /* DEBUG */
  773. #ifdef MAC // MAC!!
  774. #if defined(DEBUG)
  775. static TCHAR stMemErr[] = TEXT("\pHad a memory error. See above for details");
  776. #endif
  777. LPVOID WINAPI _LH_Open(DWORD dwMaxHeap)
  778. {
  779. Ptr lp;
  780. lp = NewPtrClear(sizeof(LHeap));
  781. if (lp == NULL)
  782. {
  783. #if defined(DEBUG)
  784. DebugTrace(TEXT("_LH_Open had an error. MemError = %d"), MemError());
  785. DebugStr(stMemErr);
  786. #endif /* DEBUG */
  787. return NULL;
  788. }
  789. return (LPVOID)lp;
  790. }
  791. void WINAPI _LH_Close(LPVOID plh)
  792. {
  793. LBlkPtr plb, plbNext;
  794. #if defined(DEBUG)
  795. short idx = 0;
  796. #endif
  797. if (plh == NULL)
  798. return;
  799. // Walk the block list throwing out remaining mem as we go along.
  800. plb = ((LHeapPtr)plh)->plb;
  801. while (plb)
  802. {
  803. plbNext = plb->next;
  804. DisposePtr((Ptr)plb);
  805. #if defined(DEBUG)
  806. if (MemError())
  807. {
  808. DebugTrace(TEXT("_LH_Close: Had a memory error."));
  809. DebugTrace(TEXT("Error number = %d"), MemError());
  810. DebugStr(stMemErr);
  811. }
  812. idx ++;
  813. #endif
  814. plb = plbNext;
  815. }
  816. // Throw out the heap header.
  817. DisposePtr((Ptr)plh);
  818. #if defined(DEBUG)
  819. if (MemError())
  820. {
  821. DebugTrace(TEXT("_LH_Close: Had error throwing out heap head."));
  822. DebugTrace(TEXT("MemError = %d"), MemError());
  823. DebugStr(stMemErr);
  824. }
  825. if (idx)
  826. DebugTrace(TEXT("Threw out %d left over local memory blocks\n"), idx);
  827. #endif /* DEBUG */
  828. }
  829. LPVOID WINAPI _LH_Alloc(LPVOID plh, UINT cb)
  830. {
  831. LBlkPtr plbNew, plb;
  832. Ptr lp;
  833. if (plh == NULL)
  834. return NULL;
  835. // Get memory for the linked list element. Mem requests are stored in a
  836. // linked list off a 'heap' head because real heap management is such a
  837. // pain on the Mac.
  838. plbNew = (LBlkPtr)NewPtr(sizeof(LBlock));
  839. if (plbNew == NULL)
  840. goto trouble;
  841. // Memory for the actual request.
  842. lp = NewPtrClear(cb);
  843. if (lp == NULL)
  844. {
  845. DisposePtr((Ptr)plbNew);
  846. goto trouble;
  847. }
  848. // All members of LBlock are filled in so there's no need to call
  849. // NewPtrclear() above.
  850. plbNew->ptr = lp;
  851. plbNew->next = NULL;
  852. // Find the end of the linked list and link this element in.
  853. if (plb = ((LHeapPtr)plh)->plb)
  854. {
  855. while (plb->next)
  856. plb = plb->next;
  857. plb->next = plbNew;
  858. }
  859. else
  860. ((LHeapPtr)plh)->plb = plbNew;
  861. // Return the successfully allocated memory.
  862. return lp;
  863. trouble:
  864. {
  865. #if defined(DEBUG)
  866. DebugTrace(TEXT("_LH_Alloc failed. MemError = %d"), MemError());
  867. DebugTrace(TEXT("The number of requested bytes = %d"), cb);
  868. DebugStr(stMemErr);
  869. #endif /* DEBUG */
  870. }
  871. return NULL;
  872. }
  873. UINT WINAPI _LH_GetSize(LPVOID plh, LPVOID pv)
  874. {
  875. long cb;
  876. cb = GetPtrSize((Ptr)pv);
  877. if (MemError())
  878. {
  879. #if defined(DEBUG)
  880. DebugTrace(TEXT("_LH_GetSize had an error. MemError = %d"), MemError());
  881. DebugStr(stMemErr);
  882. #endif /* DEBUG */
  883. return 0;
  884. }
  885. return cb;
  886. }
  887. LPVOID WINAPI _LH_Realloc(LPVOID plh, LPVOID pv, UINT cb)
  888. {
  889. Ptr lp;
  890. UINT cbOld;
  891. // Get rid of schizo cases.
  892. if (pv == NULL)
  893. {
  894. lp = _LH_Alloc(plh, cb);
  895. if (lp == NULL)
  896. goto err;
  897. return lp;
  898. }
  899. else if (cb == 0)
  900. {
  901. _LH_Free(plh, pv);
  902. return NULL;
  903. }
  904. // Get the size of the block the old ptr pointed to.
  905. cbOld = _LH_GetSize(plh, pv);
  906. if (cbOld == 0)
  907. goto err;
  908. // Get memory for the new pointer.
  909. lp = _LH_Alloc(plh, cb);
  910. if (lp == NULL)
  911. goto err;
  912. // Copy the old info into the new pointer, throw out the old mem and
  913. // return the result.
  914. BlockMove(pv, lp, cbOld <= cb ? cbOld : cb);
  915. _LH_Free(plh, pv);
  916. return lp;
  917. err:
  918. #if defined(DEBUG)
  919. DebugStr("\p_LH_Realloc failed");
  920. #endif /* DEBUG */
  921. return 0;
  922. }
  923. void WINAPI _LH_Free(LPVOID plh, LPVOID pv)
  924. {
  925. LBlkPtr plb, plbPrev = NULL;
  926. if (pv == NULL)
  927. return;
  928. // Remove the memory from the linked list.
  929. plb = ((LHeapPtr)plh)->plb;
  930. while (plb)
  931. {
  932. if (plb->ptr == pv)
  933. break;
  934. plbPrev = plb;
  935. plb = plb->next;
  936. }
  937. if (plb)
  938. {
  939. if (plbPrev)
  940. plbPrev->next = plb->next;
  941. else
  942. ((LHeapPtr)plh)->plb = plb->next;
  943. }
  944. else
  945. {
  946. #if defined(DEBUG)
  947. DebugStr("\p_LH_Free: Did not find requested <plb> in linked list");
  948. #endif /* DEBUG */
  949. return;
  950. }
  951. // Throw out the linked list element.
  952. DisposePtr((Ptr)plb);
  953. #if defined(DEBUG)
  954. if (MemError())
  955. goto err;
  956. #endif /* DEBUG */
  957. // Throw out the memory itself.
  958. DisposePtr((Ptr)pv);
  959. #if defined(DEBUG)
  960. if (MemError())
  961. err:
  962. {
  963. DebugTrace(TEXT("_LH_Free: Error disposing ptr. MemError = %d"), MemError());
  964. DebugStr(stMemErr);
  965. }
  966. #endif /* DEBUG */
  967. }
  968. #endif /* MAC */