Source code of Windows XP (NT5)
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.

899 lines
23 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: mem.cpp
  4. //
  5. // Module: CMUTIL.DLL
  6. //
  7. // Synopsis: Basic memory manipulation routines
  8. //
  9. // Copyright (c) 1997-1999 Microsoft Corporation
  10. //
  11. // Author: henryt Created 03/01/98
  12. //
  13. //+----------------------------------------------------------------------------
  14. #include "cmmaster.h"
  15. //+----------------------------------------------------------------------------
  16. // definitions
  17. //+----------------------------------------------------------------------------
  18. HANDLE g_hProcessHeap = NULL;
  19. #ifdef DEBUG
  20. LONG g_lMallocCnt = 0; // a counter to detect memory leak
  21. #endif
  22. #if defined(DEBUG) && defined(DEBUG_MEM)
  23. //////////////////////////////////////////////////////////////////////////////////
  24. //
  25. // If DEBUG_MEM is defined, track all the memory alloction in debug version.
  26. // Keep all the allocated memory blocks in the double link list.
  27. // Record the file name and line #, where memory is allocated.
  28. // Add extra tag at the beginning and end of the memory to watch for overwriten
  29. // The whole list is checked against corruption for every alloc/free operation
  30. //
  31. // The folowing three function is exported:
  32. // BOOL CheckDebugMem(void); // return TRUE for succeed
  33. // void* AllocDebugMem(long size,const char* lpFileName,int nLine);
  34. // BOOL FreeDebugMem(void* pMem); // return TRUE for succeed
  35. //
  36. ///////////////////////////////////////////////////////////////////////////////////
  37. //#undef new
  38. #define MEMTAG 0xBEEDB77D // the tag before/after the block to watch for overwriten
  39. #define FREETAG 0xBD // the flag to fill freed memory
  40. #define TAGSIZE (sizeof(long))// Size of the tags appended to the end of the block
  41. //
  42. // memory block, a double link list
  43. //
  44. struct TMemoryBlock
  45. {
  46. TMemoryBlock* pPrev;
  47. TMemoryBlock* pNext;
  48. long size;
  49. const char* lpFileName; // The filename
  50. int nLine; // The line number
  51. long topTag; // The watch tag at the beginning
  52. // followed by:
  53. // BYTE data[nDataSize];
  54. // long bottomTag;
  55. BYTE* pbData() const // Return the pointer to the actual data
  56. { return (BYTE*) (this + 1); }
  57. };
  58. //
  59. // The following internal function can be overwritten to change the behaivor
  60. //
  61. static void* MemAlloc(long size);
  62. static BOOL MemFree(void* pMem);
  63. static void LockDebugMem();
  64. static void UnlockDebugMem();
  65. //
  66. // Internal function
  67. //
  68. static BOOL RealCheckMemory(); // without call Enter/Leave critical Section
  69. static BOOL CheckBlock(const TMemoryBlock* pBlock) ;
  70. //
  71. // Internal data, protected by the lock to be multi-thread safe
  72. //
  73. static long nTotalMem; // Total bytes of memory allocated
  74. static long nTotalBlock; // Total # of blocks allocated
  75. static TMemoryBlock head; // The head of the double link list
  76. //
  77. // critical section to lock \ unlock DebugMemory
  78. // The constructor lock the memory, the destructor unlock the memory
  79. //
  80. class MemCriticalSection
  81. {
  82. public:
  83. MemCriticalSection()
  84. {
  85. LockDebugMem();
  86. }
  87. ~MemCriticalSection()
  88. {
  89. UnlockDebugMem();
  90. }
  91. };
  92. static BOOL fDebugMemInited = FALSE; // whether the debug memory is initialized
  93. //+----------------------------------------------------------------------------
  94. //
  95. // Function: StartDebugMemory
  96. //
  97. // Synopsis: Initialize the data for debug memory
  98. //
  99. // Arguments: None
  100. //
  101. // Returns:
  102. //
  103. // History: fengsun Created Header 4/2/98
  104. //
  105. //+----------------------------------------------------------------------------
  106. static void StartDebugMemory()
  107. {
  108. fDebugMemInited = TRUE;
  109. head.pNext = head.pPrev = NULL;
  110. head.topTag = MEMTAG;
  111. head.size = 0;
  112. nTotalMem = 0;
  113. nTotalBlock = 0;
  114. }
  115. //+----------------------------------------------------------------------------
  116. //
  117. // Function: MemAlloc
  118. //
  119. // Synopsis: Allocate a block of memory. This function should be overwriten
  120. // if different allocation method is used
  121. //
  122. // Arguments: long size - size of the memory
  123. //
  124. // Returns: void* - the memory allocated or NULL
  125. //
  126. // History: fengsun Created Header 4/2/98
  127. //
  128. //+----------------------------------------------------------------------------
  129. static void* MemAlloc(long size)
  130. {
  131. return (HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size));
  132. }
  133. //+----------------------------------------------------------------------------
  134. //
  135. // Function: MemFree
  136. //
  137. // Synopsis: Free a block of memory. This function should be overwriten
  138. // if different allocation method is used
  139. //
  140. // Arguments: void* pMem - The memory to be freed
  141. //
  142. // Returns: static BOOL - TRUE if succeeded
  143. //
  144. // History: Created Header 4/2/98
  145. //
  146. //+----------------------------------------------------------------------------
  147. static BOOL MemFree(void* pMem)
  148. {
  149. return HeapFree(GetProcessHeap(), 0, pMem);
  150. }
  151. //
  152. // Data / functions to provide mutual exclusion.
  153. // Can be overwritten, if other methed is to be used.
  154. //
  155. static BOOL fLockInited = FALSE; // whether the critical section is inialized
  156. static CRITICAL_SECTION cSection; // The critical section to protect the link list
  157. //+----------------------------------------------------------------------------
  158. //
  159. // Function: InitLock
  160. //
  161. // Synopsis: Initialize the memory lock which protects the doublely linked list
  162. // that contains all of the allocated memory blocks.
  163. //
  164. // Arguments: None
  165. //
  166. // Returns: Nothing
  167. //
  168. // History: quintinb Created Header 01/14/2000
  169. //
  170. //+----------------------------------------------------------------------------
  171. static void InitLock()
  172. {
  173. fLockInited = TRUE;
  174. InitializeCriticalSection(&cSection);
  175. }
  176. //+----------------------------------------------------------------------------
  177. //
  178. // Function: LockDebugMem
  179. //
  180. // Synopsis: Locks the doublely linked list that contains all of the
  181. // allocated memory blocks so that it can only be accessed by the
  182. // locking thread.
  183. //
  184. // Arguments: None
  185. //
  186. // Returns: Nothing
  187. //
  188. // History: quintinb Created Header 01/14/2000
  189. //
  190. //+----------------------------------------------------------------------------
  191. static void LockDebugMem()
  192. {
  193. static int i = 0;
  194. if(!fLockInited)
  195. {
  196. InitLock();
  197. }
  198. EnterCriticalSection(&cSection);
  199. }
  200. //+----------------------------------------------------------------------------
  201. //
  202. // Function: UnlockDebugMem
  203. //
  204. // Synopsis: Unlocks the doublely linked list that contains all of the
  205. // allocated memory blocks.
  206. //
  207. // Arguments: None
  208. //
  209. // Returns: Nothing
  210. //
  211. // History: quintinb Created Header 01/14/2000
  212. //
  213. //+----------------------------------------------------------------------------
  214. static void UnlockDebugMem()
  215. {
  216. LeaveCriticalSection(&cSection);
  217. }
  218. //+----------------------------------------------------------------------------
  219. //
  220. // Function: AllocDebugMem
  221. //
  222. // Synopsis: Process memory allocation request.
  223. // Check the link list. Allocate a larger block.
  224. // Record filename/linenumber, add tags and insert to the list
  225. //
  226. // Arguments: long size - Size of the memory to be allocated
  227. // const char* lpFileName - File name to be recorded
  228. // int nLine - Line number to be recorted
  229. //
  230. // Returns: CMUTILAPI void* - The memory allocated. Ready to use by the caller
  231. //
  232. // History: fengsun Created Header 4/2/98
  233. //
  234. //+----------------------------------------------------------------------------
  235. CMUTILAPI void* AllocDebugMem(long size,const char* lpFileName,int nLine)
  236. {
  237. if (!fDebugMemInited)
  238. {
  239. StartDebugMemory();
  240. }
  241. if (size<0)
  242. {
  243. CMASSERTMSG(FALSE,"Negtive size for alloc");
  244. return NULL;
  245. }
  246. if (size>1024*1024)
  247. {
  248. CMASSERTMSG(FALSE," size for alloc is great than 1Mb");
  249. return NULL;
  250. }
  251. if (size == 0)
  252. {
  253. CMTRACE("Allocate memory of size 0");
  254. return NULL;
  255. }
  256. //
  257. // Protect the access to the list
  258. //
  259. MemCriticalSection criticalSection;
  260. //
  261. // Check the link list first
  262. //
  263. if (!RealCheckMemory())
  264. {
  265. return NULL;
  266. }
  267. //
  268. // Allocate a large block to hold additional information
  269. //
  270. TMemoryBlock* pBlock = (TMemoryBlock*)MemAlloc(sizeof(TMemoryBlock)+size + TAGSIZE);
  271. if (!pBlock)
  272. {
  273. CMTRACE("Outof Memory");
  274. return NULL;
  275. }
  276. //
  277. // record filename/line/size, add tag to the beginning and end
  278. //
  279. pBlock->size = size;
  280. pBlock->topTag = MEMTAG;
  281. pBlock->lpFileName = lpFileName;
  282. pBlock->nLine = nLine;
  283. *(long*)(pBlock->pbData() + size) = MEMTAG;
  284. //
  285. // insert at head
  286. //
  287. pBlock->pNext = head.pNext;
  288. pBlock->pPrev = &head;
  289. if(head.pNext)
  290. head.pNext->pPrev = pBlock;
  291. head.pNext = pBlock;
  292. nTotalMem += size;
  293. nTotalBlock ++;
  294. return pBlock->pbData();
  295. }
  296. //+----------------------------------------------------------------------------
  297. //
  298. // Function: FreeDebugMem
  299. //
  300. // Synopsis: Free the memory allocated by AllocDebugMem
  301. // Check the link list, and the block to be freed.
  302. // Fill the block data with FREETAG before freed
  303. //
  304. // Arguments: void* pMem - Memory to be freed
  305. //
  306. // Returns: BOOL - TRUE for succeeded
  307. //
  308. // History: fengsun Created Header 4/2/98
  309. //
  310. //+----------------------------------------------------------------------------
  311. CMUTILAPI BOOL FreeDebugMem(void* pMem)
  312. {
  313. if (!fDebugMemInited)
  314. {
  315. StartDebugMemory();
  316. }
  317. if (!pMem)
  318. {
  319. return FALSE;
  320. }
  321. //
  322. // Get the lock
  323. //
  324. MemCriticalSection criticalSection;
  325. //
  326. // Get pointer to our structure
  327. //
  328. TMemoryBlock* pBlock =(TMemoryBlock*)( (char*)pMem - sizeof(TMemoryBlock));
  329. //
  330. // Check the block to be freed
  331. //
  332. if (!CheckBlock(pBlock))
  333. {
  334. return FALSE;
  335. }
  336. //
  337. // Check the link list
  338. //
  339. if (!RealCheckMemory())
  340. {
  341. return FALSE;
  342. }
  343. //
  344. // remove the block from the list
  345. //
  346. pBlock->pPrev->pNext = pBlock->pNext;
  347. if (pBlock->pNext)
  348. {
  349. pBlock->pNext->pPrev = pBlock->pPrev;
  350. }
  351. nTotalMem -= pBlock->size;
  352. nTotalBlock --;
  353. //
  354. // Fill the freed memory with 0xBD, leave the size/filename/lineNumber unchanged
  355. //
  356. memset(&pBlock->topTag, FREETAG, (size_t)pBlock->size + sizeof(pBlock->topTag) + TAGSIZE);
  357. return MemFree(pBlock);
  358. }
  359. //+----------------------------------------------------------------------------
  360. //
  361. // Function: void* ReAllocDebugMem
  362. //
  363. // Synopsis: Reallocate a memory with a diffirent size
  364. //
  365. // Arguments: void* pMem - memory to be reallocated
  366. // long nSize - size of the request
  367. // const char* lpFileName - FileName to be recorded
  368. // int nLine - Line umber to be recorded
  369. //
  370. // Returns: void* - new memory returned
  371. //
  372. // History: fengsun Created Header 4/2/98
  373. //
  374. //+----------------------------------------------------------------------------
  375. CMUTILAPI void* ReAllocDebugMem(void* pMem, long nSize, const char* lpFileName,int nLine)
  376. {
  377. if (!fDebugMemInited)
  378. {
  379. StartDebugMemory();
  380. }
  381. if (!pMem)
  382. {
  383. CMTRACE("Free a NULL pointer");
  384. return NULL;
  385. }
  386. //
  387. // Allocate a new block, copy the information over and free the old block.
  388. //
  389. TMemoryBlock* pBlock =(TMemoryBlock*)( (char*)pMem - sizeof(TMemoryBlock));
  390. long lOrginalSize = pBlock->size;
  391. void* pNew = AllocDebugMem(nSize, lpFileName, nLine);
  392. if(pNew)
  393. {
  394. CopyMemory(pNew, pMem, (nSize < lOrginalSize ? nSize : lOrginalSize));
  395. FreeDebugMem(pMem);
  396. }
  397. return pNew;
  398. }
  399. //+----------------------------------------------------------------------------
  400. //
  401. // Function: CheckDebugMem
  402. //
  403. // Synopsis: Exported to external module.
  404. // Call this function, whenever, you want to check against
  405. // memory curruption
  406. //
  407. // Arguments: None
  408. //
  409. // Returns: BOOL - TRUE if the memory is fine.
  410. //
  411. // History: fengsun Created Header 4/2/98
  412. //
  413. //+----------------------------------------------------------------------------
  414. CMUTILAPI BOOL CheckDebugMem()
  415. {
  416. if (!fDebugMemInited)
  417. {
  418. StartDebugMemory();
  419. }
  420. MemCriticalSection criticalSection;
  421. return RealCheckMemory();
  422. }
  423. //+----------------------------------------------------------------------------
  424. //
  425. // Function: RealCheckMemory
  426. //
  427. // Synopsis: Go through the link list to check for memory corruption
  428. //
  429. // Arguments: None
  430. //
  431. // Returns: BOOL - TRUE if the memory is fine.
  432. //
  433. // History: fengsun Created Header 4/2/98
  434. //
  435. //+----------------------------------------------------------------------------
  436. static BOOL RealCheckMemory()
  437. {
  438. TMemoryBlock* pBlock = head.pNext;
  439. int nBlock =0;
  440. while(pBlock!=NULL)
  441. {
  442. if(!CheckBlock(pBlock))
  443. {
  444. return FALSE;
  445. }
  446. pBlock = pBlock->pNext;
  447. nBlock++;
  448. }
  449. if(nBlock != nTotalBlock)
  450. {
  451. CMASSERTMSG(FALSE,"Memery corrupted");
  452. return FALSE;
  453. }
  454. return TRUE;
  455. }
  456. //+----------------------------------------------------------------------------
  457. //
  458. // Function: CheckBlock
  459. //
  460. // Synopsis: Check a block for memory corruption
  461. //
  462. // Arguments: const TMemoryBlock* pBlock -
  463. //
  464. // Returns: BOOL - TRUE, if the block is fine
  465. //
  466. // History: fengsun Created Header 4/2/98
  467. //
  468. //+----------------------------------------------------------------------------
  469. static BOOL CheckBlock(const TMemoryBlock* pBlock)
  470. {
  471. if (pBlock->topTag != MEMTAG) // overwriten at top
  472. {
  473. CMASSERTMSG(FALSE, "Memery corrupted");
  474. return FALSE;
  475. }
  476. if (pBlock->size<0)
  477. {
  478. CMASSERTMSG(FALSE, "Memery corrupted");
  479. return FALSE;
  480. }
  481. if (*(long*)(pBlock->pbData() +pBlock->size) != MEMTAG) // overwriten at bottom
  482. {
  483. CMASSERTMSG(FALSE, "Memery corrupted");
  484. return FALSE;
  485. }
  486. if (pBlock->pPrev && pBlock->pPrev->pNext != pBlock)
  487. {
  488. CMASSERTMSG(FALSE, "Memery corrupted");
  489. return FALSE;
  490. }
  491. if (pBlock->pNext && pBlock->pNext->pPrev != pBlock)
  492. {
  493. CMASSERTMSG(FALSE, "Memery corrupted");
  494. return FALSE;
  495. }
  496. return TRUE;
  497. }
  498. /////////////////////////////////////////////////////////////////////////////
  499. // operator new, delete
  500. /* We did not redefine new and delete
  501. void* __cdecl operator new(size_t nSize)
  502. {
  503. void* p = AllocDebugMem(nSize,NULL,0);
  504. if (p == NULL)
  505. {
  506. CMTRACE("New failed");
  507. }
  508. return p;
  509. }
  510. void* __cdecl operator new(size_t nSize, const char* lpszFileName, int nLine)
  511. {
  512. void* p = AllocDebugMem(nSize, lpszFileName,nLine);
  513. if (p == NULL)
  514. {
  515. CMTRACE("New failed");
  516. }
  517. return p;
  518. }
  519. void __cdecl operator delete(void* p)
  520. {
  521. if(p)
  522. FreeDebugMem(p);
  523. }
  524. */
  525. //+----------------------------------------------------------------------------
  526. //
  527. // Function: EndDebugMemory
  528. //
  529. // Synopsis: Called before the program exits. Report any unreleased memory leak
  530. //
  531. // Arguments: None
  532. //
  533. // Returns: Nothing
  534. //
  535. // History: fengsun Created Header 4/2/98
  536. //
  537. //+----------------------------------------------------------------------------
  538. void EndDebugMemory()
  539. {
  540. if(head.pNext != NULL || nTotalMem!=0 || nTotalBlock !=0)
  541. {
  542. CMTRACE("Detected memory leaks");
  543. TMemoryBlock * pBlock;
  544. for(pBlock = head.pNext; pBlock != NULL; pBlock = pBlock->pNext)
  545. {
  546. TCHAR buf[1024];
  547. wsprintf(buf, TEXT("Memory Leak of %d bytes:\n%S"), pBlock->size, pBlock->pbData());
  548. MyDbgAssertA(pBlock->lpFileName, pBlock->nLine, buf); // do not print the file name
  549. }
  550. DeleteCriticalSection(&cSection);
  551. }
  552. }
  553. #else // defined(DEBUG) && defined(DEBUG_MEM)
  554. //////////////////////////////////////////////////////////////////////////////////
  555. //
  556. // If DEBUG_MEM if NOT defined, only track a count of memory for debug version
  557. //
  558. ///////////////////////////////////////////////////////////////////////////////////
  559. #ifdef DEBUG
  560. void TraceHeapBlock(PROCESS_HEAP_ENTRY* pheEntry)
  561. {
  562. CMTRACE(TEXT("TraceHeapBlock -- Begin Entry Trace"));
  563. CMTRACE1(TEXT("\tEntry->lpData = 0x%x"), pheEntry->lpData);
  564. CMTRACE1(TEXT("\tEntry->cbData = %u"), pheEntry->cbData);
  565. CMTRACE1(TEXT("\tEntry->cbOverhead = %u"), pheEntry->cbOverhead);
  566. CMTRACE1(TEXT("\tEntry->iRegionIndex = %u"), pheEntry->iRegionIndex);
  567. if (pheEntry->wFlags & PROCESS_HEAP_REGION)
  568. {
  569. CMTRACE1(TEXT("\tEntry->dwCommittedSize = %u"), pheEntry->Region.dwCommittedSize);
  570. CMTRACE1(TEXT("\tEntry->dwUnCommittedSize = %u"), pheEntry->Region.dwUnCommittedSize);
  571. CMTRACE1(TEXT("\tEntry->lpFirstBlock = 0x%x"), pheEntry->Region.lpFirstBlock);
  572. CMTRACE1(TEXT("\tEntry->lpLastBlock = 0x%x"), pheEntry->Region.lpLastBlock);
  573. CMTRACE(TEXT("\tPROCESS_HEAP_REGION flag set."));
  574. }
  575. if (pheEntry->wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE)
  576. {
  577. CMTRACE(TEXT("\tPROCESS_HEAP_UNCOMMITTED_RANGE flag set."));
  578. }
  579. if ((pheEntry->wFlags & PROCESS_HEAP_ENTRY_BUSY) && (pheEntry->wFlags & PROCESS_HEAP_ENTRY_MOVEABLE))
  580. {
  581. CMTRACE1(TEXT("\tEntry->hMem = 0x%x"), pheEntry->Block.hMem);
  582. CMTRACE1(TEXT("\tEntry->dwReserved = %u"), pheEntry->Block.dwReserved);
  583. CMTRACE(TEXT("\tPROCESS_HEAP_ENTRY_BUSY and PROCESS_HEAP_ENTRY_MOVEABLE flags are set."));
  584. }
  585. if ((pheEntry->wFlags & PROCESS_HEAP_ENTRY_BUSY) && (pheEntry->wFlags & PROCESS_HEAP_ENTRY_DDESHARE))
  586. {
  587. CMTRACE(TEXT("\tPROCESS_HEAP_ENTRY_BUSY and PROCESS_HEAP_ENTRY_DDESHARE flags are set."));
  588. }
  589. CMTRACE(TEXT("TraceHeapBlock -- End Entry Trace"));
  590. CMTRACE(TEXT(""));
  591. }
  592. BOOL CheckProcessHeap()
  593. {
  594. BOOL bRet;
  595. DWORD dwError;
  596. PROCESS_HEAP_ENTRY pheEntry;
  597. ZeroMemory(&pheEntry, sizeof(pheEntry));
  598. do
  599. {
  600. bRet = HeapWalk(g_hProcessHeap, &pheEntry);
  601. if (!bRet)
  602. {
  603. dwError = GetLastError();
  604. if (ERROR_NO_MORE_ITEMS != dwError)
  605. {
  606. CMTRACE1(TEXT("HeapWalk returned FALSE, GLE returns %u"), dwError);
  607. }
  608. else
  609. {
  610. TraceHeapBlock(&pheEntry);
  611. }
  612. }
  613. else
  614. {
  615. TraceHeapBlock(&pheEntry);
  616. }
  617. } while(!bRet);
  618. return TRUE;
  619. }
  620. #endif // DEBUG
  621. CMUTILAPI void *CmRealloc(void *pvPtr, size_t nBytes)
  622. {
  623. #ifdef DEBUG
  624. if (OS_NT && !HeapValidate(g_hProcessHeap, 0, NULL))
  625. {
  626. CMTRACE(TEXT("CmRealloc -- HeapValidate Returns FALSE. Checking Process Heap."));
  627. CheckProcessHeap();
  628. }
  629. #endif
  630. void* p = HeapReAlloc(g_hProcessHeap, HEAP_ZERO_MEMORY, pvPtr, nBytes);
  631. #ifdef DEBUG
  632. if (OS_NT && !HeapValidate(g_hProcessHeap, 0, NULL))
  633. {
  634. CMTRACE(TEXT("CmRealloc -- HeapValidate Returns FALSE. Checking Process Heap."));
  635. CheckProcessHeap();
  636. }
  637. CMASSERTMSG(p, TEXT("CmRealloc failed"));
  638. #endif
  639. return p;
  640. }
  641. CMUTILAPI void *CmMalloc(size_t nBytes)
  642. {
  643. #ifdef DEBUG
  644. InterlockedIncrement(&g_lMallocCnt);
  645. MYDBGASSERT(nBytes < 1024*1024); // It should be less than 1 MB
  646. MYDBGASSERT(nBytes > 0); // It should be *something*
  647. if (OS_NT && !HeapValidate(g_hProcessHeap, 0, NULL))
  648. {
  649. CMTRACE(TEXT("CmMalloc -- HeapValidate Returns FALSE. Checking Process Heap."));
  650. CheckProcessHeap();
  651. }
  652. #endif
  653. void* p = HeapAlloc(g_hProcessHeap, HEAP_ZERO_MEMORY, nBytes);
  654. #ifdef DEBUG
  655. if (OS_NT && !HeapValidate(g_hProcessHeap, 0, NULL))
  656. {
  657. CMTRACE(TEXT("CmMalloc -- HeapValidate Returns FALSE. Checking Process Heap."));
  658. CheckProcessHeap();
  659. }
  660. CMASSERTMSG(p, TEXT("CmMalloc failed"));
  661. #endif
  662. return p;
  663. }
  664. CMUTILAPI void CmFree(void *pvPtr)
  665. {
  666. #ifdef DEBUG
  667. if (OS_NT && !HeapValidate(g_hProcessHeap, 0, NULL))
  668. {
  669. CMTRACE(TEXT("CmMalloc -- HeapValidate Returns FALSE. Checking Process Heap."));
  670. CheckProcessHeap();
  671. }
  672. #endif
  673. if (pvPtr)
  674. {
  675. MYVERIFY(HeapFree(g_hProcessHeap, 0, pvPtr));
  676. #ifdef DEBUG
  677. if (OS_NT && !HeapValidate(g_hProcessHeap, 0, NULL))
  678. {
  679. CMTRACE(TEXT("CmMalloc -- HeapValidate Returns FALSE. Checking Process Heap."));
  680. CheckProcessHeap();
  681. }
  682. InterlockedDecrement(&g_lMallocCnt);
  683. #endif
  684. }
  685. }
  686. #ifdef DEBUG
  687. void EndDebugMemory()
  688. {
  689. if (g_lMallocCnt)
  690. {
  691. char buf[256];
  692. wsprintfA(buf, TEXT("Detect Memory Leak of %d blocks"), g_lMallocCnt);
  693. CMASSERTMSGA(FALSE, buf);
  694. }
  695. }
  696. #endif
  697. #endif
  698. //
  699. // the memory functions are for i386 only.
  700. //
  701. #ifdef _M_IX86
  702. //+----------------------------------------------------------------------------
  703. //
  704. // memmove - Copy source buffer to destination buffer. The code is copied from
  705. // libc.
  706. //
  707. // Purpose:
  708. // memmove() copies a source memory buffer to a destination memory buffer.
  709. // This routine recognize overlapping buffers to avoid propogation.
  710. // For cases where propogation is not a problem, memcpy() can be used.
  711. //
  712. // Entry:
  713. // void *dst = pointer to destination buffer
  714. // const void *src = pointer to source buffer
  715. // size_t count = number of bytes to copy
  716. //
  717. // Exit:
  718. // Returns a pointer to the destination buffer
  719. //
  720. //+----------------------------------------------------------------------------
  721. CMUTILAPI PVOID WINAPI CmMoveMemory(
  722. PVOID dst,
  723. CONST PVOID src,
  724. size_t count
  725. )
  726. {
  727. void * ret = dst;
  728. PVOID src1 = src;
  729. if (dst <= src1 || (char *)dst >= ((char *)src1 + count)) {
  730. /*
  731. * Non-Overlapping Buffers
  732. * copy from lower addresses to higher addresses
  733. */
  734. while (count--) {
  735. *(char *)dst = *(char *)src1;
  736. dst = (char *)dst + 1;
  737. src1 = (char *)src1 + 1;
  738. }
  739. }
  740. else {
  741. /*
  742. * Overlapping Buffers
  743. * copy from higher addresses to lower addresses
  744. */
  745. dst = (char *)dst + count - 1;
  746. src1 = (char *)src1 + count - 1;
  747. while (count--) {
  748. *(char *)dst = *(char *)src1;
  749. dst = (char *)dst - 1;
  750. src1 = (char *)src1 - 1;
  751. }
  752. }
  753. return(ret);
  754. }
  755. #endif //_M_IX86