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.

676 lines
17 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: mem.cpp
  4. //
  5. // Module: common
  6. //
  7. // Synopsis: Basic memory manipulation routines
  8. //
  9. // Copyright (C) 1997-1998 Microsoft Corporation. All rights reserved.
  10. //
  11. // Author: fengsun
  12. //
  13. // Created 9/24/98
  14. //
  15. //+----------------------------------------------------------------------------
  16. //
  17. // Always use ANSI code
  18. //
  19. #ifdef UNICODE
  20. #undef UNICODE
  21. #endif
  22. //
  23. // for mem.h
  24. // somehow, new and delete functions are not inlined and cause link problem, not sure why
  25. //
  26. #define NO_INLINE_NEW
  27. #include <windows.h>
  28. #include "mem.h"
  29. #include "debug.h"
  30. #if !defined(DEBUG_MEM)
  31. //////////////////////////////////////////////////////////////////////////////////
  32. //
  33. // If DEBUG_MEM if NOT defined, only track a count of memory leaks for debug version
  34. //
  35. ///////////////////////////////////////////////////////////////////////////////////
  36. #ifdef _DEBUG
  37. static LONG g_lMallocCnt = 0; // a counter to detect memory leak
  38. #endif
  39. void *SaRealloc(void *pvPtr, size_t nBytes)
  40. {
  41. void* pMem = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY|HEAP_GENERATE_EXCEPTIONS, pvPtr, nBytes);
  42. ASSERT(pMem != NULL);
  43. return pMem;
  44. }
  45. void *SaAlloc(size_t nBytes)
  46. {
  47. #ifdef _DEBUG
  48. InterlockedIncrement(&g_lMallocCnt);
  49. #endif
  50. ASSERT(nBytes < 1024*1024); // It should be less than 1 MB
  51. void* pMem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY|HEAP_GENERATE_EXCEPTIONS, nBytes);
  52. ASSERT(pMem != NULL);
  53. return pMem;
  54. }
  55. void SaFree(void *pvPtr)
  56. {
  57. if (pvPtr)
  58. {
  59. VERIFY(HeapFree(GetProcessHeap(), 0, pvPtr));
  60. #ifdef _DEBUG
  61. InterlockedDecrement(&g_lMallocCnt);
  62. #endif
  63. }
  64. }
  65. #ifdef _DEBUG
  66. void EndDebugMemory()
  67. {
  68. if (g_lMallocCnt)
  69. {
  70. TCHAR buf[256];
  71. wsprintf(buf, TEXT("Detect Memory Leak of %d blocks"),g_lMallocCnt);
  72. AssertMessage(TEXT(__FILE__),__LINE__,buf);
  73. }
  74. }
  75. #endif
  76. #else // DEBUG_MEM
  77. //////////////////////////////////////////////////////////////////////////////////
  78. //
  79. // If DEBUG_MEM if defined, track all the memory alloction in debug version.
  80. // Keep all the allocated memory blocks in the double link list.
  81. // Record the file name and line #, where memory is allocated.
  82. // Add extra tag at the beginning and end of the memory to watch for overwriten
  83. // The whole list is checked against corruption for every alloc/free operation
  84. //
  85. // The folowing three function is exported:
  86. // BOOL CheckDebugMem(void); // return TRUE for succeed
  87. // void* AllocDebugMem(long size,const char* lpFileName,int nLine);
  88. // BOOL FreeDebugMem(void* pMem); // return TRUE for succeed
  89. //
  90. ///////////////////////////////////////////////////////////////////////////////////
  91. //#undef new
  92. #define MEMTAG 0xBEEDB77D // the tag before/after the block to watch for overwriten
  93. #define FREETAG 0xBD // the flag to fill freed memory
  94. #define TAGSIZE (sizeof(long))// Size of the tags appended to the end of the block
  95. //
  96. // memory block, a double link list
  97. //
  98. struct TMemoryBlock
  99. {
  100. TMemoryBlock* pPrev;
  101. TMemoryBlock* pNext;
  102. long size;
  103. const char* lpFileName; // The filename
  104. int nLine; // The line number
  105. long topTag; // The watch tag at the beginning
  106. // followed by:
  107. // BYTE data[nDataSize];
  108. // long bottomTag;
  109. BYTE* pbData() const // Return the pointer to the actual data
  110. { return (BYTE*) (this + 1); }
  111. };
  112. //
  113. // The following internal function can be overwritten to change the behaivor
  114. //
  115. static void* MemAlloc(long size);
  116. static BOOL MemFree(void* pMem);
  117. static void LockDebugMem();
  118. static void UnlockDebugMem();
  119. //
  120. // Internal function
  121. //
  122. static BOOL RealCheckMemory(); // without call Enter/Leave critical Section
  123. static BOOL CheckBlock(const TMemoryBlock* pBlock) ;
  124. //
  125. // Internal data, protected by the lock to be multi-thread safe
  126. //
  127. static long nTotalMem; // Total bytes of memory allocated
  128. static long nTotalBlock; // Total # of blocks allocated
  129. static TMemoryBlock head; // The head of the double link list
  130. //
  131. // critical section to lock \ unlock DebugMemory
  132. // The constructor lock the memory, the destructor unlock the memory
  133. //
  134. class MemCriticalSection
  135. {
  136. public:
  137. MemCriticalSection()
  138. {
  139. LockDebugMem();
  140. }
  141. ~MemCriticalSection()
  142. {
  143. UnlockDebugMem();
  144. }
  145. };
  146. static BOOL fDebugMemInited = FALSE; // whether the debug memory is initialized
  147. //+----------------------------------------------------------------------------
  148. //
  149. // Function: StartDebugMemory
  150. //
  151. // Synopsis: Initialize the data for debug memory
  152. //
  153. // Arguments: None
  154. //
  155. // Returns:
  156. //
  157. // History: fengsun Created Header 4/2/98
  158. //
  159. //+----------------------------------------------------------------------------
  160. static void StartDebugMemory()
  161. {
  162. fDebugMemInited = TRUE;
  163. head.pNext = head.pPrev = NULL;
  164. head.topTag = MEMTAG;
  165. head.size = 0;
  166. nTotalMem = 0;
  167. nTotalBlock = 0;
  168. }
  169. //+----------------------------------------------------------------------------
  170. //
  171. // Function: MemAlloc
  172. //
  173. // Synopsis: Allocate a block of memory. This function should be overwriten
  174. // if different allocation method is used
  175. //
  176. // Arguments: long size - size of the memory
  177. //
  178. // Returns: void* - the memory allocated or NULL
  179. //
  180. // History: fengsun Created Header 4/2/98
  181. //
  182. //+----------------------------------------------------------------------------
  183. static void* MemAlloc(long size)
  184. {
  185. return (HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY|HEAP_GENERATE_EXCEPTIONS, size));
  186. }
  187. //+----------------------------------------------------------------------------
  188. //
  189. // Function: MemFree
  190. //
  191. // Synopsis: Free a block of memory. This function should be overwriten
  192. // if different allocation method is used
  193. //
  194. // Arguments: void* pMem - The memory to be freed
  195. //
  196. // Returns: static BOOL - TRUE if succeeded
  197. //
  198. // History: Created Header 4/2/98
  199. //
  200. //+----------------------------------------------------------------------------
  201. static BOOL MemFree(void* pMem)
  202. {
  203. return HeapFree(GetProcessHeap(), 0, pMem);
  204. }
  205. //
  206. // Data / functions to provide mutual exclusion.
  207. // Can be overwritten, if other methed is to be used.
  208. //
  209. static BOOL fLockInited = FALSE; // whether the critical section is inialized
  210. static CRITICAL_SECTION cSection; // The critical section to protect the link list
  211. static void InitLock()
  212. {
  213. fLockInited = TRUE;
  214. InitializeCriticalSection(&cSection);
  215. }
  216. static void LockDebugMem()
  217. {
  218. static int i = 0;
  219. if(!fLockInited)
  220. InitLock();
  221. EnterCriticalSection(&cSection);
  222. }
  223. static void UnlockDebugMem()
  224. {
  225. LeaveCriticalSection(&cSection);
  226. }
  227. //+----------------------------------------------------------------------------
  228. //
  229. // Function: AllocDebugMem
  230. //
  231. // Synopsis: Process memory allocation request.
  232. // Check the link list. Allocate a larger block.
  233. // Record filename/linenumber, add tags and insert to the list
  234. //
  235. // Arguments: long size - Size of the memory to be allocated
  236. // const char* lpFileName - File name to be recorded
  237. // int nLine - Line number to be recorted
  238. //
  239. // Returns: void* - The memory allocated. Ready to use by the caller
  240. //
  241. // History: fengsun Created Header 4/2/98
  242. //
  243. //+----------------------------------------------------------------------------
  244. void* AllocDebugMem(long size,const char* lpFileName,int nLine)
  245. {
  246. if(!fDebugMemInited)
  247. {
  248. StartDebugMemory();
  249. }
  250. if(size<0)
  251. {
  252. ASSERTMSG(FALSE,TEXT("Negtive size for alloc"));
  253. return NULL;
  254. }
  255. if(size>1024*1024)
  256. {
  257. ASSERTMSG(FALSE, TEXT("Size for alloc is great than 1Mb"));
  258. return NULL;
  259. }
  260. if(size == 0)
  261. {
  262. TRACE(TEXT("Allocate memory of size 0"));
  263. return NULL;
  264. }
  265. //
  266. // Protect the access to the list
  267. //
  268. MemCriticalSection criticalSection;
  269. //
  270. // Check the link list first
  271. //
  272. if(!RealCheckMemory())
  273. {
  274. return NULL;
  275. }
  276. //
  277. // Allocate a large block to hold additional information
  278. //
  279. TMemoryBlock* pBlock = (TMemoryBlock*)MemAlloc(sizeof(TMemoryBlock)+size + TAGSIZE);
  280. if(!pBlock)
  281. {
  282. TRACE(TEXT("Outof Memory"));
  283. return NULL;
  284. }
  285. //
  286. // record filename/line/size, add tag to the beginning and end
  287. //
  288. pBlock->size = size;
  289. pBlock->topTag = MEMTAG;
  290. if (lpFileName)
  291. {
  292. pBlock->lpFileName = lpFileName;
  293. }
  294. else
  295. {
  296. pBlock->lpFileName = TEXT("");
  297. }
  298. pBlock->nLine = nLine;
  299. *(long*)(pBlock->pbData() + size) = MEMTAG;
  300. //
  301. // insert at head
  302. //
  303. pBlock->pNext = head.pNext;
  304. pBlock->pPrev = &head;
  305. if(head.pNext)
  306. head.pNext->pPrev = pBlock;
  307. head.pNext = pBlock;
  308. nTotalMem += size;
  309. nTotalBlock ++;
  310. return pBlock->pbData();
  311. }
  312. //+----------------------------------------------------------------------------
  313. //
  314. // Function: FreeDebugMem
  315. //
  316. // Synopsis: Free the memory allocated by AllocDebugMem
  317. // Check the link list, and the block to be freed.
  318. // Fill the block data with FREETAG before freed
  319. //
  320. // Arguments: void* pMem - Memory to be freed
  321. //
  322. // Returns: BOOL - TRUE for succeeded
  323. //
  324. // History: fengsun Created Header 4/2/98
  325. //
  326. //+----------------------------------------------------------------------------
  327. BOOL FreeDebugMem(void* pMem)
  328. {
  329. if(!fDebugMemInited)
  330. {
  331. StartDebugMemory();
  332. }
  333. if(!pMem)
  334. {
  335. return FALSE;
  336. }
  337. //
  338. // Get the lock
  339. //
  340. MemCriticalSection criticalSection;
  341. //
  342. // Get pointer to our structure
  343. //
  344. TMemoryBlock* pBlock =(TMemoryBlock*)( (char*)pMem - sizeof(TMemoryBlock));
  345. //
  346. // Check the block to be freed
  347. //
  348. if(!CheckBlock(pBlock))
  349. {
  350. ASSERTMSG(FALSE, TEXT("The memory to be freed is either corrupted or not allocated by us"));
  351. return FALSE;
  352. }
  353. //
  354. // Check the link list
  355. //
  356. if(!RealCheckMemory())
  357. {
  358. return FALSE;
  359. }
  360. //
  361. // remove the block from the list
  362. //
  363. pBlock->pPrev->pNext = pBlock->pNext;
  364. if(pBlock->pNext)
  365. {
  366. pBlock->pNext->pPrev = pBlock->pPrev;
  367. }
  368. nTotalMem -= pBlock->size;
  369. nTotalBlock --;
  370. //
  371. // Fill the freed memory with 0xBD, leave the size/filename/lineNumber unchanged
  372. //
  373. memset(&pBlock->topTag,FREETAG,(size_t)pBlock->size + sizeof(pBlock->topTag)+ TAGSIZE);
  374. return MemFree(pBlock);
  375. }
  376. //+----------------------------------------------------------------------------
  377. //
  378. // Function: void* ReAllocDebugMem
  379. //
  380. // Synopsis: Reallocate a memory with a diffirent size
  381. //
  382. // Arguments: void* pMem - memory to be reallocated
  383. // long nSize - size of the request
  384. // const char* lpFileName - FileName to be recorded
  385. // int nLine - Line umber to be recorded
  386. //
  387. // Returns: void* - new memory returned
  388. //
  389. // History: fengsun Created Header 4/2/98
  390. //
  391. //+----------------------------------------------------------------------------
  392. void* ReAllocDebugMem(void* pMem, long nSize, const char* lpFileName,int nLine)
  393. {
  394. if(!fDebugMemInited)
  395. StartDebugMemory();
  396. if(!pMem)
  397. {
  398. return NULL;
  399. }
  400. //
  401. // Allocate a new block, copy the information over and free the old block.
  402. //
  403. TMemoryBlock* pBlock =(TMemoryBlock*)( (char*)pMem - sizeof(TMemoryBlock));
  404. DWORD dwOrginalSize = pBlock->size;
  405. void* pNew = AllocDebugMem(nSize, lpFileName, nLine);
  406. if(pNew)
  407. {
  408. CopyMemory(pNew, pMem, ((DWORD)nSize < dwOrginalSize ? nSize : dwOrginalSize));
  409. FreeDebugMem(pMem);
  410. }
  411. return pNew;
  412. }
  413. //+----------------------------------------------------------------------------
  414. //
  415. // Function: CheckDebugMem
  416. //
  417. // Synopsis: Exported to external module.
  418. // Call this function, whenever, you want to check against
  419. // memory curruption
  420. //
  421. // Arguments: None
  422. //
  423. // Returns: BOOL - TRUE if the memory is fine.
  424. //
  425. // History: fengsun Created Header 4/2/98
  426. //
  427. //+----------------------------------------------------------------------------
  428. BOOL CheckDebugMem()
  429. {
  430. if(!fDebugMemInited)
  431. StartDebugMemory();
  432. MemCriticalSection criticalSection;
  433. return RealCheckMemory();
  434. }
  435. //+----------------------------------------------------------------------------
  436. //
  437. // Function: RealCheckMemory
  438. //
  439. // Synopsis: Go through the link list to check for memory corruption
  440. //
  441. // Arguments: None
  442. //
  443. // Returns: BOOL - TRUE if the memory is fine.
  444. //
  445. // History: fengsun Created Header 4/2/98
  446. //
  447. //+----------------------------------------------------------------------------
  448. static BOOL RealCheckMemory()
  449. {
  450. TMemoryBlock* pBlock = head.pNext;
  451. int nBlock =0;
  452. while(pBlock!=NULL)
  453. {
  454. if(!CheckBlock(pBlock))
  455. {
  456. return FALSE;
  457. }
  458. pBlock = pBlock->pNext;
  459. nBlock++;
  460. }
  461. if(nBlock != nTotalBlock)
  462. {
  463. ASSERTMSG(FALSE,TEXT("Memery corrupted"));
  464. return FALSE;
  465. }
  466. return TRUE;
  467. }
  468. //+----------------------------------------------------------------------------
  469. //
  470. // Function: CheckBlock
  471. //
  472. // Synopsis: Check a block for memory corruption
  473. //
  474. // Arguments: const TMemoryBlock* pBlock -
  475. //
  476. // Returns: BOOL - TRUE, if the block is fine
  477. //
  478. // History: fengsun Created Header 4/2/98
  479. //
  480. //+----------------------------------------------------------------------------
  481. static BOOL CheckBlock(const TMemoryBlock* pBlock)
  482. {
  483. if(pBlock->topTag != MEMTAG) // overwriten at top
  484. {
  485. if(pBlock->topTag == (FREETAG | (FREETAG <<8) | (FREETAG <<16) | (FREETAG <<24)))
  486. {
  487. TCHAR buf[1024];
  488. wsprintf(buf,TEXT("Memory in used after freed. Allocated %d bytes:\n%s"),pBlock->size,pBlock->pbData());
  489. AssertMessage(pBlock->lpFileName,pBlock->nLine, buf); // do not print the file name
  490. }
  491. else
  492. {
  493. ASSERTMSG(FALSE, TEXT("Memery overwriten from top"));
  494. }
  495. return FALSE;
  496. }
  497. if(pBlock->size<0)
  498. {
  499. ASSERTMSG(FALSE, TEXT("Memery corrupted"));
  500. return FALSE;
  501. }
  502. if(*(long*)(pBlock->pbData() +pBlock->size) != MEMTAG) // overwriten at bottom
  503. {
  504. TCHAR buf[1024];
  505. wsprintf(buf,TEXT("Memory overwriten. Allocated %d bytes:\n%s"),pBlock->size,pBlock->pbData());
  506. AssertMessage(pBlock->lpFileName,pBlock->nLine, buf); // do not print the file name
  507. // ASSERTMSG(FALSE, TEXT("Memery corrupted"));
  508. return FALSE;
  509. }
  510. if(pBlock->pPrev && pBlock->pPrev->pNext != pBlock)
  511. {
  512. ASSERTMSG(FALSE, TEXT("Memery corrupted"));
  513. return FALSE;
  514. }
  515. if(pBlock->pNext && pBlock->pNext->pPrev != pBlock)
  516. {
  517. ASSERTMSG(FALSE, TEXT("Memery corrupted"));
  518. return FALSE;
  519. }
  520. return TRUE;
  521. }
  522. //+----------------------------------------------------------------------------
  523. //
  524. // Function: EndDebugMemory
  525. //
  526. // Synopsis: Called before the program exits. Report any unreleased memory leak
  527. //
  528. // Arguments: None
  529. //
  530. // Returns: Nothing
  531. //
  532. // History: fengsun Created Header 4/2/98
  533. //
  534. //+----------------------------------------------------------------------------
  535. void EndDebugMemory()
  536. {
  537. if(head.pNext != NULL || nTotalMem!=0 || nTotalBlock !=0)
  538. {
  539. TRACE1(TEXT("Detected memory leaks of %d blocks"), nTotalBlock);
  540. TMemoryBlock * pBlock;
  541. for(pBlock = head.pNext; pBlock != NULL; pBlock = pBlock->pNext)
  542. {
  543. TCHAR buf[256];
  544. wsprintf(buf,TEXT("Memory Leak of %d bytes:\n"),pBlock->size);
  545. TRACE(buf);
  546. AssertMessage(pBlock->lpFileName,pBlock->nLine, buf); // do not print the file name
  547. }
  548. DeleteCriticalSection(&cSection);
  549. }
  550. }
  551. #endif //#else defined(DEBUG_MEM)
  552. #ifdef _DEBUG
  553. //
  554. // Call ExitDebugMem upon exit
  555. //
  556. class ExitDebugMem
  557. {
  558. public:
  559. ~ExitDebugMem()
  560. {EndDebugMemory();}
  561. };
  562. // force initialization early
  563. #pragma warning(disable:4073)
  564. #pragma init_seg(lib)
  565. static ExitDebugMem exitDebugMem;
  566. #endif