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.

1326 lines
26 KiB

  1. /*
  2. * memmgr.c - Memory manager module.
  3. */
  4. /*
  5. The memory manager implementation in this module uses either a private
  6. shared heap (if PRIVATE_HEAP is #defined) or the non-shared process heap (if
  7. PRIVATE_HEAP is not #defined). Thde debug implementation of this memory
  8. manager keeps track of memory blocks allocated from the heap using a
  9. doubly-linked list of heap element nodes. Each node describes one allocated
  10. heap element.
  11. Debug heap elements are allocated with extra space at the beginning and end
  12. of the element. Prefix and suffix sentinels surround each allocated heap
  13. element. New heap elements are filled with UNINITIALIZED_BYTE_VALUE. Freed
  14. heap elements are filled with FREED_BYTE_VALUE. The new tails of grown heap
  15. elements are filled with UNINITIALIZED_BYTE_VALUE.
  16. */
  17. /* Headers
  18. **********/
  19. #include "project.h"
  20. #pragma hdrstop
  21. /* Constants
  22. ************/
  23. #ifdef PRIVATE_HEAP
  24. /* undocumented flag for HeapCreate() from kernel32.h */
  25. #define HEAP_SHARED (0x04000000)
  26. /*
  27. * Set maximum shared heap size used for CreateHeap() to 0 since we don't know
  28. * how big the heap may get, and we don't want to restrict its size
  29. * artificially. BrianSm says this is ok.
  30. */
  31. #define MAX_SHARED_HEAP_SIZE (0)
  32. #endif /* PRIVATE_HEAP */
  33. #ifdef DEBUG
  34. /* heap element byte fill values */
  35. #define UNINITIALIZED_BYTE_VALUE (0xcc)
  36. #define FREED_BYTE_VALUE (0xdd)
  37. #endif /* DEBUG */
  38. /* Macros
  39. *********/
  40. /* atomic memory management function wrappers for translation */
  41. #ifdef PRIVATE_HEAP
  42. #define GetHeap() (Mhheap)
  43. #define MEMALLOCATE(size) HeapAlloc(GetHeap(), 0, (size))
  44. #define MEMREALLOCATE(pv, size) HeapReAlloc(GetHeap(), 0, (pv), (size))
  45. #define MEMFREE(pv) HeapFree(GetHeap(), 0, (pv))
  46. #define MEMSIZE(pv) (DWORD)HeapSize(GetHeap(), 0, (pv))
  47. #else
  48. #define MEMALLOCATE(size) LocalAlloc(LMEM_FIXED, (size))
  49. #define MEMREALLOCATE(pv, size) LocalReAlloc((pv), (size), 0)
  50. #define MEMFREE(pv) (! LocalFree(pv))
  51. #define MEMSIZE(pv) (DWORD)LocalSize(pv)
  52. #endif
  53. /* Types
  54. ********/
  55. #ifdef DEBUG
  56. /* heap element descriptor structure */
  57. typedef struct _heapelemdesc
  58. {
  59. TCHAR rgchSize[6]; /* enough for 99,999 lines */
  60. TCHAR rgchFile[24];
  61. ULONG ulLine;
  62. }
  63. HEAPELEMDESC;
  64. DECLARE_STANDARD_TYPES(HEAPELEMDESC);
  65. /* heap node */
  66. typedef struct _heapnode
  67. {
  68. PCVOID pcv;
  69. DWORD dwcbSize;
  70. struct _heapnode *phnPrev;
  71. struct _heapnode *phnNext;
  72. HEAPELEMDESC hed;
  73. }
  74. HEAPNODE;
  75. DECLARE_STANDARD_TYPES(HEAPNODE);
  76. /* heap */
  77. typedef struct _heap
  78. {
  79. HEAPNODE hnHead;
  80. }
  81. HEAP;
  82. DECLARE_STANDARD_TYPES(HEAP);
  83. /* heap summary filled in by AnalyzeHeap() */
  84. typedef struct _heapsummary
  85. {
  86. ULONG ulcUsedElements;
  87. DWORD dwcbUsedSize;
  88. }
  89. HEAPSUMMARY;
  90. DECLARE_STANDARD_TYPES(HEAPSUMMARY);
  91. /* debug flags */
  92. typedef enum _memmgrdebugflags
  93. {
  94. MEMMGR_DFL_VALIDATE_HEAP_ON_ENTRY = 0x0001,
  95. MEMMGR_DFL_VALIDATE_HEAP_ON_EXIT = 0x0002,
  96. ALL_MEMMGR_DFLAGS = (MEMMGR_DFL_VALIDATE_HEAP_ON_ENTRY |
  97. MEMMGR_DFL_VALIDATE_HEAP_ON_EXIT)
  98. }
  99. MEMMGRDEBUGFLAGS;
  100. #endif /* DEBUG */
  101. /* Global Variables
  102. *******************/
  103. #ifdef DEBUG
  104. /* parameters used by debug AllocateMemory() macro */
  105. PUBLIC_DATA LPCTSTR GpcszElemHdrSize = NULL;
  106. PUBLIC_DATA LPCTSTR GpcszElemHdrFile = NULL;
  107. PUBLIC_DATA ULONG GulElemHdrLine = 0;
  108. #endif /* DEBUG */
  109. /* Module Variables
  110. *******************/
  111. #ifdef PRIVATE_HEAP
  112. /* handle to global shared heap */
  113. PRIVATE_DATA HANDLE Mhheap = NULL;
  114. #endif /* PRIVATE_HEAP */
  115. #ifdef DEBUG
  116. /* heap */
  117. PRIVATE_DATA PHEAP Mpheap = NULL;
  118. /* debug flags */
  119. PRIVATE_DATA DWORD MdwMemoryManagerModuleFlags = 0;
  120. /* heap element sentinels */
  121. PRIVATE_DATA CONST struct
  122. {
  123. BYTE rgbyte[4];
  124. }
  125. MchsPrefix =
  126. {
  127. { TEXT('H'), TEXT('E'), TEXT('A'), TEXT('D') }
  128. };
  129. PRIVATE_DATA CONST struct
  130. {
  131. BYTE rgbyte[4];
  132. }
  133. MchsSuffix =
  134. {
  135. { TEXT('T'), TEXT('A'), TEXT('I'), TEXT('L') }
  136. };
  137. /* .ini file switch descriptions */
  138. PRIVATE_DATA CBOOLINISWITCH cbisValidateHeapOnEntry =
  139. {
  140. IST_BOOL,
  141. TEXT("ValidateHeapOnEntry"),
  142. &MdwMemoryManagerModuleFlags,
  143. MEMMGR_DFL_VALIDATE_HEAP_ON_ENTRY
  144. };
  145. PRIVATE_DATA CBOOLINISWITCH cbisValidateHeapOnExit =
  146. {
  147. IST_BOOL,
  148. TEXT("ValidateHeapOnExit"),
  149. &MdwMemoryManagerModuleFlags,
  150. MEMMGR_DFL_VALIDATE_HEAP_ON_EXIT
  151. };
  152. PRIVATE_DATA const PCVOID MrgcpcvisMemoryManagerModule[] =
  153. {
  154. &cbisValidateHeapOnEntry,
  155. &cbisValidateHeapOnExit
  156. };
  157. #endif /* DEBUG */
  158. /***************************** Private Functions *****************************/
  159. /* Module Prototypes
  160. ********************/
  161. #ifdef DEBUG
  162. PRIVATE_CODE DWORD CalculatePrivateSize(DWORD);
  163. PRIVATE_CODE PVOID GetPrivateHeapPtr(PVOID);
  164. PRIVATE_CODE PVOID GetPublicHeapPtr(PVOID);
  165. PRIVATE_CODE DWORD GetHeapSize(PCVOID);
  166. PRIVATE_CODE BOOL AddHeapElement(PCVOID, DWORD);
  167. PRIVATE_CODE void RemoveHeapElement(PCVOID);
  168. PRIVATE_CODE void ModifyHeapElement(PCVOID, PCVOID, DWORD);
  169. PRIVATE_CODE BOOL FindHeapElement(PCVOID, PHEAPNODE *);
  170. PRIVATE_CODE void FillNewMemory(PBYTE, DWORD, DWORD);
  171. PRIVATE_CODE void FillFreedMemory(PBYTE, DWORD);
  172. PRIVATE_CODE void FillGrownMemory(PBYTE, DWORD, DWORD, DWORD);
  173. PRIVATE_CODE void FillShrunkenMemory(PBYTE, DWORD, DWORD, DWORD);
  174. PRIVATE_CODE BOOL IsValidHeapPtr(PCVOID);
  175. PRIVATE_CODE BOOL IsHeapOK(void);
  176. PRIVATE_CODE BOOL IsValidPCHEAPNODE(PCHEAPNODE);
  177. PRIVATE_CODE BOOL IsValidPCHEAPELEMDESC(PCHEAPELEMDESC);
  178. PRIVATE_CODE BOOL IsValidHeapElement(PCBYTE, DWORD, DWORD);
  179. PRIVATE_CODE void SpewHeapElementInfo(PCHEAPNODE);
  180. PRIVATE_CODE void AnalyzeHeap(PHEAPSUMMARY, DWORD);
  181. #endif /* DEBUG */
  182. #ifdef PRIVATE_HEAP
  183. /*
  184. ** InitPrivateHeapModule()
  185. **
  186. **
  187. **
  188. ** Arguments:
  189. **
  190. ** Returns:
  191. **
  192. ** Side Effects: none
  193. */
  194. PRIVATE_CODE BOOL InitPrivateHeapModule(void)
  195. {
  196. BOOL bResult;
  197. SYSTEM_INFO si;
  198. ASSERT(! Mhheap);
  199. /* Create shared heap. */
  200. GetSystemInfo(&si);
  201. Mhheap = HeapCreate(0, si.dwPageSize, MAX_SHARED_HEAP_SIZE);
  202. if (Mhheap)
  203. {
  204. #ifdef DEBUG
  205. ASSERT(! Mpheap);
  206. Mpheap = MEMALLOCATE(sizeof(*Mpheap));
  207. if (Mpheap)
  208. {
  209. FillMemory(Mpheap, sizeof(*Mpheap), 0);
  210. bResult = TRUE;
  211. TRACE_OUT((TEXT("InitMemoryManagerModule(): Created shared heap, initial size == %lu, maximum size == %lu."),
  212. si.dwPageSize,
  213. MAX_SHARED_HEAP_SIZE));
  214. }
  215. else
  216. {
  217. EVAL(HeapDestroy(Mhheap));
  218. Mhheap = NULL;
  219. bResult = FALSE;
  220. WARNING_OUT((TEXT("InitMemoryManagerModule(): Failed to create shared heap head.")));
  221. }
  222. #else /* DEBUG */
  223. bResult = TRUE;
  224. #endif /* DEBUG */
  225. }
  226. else
  227. {
  228. bResult = FALSE;
  229. WARNING_OUT((TEXT("InitMemoryManagerModule(): Failed to create shared heap.")));
  230. }
  231. return(bResult);
  232. }
  233. #else /* PRIVATE_HEAP */
  234. /*
  235. ** InitHeapModule()
  236. **
  237. **
  238. **
  239. ** Arguments:
  240. **
  241. ** Returns:
  242. **
  243. ** Side Effects: none
  244. */
  245. PRIVATE_CODE BOOL InitHeapModule(void)
  246. {
  247. BOOL bResult;
  248. #ifdef DEBUG
  249. ASSERT(! Mpheap);
  250. Mpheap = MEMALLOCATE(sizeof(*Mpheap));
  251. if (Mpheap)
  252. {
  253. FillMemory(Mpheap, sizeof(*Mpheap), 0);
  254. TRACE_OUT((TEXT("InitMemoryManagerModule(): Created heap.")));
  255. }
  256. else
  257. WARNING_OUT((TEXT("InitMemoryManagerModule(): Failed to create heap head.")));
  258. bResult = (Mpheap != NULL);
  259. #else
  260. bResult = TRUE;
  261. #endif
  262. return(bResult);
  263. }
  264. #endif /* PRIVATE_HEAP */
  265. #ifdef DEBUG
  266. /*
  267. ** CalculatePrivateSize()
  268. **
  269. **
  270. **
  271. ** Arguments:
  272. **
  273. ** Returns:
  274. **
  275. ** Side Effects: none
  276. */
  277. PRIVATE_CODE DWORD CalculatePrivateSize(DWORD dwcbPublicSize)
  278. {
  279. ASSERT(dwcbPublicSize <= DWORD_MAX - sizeof(MchsPrefix) - sizeof(MchsSuffix));
  280. return(dwcbPublicSize + sizeof(MchsPrefix) + sizeof(MchsSuffix));
  281. }
  282. /*
  283. ** GetPrivateHeapPtr()
  284. **
  285. **
  286. **
  287. ** Arguments:
  288. **
  289. ** Returns:
  290. **
  291. ** Side Effects: none
  292. */
  293. PRIVATE_CODE PVOID GetPrivateHeapPtr(PVOID pvPublic)
  294. {
  295. ASSERT((ULONG_PTR)pvPublic > sizeof(MchsPrefix));
  296. return((PBYTE)pvPublic - sizeof(MchsPrefix));
  297. }
  298. /*
  299. ** GetPublicHeapPtr()
  300. **
  301. **
  302. **
  303. ** Arguments:
  304. **
  305. ** Returns:
  306. **
  307. ** Side Effects: none
  308. */
  309. PRIVATE_CODE PVOID GetPublicHeapPtr(PVOID pvPrivate)
  310. {
  311. ASSERT((PCBYTE)pvPrivate <= (PCBYTE)PTR_MAX - sizeof(MchsPrefix));
  312. return((PBYTE)pvPrivate + sizeof(MchsPrefix));
  313. }
  314. /*
  315. ** GetHeapSize()
  316. **
  317. **
  318. **
  319. ** Arguments:
  320. **
  321. ** Returns:
  322. **
  323. ** Side Effects: none
  324. */
  325. PRIVATE_CODE DWORD GetHeapSize(PCVOID pcv)
  326. {
  327. PHEAPNODE phn;
  328. DWORD dwcbSize;
  329. if (EVAL(FindHeapElement(pcv, &phn)))
  330. dwcbSize = phn->dwcbSize;
  331. else
  332. dwcbSize = 0;
  333. return(dwcbSize);
  334. }
  335. /*
  336. ** AddHeapElement()
  337. **
  338. **
  339. **
  340. ** Arguments:
  341. **
  342. ** Returns:
  343. **
  344. ** Side Effects: none
  345. **
  346. ** Assumes that the global variables GpcszElemHdrSize, GpcszElemHdrFile, and
  347. ** GulElemHdrLine are filled in.
  348. */
  349. PRIVATE_CODE BOOL AddHeapElement(PCVOID pcvNew, DWORD dwcbSize)
  350. {
  351. PHEAPNODE phnNew;
  352. /* Is the new heap element already in the list? */
  353. ASSERT(! FindHeapElement(pcvNew, &phnNew));
  354. if (Mpheap)
  355. {
  356. /* Create new heap node. */
  357. phnNew = MEMALLOCATE(sizeof(*phnNew));
  358. if (phnNew)
  359. {
  360. /* Fill in heap node fields. */
  361. phnNew->pcv = pcvNew;
  362. phnNew->dwcbSize = dwcbSize;
  363. /* Insert heap node at front of list. */
  364. phnNew->phnNext = Mpheap->hnHead.phnNext;
  365. phnNew->phnPrev = &(Mpheap->hnHead);
  366. Mpheap->hnHead.phnNext = phnNew;
  367. if (phnNew->phnNext)
  368. phnNew->phnNext->phnPrev = phnNew;
  369. /* Fill in heap element descriptor fields. */
  370. MyLStrCpyN(phnNew->hed.rgchSize, GpcszElemHdrSize, ARRAYSIZE(phnNew->hed.rgchSize));
  371. MyLStrCpyN(phnNew->hed.rgchFile, GpcszElemHdrFile, ARRAYSIZE(phnNew->hed.rgchFile));
  372. phnNew->hed.ulLine = GulElemHdrLine;
  373. ASSERT(IS_VALID_STRUCT_PTR(phnNew, CHEAPNODE));
  374. }
  375. }
  376. else
  377. phnNew = NULL;
  378. return(phnNew != NULL);
  379. }
  380. /*
  381. ** RemoveHeapElement()
  382. **
  383. **
  384. **
  385. ** Arguments:
  386. **
  387. ** Returns:
  388. **
  389. ** Side Effects: none
  390. */
  391. PRIVATE_CODE void RemoveHeapElement(PCVOID pcvOld)
  392. {
  393. PHEAPNODE phnOld;
  394. if (EVAL(FindHeapElement(pcvOld, &phnOld)))
  395. {
  396. /* Remove heap node from list. */
  397. phnOld->phnPrev->phnNext = phnOld->phnNext;
  398. if (phnOld->phnNext)
  399. phnOld->phnNext->phnPrev = phnOld->phnPrev;
  400. MEMFREE(phnOld);
  401. }
  402. return;
  403. }
  404. /*
  405. ** ModifyHeapElement()
  406. **
  407. **
  408. **
  409. ** Arguments:
  410. **
  411. ** Returns:
  412. **
  413. ** Side Effects: none
  414. */
  415. PRIVATE_CODE void ModifyHeapElement(PCVOID pcvOld, PCVOID pcvNew, DWORD dwcbNewSize)
  416. {
  417. PHEAPNODE phn;
  418. if (EVAL(FindHeapElement(pcvOld, &phn)))
  419. {
  420. phn->pcv = pcvNew;
  421. phn->dwcbSize = dwcbNewSize;
  422. }
  423. return;
  424. }
  425. /*
  426. ** FindHeapElement()
  427. **
  428. **
  429. **
  430. ** Arguments:
  431. **
  432. ** Returns:
  433. **
  434. ** Side Effects: none
  435. */
  436. PRIVATE_CODE BOOL FindHeapElement(PCVOID pcvTarget, PHEAPNODE *pphn)
  437. {
  438. BOOL bFound = FALSE;
  439. PHEAPNODE phn;
  440. ASSERT(IS_VALID_WRITE_PTR(pphn, PHEAPNODE));
  441. if (Mpheap)
  442. {
  443. for (phn = Mpheap->hnHead.phnNext;
  444. phn;
  445. phn = phn->phnNext)
  446. {
  447. /*
  448. * Verify each HEAPNODE structure carefully. We may be in the middle of
  449. * a ModifyHeapElement() call, in which case just the target HEAPNODE may
  450. * be invalid, e.g., after MEMREALLOCATE() in ReallocateMemory().
  451. */
  452. ASSERT((IS_VALID_READ_PTR(phn, CHEAPNODE) && phn->pcv == pcvTarget) ||
  453. IS_VALID_STRUCT_PTR(phn, CHEAPNODE));
  454. if (phn->pcv == pcvTarget)
  455. {
  456. *pphn = phn;
  457. bFound = TRUE;
  458. break;
  459. }
  460. }
  461. }
  462. return(bFound);
  463. }
  464. /*
  465. ** FillNewMemory()
  466. **
  467. **
  468. **
  469. ** Arguments:
  470. **
  471. ** Returns:
  472. **
  473. ** Side Effects: none
  474. */
  475. PRIVATE_CODE void FillNewMemory(PBYTE pbyte, DWORD dwcbRequestedSize,
  476. DWORD dwcbAllocatedSize)
  477. {
  478. ASSERT(dwcbRequestedSize >= sizeof(MchsPrefix) + sizeof(MchsSuffix));
  479. ASSERT(dwcbAllocatedSize >= dwcbRequestedSize);
  480. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pbyte, BYTE, (UINT)dwcbAllocatedSize));
  481. /* Fill new heap element with the uninitialized byte value. */
  482. FillMemory(pbyte, dwcbAllocatedSize, UNINITIALIZED_BYTE_VALUE);
  483. /* Copy prefix and suffix heap element sentinels. */
  484. CopyMemory(pbyte, &MchsPrefix, sizeof(MchsPrefix));
  485. CopyMemory(pbyte + dwcbRequestedSize - sizeof(MchsSuffix), &MchsSuffix,
  486. sizeof(MchsSuffix));
  487. return;
  488. }
  489. /*
  490. ** FillFreedMemory()
  491. **
  492. **
  493. **
  494. ** Arguments:
  495. **
  496. ** Returns:
  497. **
  498. ** Side Effects: none
  499. */
  500. PRIVATE_CODE void FillFreedMemory(PBYTE pbyte, DWORD dwcbAllocatedSize)
  501. {
  502. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pbyte, BYTE, (UINT)dwcbAllocatedSize));
  503. /* Fill old heap element with the freed byte value. */
  504. FillMemory(pbyte, dwcbAllocatedSize, FREED_BYTE_VALUE);
  505. return;
  506. }
  507. /*
  508. ** FillGrownMemory()
  509. **
  510. **
  511. **
  512. ** Arguments:
  513. **
  514. ** Returns:
  515. **
  516. ** Side Effects: none
  517. */
  518. PRIVATE_CODE void FillGrownMemory(PBYTE pbyte, DWORD dwcbOldRequestedSize,
  519. DWORD dwcbNewRequestedSize,
  520. DWORD dwcbNewAllocatedSize)
  521. {
  522. ASSERT(dwcbOldRequestedSize >= sizeof(MchsPrefix) + sizeof(MchsSuffix));
  523. ASSERT(dwcbNewRequestedSize > dwcbOldRequestedSize);
  524. ASSERT(dwcbNewAllocatedSize >= dwcbNewRequestedSize);
  525. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pbyte, BYTE, (UINT)dwcbNewAllocatedSize));
  526. ASSERT(MyMemComp(pbyte, &MchsPrefix, sizeof(MchsPrefix)) == CR_EQUAL);
  527. /* Fill new heap element tail with the uninitialized byte value. */
  528. FillMemory(pbyte + dwcbOldRequestedSize - sizeof(MchsSuffix),
  529. dwcbNewRequestedSize - dwcbOldRequestedSize,
  530. UNINITIALIZED_BYTE_VALUE);
  531. /* Copy suffix heap element sentinel. */
  532. CopyMemory(pbyte + dwcbNewRequestedSize - sizeof(MchsSuffix), &MchsSuffix,
  533. sizeof(MchsSuffix));
  534. return;
  535. }
  536. /*
  537. ** FillShrunkenMemory()
  538. **
  539. **
  540. **
  541. ** Arguments:
  542. **
  543. ** Returns:
  544. **
  545. ** Side Effects: none
  546. */
  547. PRIVATE_CODE void FillShrunkenMemory(PBYTE pbyte, DWORD dwcbOldRequestedSize,
  548. DWORD dwcbNewRequestedSize,
  549. DWORD dwcbNewAllocatedSize)
  550. {
  551. ASSERT(dwcbNewRequestedSize >= sizeof(MchsPrefix) + sizeof(MchsSuffix));
  552. ASSERT(dwcbNewRequestedSize < dwcbOldRequestedSize);
  553. ASSERT(dwcbNewAllocatedSize >= dwcbNewRequestedSize);
  554. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pbyte, BYTE, (UINT)dwcbNewAllocatedSize));
  555. ASSERT(MyMemComp(pbyte, &MchsPrefix, sizeof(MchsPrefix)) == CR_EQUAL);
  556. /* Fill old heap element tail with the freed byte value. */
  557. FillMemory(pbyte + dwcbNewRequestedSize,
  558. dwcbOldRequestedSize - dwcbNewRequestedSize, FREED_BYTE_VALUE);
  559. /* Copy suffix heap element sentinel. */
  560. CopyMemory(pbyte + dwcbNewRequestedSize - sizeof(MchsSuffix), &MchsSuffix,
  561. sizeof(MchsSuffix));
  562. return;
  563. }
  564. /*
  565. ** IsValidHeapPtr()
  566. **
  567. **
  568. **
  569. ** Arguments:
  570. **
  571. ** Returns:
  572. **
  573. ** Side Effects: none
  574. */
  575. PRIVATE_CODE BOOL IsValidHeapPtr(PCVOID pcv)
  576. {
  577. PHEAPNODE phnUnused;
  578. return(FindHeapElement(pcv, &phnUnused));
  579. }
  580. /*
  581. ** IsHeapOK()
  582. **
  583. **
  584. **
  585. ** Arguments:
  586. **
  587. ** Returns:
  588. **
  589. ** Side Effects: none
  590. */
  591. PRIVATE_CODE BOOL IsHeapOK(void)
  592. {
  593. PHEAPNODE phn;
  594. if (Mpheap)
  595. {
  596. for (phn = Mpheap->hnHead.phnNext;
  597. phn && IS_VALID_STRUCT_PTR(phn, CHEAPNODE);
  598. phn = phn->phnNext)
  599. ;
  600. }
  601. else
  602. phn = (PHEAPNODE)0xFFFF;
  603. return(phn == NULL);
  604. }
  605. /*
  606. ** IsValidPCHEAPNODE()
  607. **
  608. **
  609. **
  610. ** Arguments:
  611. **
  612. ** Returns:
  613. **
  614. ** Side Effects: none
  615. */
  616. PRIVATE_CODE BOOL IsValidPCHEAPNODE(PCHEAPNODE pchn)
  617. {
  618. BOOL bResult;
  619. if (IS_VALID_READ_PTR(pchn, CHEAPNODE) &&
  620. IS_VALID_READ_PTR(pchn->phnPrev, CHEAPNODE) &&
  621. EVAL(pchn->phnPrev->phnNext == pchn) &&
  622. EVAL(! pchn->phnNext ||
  623. (IS_VALID_READ_PTR(pchn->phnNext, CHEAPNODE) &&
  624. EVAL(pchn->phnNext->phnPrev == pchn))) &&
  625. EVAL(IsValidHeapElement(pchn->pcv, pchn->dwcbSize, MEMSIZE((PVOID)(pchn->pcv)))) &&
  626. IS_VALID_STRUCT_PTR(&(pchn->hed), CHEAPELEMDESC))
  627. bResult = TRUE;
  628. else
  629. bResult = FALSE;
  630. return(bResult);
  631. }
  632. /*
  633. ** IsValidPCHEAPELEMDESC()
  634. **
  635. **
  636. **
  637. ** Arguments:
  638. **
  639. ** Returns:
  640. **
  641. ** Side Effects: none
  642. */
  643. PRIVATE_CODE BOOL IsValidPCHEAPELEMDESC(PCHEAPELEMDESC pched)
  644. {
  645. BOOL bResult;
  646. /* Any value for pched->ulLine is valid. */
  647. if (IS_VALID_READ_PTR(pched, CHEAPELEMDESC))
  648. bResult = TRUE;
  649. else
  650. bResult = FALSE;
  651. return(bResult);
  652. }
  653. /*
  654. ** IsValidHeapElement()
  655. **
  656. **
  657. **
  658. ** Arguments:
  659. **
  660. ** Returns:
  661. **
  662. ** Side Effects: none
  663. */
  664. PRIVATE_CODE BOOL IsValidHeapElement(PCBYTE pcbyte, DWORD dwcbRequestedSize,
  665. DWORD dwcbAllocatedSize)
  666. {
  667. BOOL bResult;
  668. if (EVAL(dwcbRequestedSize >= sizeof(MchsPrefix) + sizeof(MchsSuffix)) &&
  669. EVAL(dwcbAllocatedSize >= dwcbRequestedSize) &&
  670. IS_VALID_READ_PTR(pcbyte, dwcbAllocatedSize) &&
  671. EVAL(MyMemComp(pcbyte, &MchsPrefix, sizeof(MchsPrefix)) == CR_EQUAL) &&
  672. EVAL(MyMemComp(pcbyte + dwcbRequestedSize - sizeof(MchsSuffix), &MchsSuffix, sizeof(MchsSuffix)) == CR_EQUAL))
  673. bResult = TRUE;
  674. else
  675. bResult = FALSE;
  676. return(bResult);
  677. }
  678. /*
  679. ** SpewHeapElementInfo()
  680. **
  681. **
  682. **
  683. ** Arguments:
  684. **
  685. ** Returns:
  686. **
  687. ** Side Effects: none
  688. */
  689. PRIVATE_CODE void SpewHeapElementInfo(PCHEAPNODE pchn)
  690. {
  691. ASSERT(IS_VALID_STRUCT_PTR(pchn, CHEAPNODE));
  692. TRACE_OUT((TEXT("Used heap element at %#lx:\r\n")
  693. TEXT(" %lu bytes requested\r\n")
  694. TEXT(" %lu bytes allocated\r\n")
  695. TEXT(" originally allocated as '%s' bytes in file %s at line %lu"),
  696. pchn->pcv,
  697. pchn->dwcbSize,
  698. MEMSIZE((PVOID)(pchn->pcv)),
  699. pchn->hed.rgchSize,
  700. pchn->hed.rgchFile,
  701. pchn->hed.ulLine));
  702. return;
  703. }
  704. /*
  705. ** AnalyzeHeap()
  706. **
  707. **
  708. **
  709. ** Arguments:
  710. **
  711. ** Returns:
  712. **
  713. ** Side Effects: none
  714. */
  715. PRIVATE_CODE void AnalyzeHeap(PHEAPSUMMARY phs, DWORD dwFlags)
  716. {
  717. PCHEAPNODE pchn;
  718. ULONG ulcHeapElements = 0;
  719. DWORD dwcbUsed = 0;
  720. ASSERT(IS_VALID_WRITE_PTR(phs, HEAPSUMMARY));
  721. ASSERT(FLAGS_ARE_VALID(dwFlags, SHS_FL_SPEW_USED_INFO));
  722. ASSERT(IsHeapOK());
  723. TRACE_OUT((TEXT("Starting private heap analysis.")));
  724. if (Mpheap)
  725. {
  726. for (pchn = Mpheap->hnHead.phnNext;
  727. pchn;
  728. pchn = pchn->phnNext)
  729. {
  730. ASSERT(IS_VALID_STRUCT_PTR(pchn, CHEAPNODE));
  731. ASSERT(ulcHeapElements < ULONG_MAX);
  732. ulcHeapElements++;
  733. ASSERT(dwcbUsed < DWORD_MAX - pchn->dwcbSize);
  734. dwcbUsed += pchn->dwcbSize;
  735. if (IS_FLAG_SET(dwFlags, SHS_FL_SPEW_USED_INFO))
  736. SpewHeapElementInfo(pchn);
  737. }
  738. phs->ulcUsedElements = ulcHeapElements;
  739. phs->dwcbUsedSize = dwcbUsed;
  740. }
  741. else
  742. WARNING_OUT((TEXT("Private heap not allocated!")));
  743. TRACE_OUT((TEXT("Private heap analysis complete.")));
  744. return;
  745. }
  746. #endif /* DEBUG */
  747. /****************************** Public Functions *****************************/
  748. /*
  749. ** InitMemoryManagerModule()
  750. **
  751. ** When PRIVATE_HEAP is defined, this function should be called only
  752. ** once, when the DLL is being first initialized. When PRIVATE_HEAP
  753. ** is not defined, this function should be called for every
  754. ** DLL_PROCESS_ATTACH.
  755. **
  756. **
  757. ** Arguments:
  758. **
  759. ** Returns:
  760. **
  761. ** Side Effects: none
  762. */
  763. PUBLIC_CODE BOOL InitMemoryManagerModule(void)
  764. {
  765. BOOL bResult;
  766. #ifdef PRIVATE_HEAP
  767. bResult = InitPrivateHeapModule();
  768. #else /* PRIVATE_HEAP */
  769. bResult = InitHeapModule();
  770. #endif
  771. return(bResult);
  772. }
  773. /*
  774. ** ExitMemoryManagerModule()
  775. **
  776. ** When PRIVATE_HEAP is defined, this function should be called only
  777. ** once, when the DLL is finally being terminated. When PRIVATE_HEAP
  778. ** is not defined, this function should be called for every
  779. ** DLL_PROCESS_DETACH.
  780. **
  781. **
  782. ** Arguments:
  783. **
  784. ** Returns:
  785. **
  786. ** Side Effects: none
  787. */
  788. PUBLIC_CODE void ExitMemoryManagerModule(void)
  789. {
  790. #ifdef DEBUG
  791. if (Mpheap)
  792. {
  793. MEMFREE(Mpheap);
  794. Mpheap = NULL;
  795. }
  796. else
  797. WARNING_OUT((TEXT("ExitMemoryManagerModule() called when Mpheap is NULL.")));
  798. #endif
  799. #ifdef PRIVATE_HEAP
  800. if (Mhheap)
  801. {
  802. EVAL(HeapDestroy(Mhheap));
  803. Mhheap = NULL;
  804. }
  805. else
  806. WARNING_OUT((TEXT("ExitMemoryManagerModule() called when Mhheap is NULL.")));
  807. #endif
  808. return;
  809. }
  810. /*
  811. ** MyMemComp()
  812. **
  813. **
  814. **
  815. ** Arguments:
  816. **
  817. ** Returns:
  818. **
  819. ** Side Effects: none
  820. */
  821. PUBLIC_CODE COMPARISONRESULT MyMemComp(PCVOID pcv1, PCVOID pcv2, DWORD dwcbSize)
  822. {
  823. int nResult = 0;
  824. PCBYTE pcbyte1 = pcv1;
  825. PCBYTE pcbyte2 = pcv2;
  826. ASSERT(IS_VALID_READ_BUFFER_PTR(pcv1, BYTE, (UINT)dwcbSize));
  827. ASSERT(IS_VALID_READ_BUFFER_PTR(pcv2, BYTE, (UINT)dwcbSize));
  828. while (dwcbSize > 0 &&
  829. ! (nResult = *pcbyte1 - *pcbyte2))
  830. {
  831. pcbyte1++;
  832. pcbyte2++;
  833. dwcbSize--;
  834. }
  835. return(MapIntToComparisonResult(nResult));
  836. }
  837. /*
  838. ** MyAllocateMemory()
  839. **
  840. **
  841. **
  842. ** Arguments:
  843. **
  844. ** Returns:
  845. **
  846. ** Side Effects: none
  847. */
  848. PUBLIC_CODE BOOL MyAllocateMemory(DWORD dwcbSize, PVOID *ppvNew)
  849. {
  850. #ifdef DEBUG
  851. DWORD dwcbRequestedSize = dwcbSize;
  852. // ASSERT(dwcbSize >= 0); // DWORDs are nonnegative by definition
  853. ASSERT(IS_VALID_WRITE_PTR(ppvNew, PVOID));
  854. dwcbSize = CalculatePrivateSize(dwcbSize);
  855. if (IS_FLAG_SET(MdwMemoryManagerModuleFlags, MEMMGR_DFL_VALIDATE_HEAP_ON_ENTRY))
  856. ASSERT(IsHeapOK());
  857. #endif
  858. *ppvNew = MEMALLOCATE(dwcbSize);
  859. #ifdef DEBUG
  860. if (*ppvNew)
  861. {
  862. FillNewMemory(*ppvNew, dwcbSize, MEMSIZE(*ppvNew));
  863. if (AddHeapElement(*ppvNew, dwcbSize))
  864. {
  865. *ppvNew = GetPublicHeapPtr(*ppvNew);
  866. ASSERT(IS_VALID_WRITE_BUFFER_PTR(*ppvNew, BYTE, (UINT)dwcbRequestedSize));
  867. }
  868. else
  869. {
  870. EVAL(MEMFREE(*ppvNew));
  871. *ppvNew = NULL;
  872. }
  873. }
  874. if (IS_FLAG_SET(MdwMemoryManagerModuleFlags, MEMMGR_DFL_VALIDATE_HEAP_ON_EXIT))
  875. ASSERT(IsHeapOK());
  876. #endif
  877. return(*ppvNew != NULL);
  878. }
  879. /*
  880. ** FreeMemory()
  881. **
  882. **
  883. **
  884. ** Arguments:
  885. **
  886. ** Returns:
  887. **
  888. ** Side Effects: none
  889. */
  890. PUBLIC_CODE void FreeMemory(PVOID pvOld)
  891. {
  892. #ifdef DEBUG
  893. if (IS_FLAG_SET(MdwMemoryManagerModuleFlags, MEMMGR_DFL_VALIDATE_HEAP_ON_ENTRY))
  894. ASSERT(IsHeapOK());
  895. pvOld = GetPrivateHeapPtr(pvOld);
  896. ASSERT(IsValidHeapPtr(pvOld));
  897. RemoveHeapElement(pvOld);
  898. FillFreedMemory(pvOld, MEMSIZE(pvOld));
  899. #endif
  900. EVAL(MEMFREE(pvOld));
  901. #ifdef DEBUG
  902. if (IS_FLAG_SET(MdwMemoryManagerModuleFlags, MEMMGR_DFL_VALIDATE_HEAP_ON_EXIT))
  903. ASSERT(IsHeapOK());
  904. #endif /* DEBUG */
  905. return;
  906. }
  907. /*
  908. ** ReallocateMemory()
  909. **
  910. **
  911. **
  912. ** Arguments:
  913. **
  914. ** Returns:
  915. **
  916. ** Side Effects: none
  917. */
  918. PUBLIC_CODE BOOL ReallocateMemory(PVOID pvOld, DWORD dwcbNewSize, PVOID *ppvNew)
  919. {
  920. #ifdef DEBUG
  921. DWORD dwcbRequestedSize = dwcbNewSize;
  922. DWORD dwcbOldSize;
  923. ASSERT(IS_VALID_WRITE_PTR(ppvNew, PVOID));
  924. if (IS_FLAG_SET(MdwMemoryManagerModuleFlags, MEMMGR_DFL_VALIDATE_HEAP_ON_ENTRY))
  925. ASSERT(IsHeapOK());
  926. pvOld = GetPrivateHeapPtr(pvOld);
  927. ASSERT(IsValidHeapPtr(pvOld));
  928. dwcbNewSize = CalculatePrivateSize(dwcbNewSize);
  929. dwcbOldSize = GetHeapSize(pvOld);
  930. if (dwcbNewSize == dwcbOldSize)
  931. WARNING_OUT((TEXT("ReallocateMemory(): Size of heap element %#lx is already %lu bytes."),
  932. GetPublicHeapPtr(pvOld),
  933. dwcbNewSize));
  934. #endif
  935. *ppvNew = MEMREALLOCATE(pvOld, dwcbNewSize);
  936. #ifdef DEBUG
  937. if (*ppvNew)
  938. {
  939. /* Bigger or smaller? */
  940. if (dwcbNewSize > dwcbOldSize)
  941. /* Bigger. */
  942. FillGrownMemory(*ppvNew, dwcbOldSize, dwcbNewSize, MEMSIZE(*ppvNew));
  943. else
  944. /* Smaller. */
  945. FillShrunkenMemory(*ppvNew, dwcbOldSize, dwcbNewSize, MEMSIZE(*ppvNew));
  946. ModifyHeapElement(pvOld, *ppvNew, dwcbNewSize);
  947. *ppvNew = GetPublicHeapPtr(*ppvNew);
  948. ASSERT(IS_VALID_WRITE_BUFFER_PTR(*ppvNew, BYTE, (UINT)dwcbRequestedSize));
  949. }
  950. if (IS_FLAG_SET(MdwMemoryManagerModuleFlags, MEMMGR_DFL_VALIDATE_HEAP_ON_EXIT))
  951. ASSERT(IsHeapOK());
  952. #endif
  953. return(*ppvNew != NULL);
  954. }
  955. /*
  956. ** GetMemorySize()
  957. **
  958. **
  959. **
  960. ** Arguments:
  961. **
  962. ** Returns:
  963. **
  964. ** Side Effects: none
  965. */
  966. PUBLIC_CODE DWORD GetMemorySize(PVOID pv)
  967. {
  968. ASSERT(IsValidHeapPtr(GetPrivateHeapPtr(pv)));
  969. return(MEMSIZE(pv));
  970. }
  971. #ifdef DEBUG
  972. /*
  973. ** SetMemoryManagerModuleIniSwitches()
  974. **
  975. **
  976. **
  977. ** Arguments:
  978. **
  979. ** Returns:
  980. **
  981. ** Side Effects: none
  982. */
  983. PUBLIC_CODE BOOL SetMemoryManagerModuleIniSwitches(void)
  984. {
  985. BOOL bResult;
  986. bResult = SetIniSwitches(MrgcpcvisMemoryManagerModule,
  987. ARRAY_ELEMENTS(MrgcpcvisMemoryManagerModule));
  988. ASSERT(FLAGS_ARE_VALID(MdwMemoryManagerModuleFlags, ALL_MEMMGR_DFLAGS));
  989. return(bResult);
  990. }
  991. /*
  992. ** SpewHeapSummary()
  993. **
  994. **
  995. **
  996. ** Arguments:
  997. **
  998. ** Returns:
  999. **
  1000. ** Side Effects: none
  1001. */
  1002. PUBLIC_CODE void SpewHeapSummary(DWORD dwFlags)
  1003. {
  1004. HEAPSUMMARY hs;
  1005. ASSERT(FLAGS_ARE_VALID(dwFlags, SHS_FL_SPEW_USED_INFO));
  1006. AnalyzeHeap(&hs, dwFlags);
  1007. TRACE_OUT((TEXT("Heap summary: %lu bytes in %lu used elements."),
  1008. hs.dwcbUsedSize,
  1009. hs.ulcUsedElements));
  1010. return;
  1011. }
  1012. #endif /* DEBUG */