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.

455 lines
9.7 KiB

  1. //
  2. // File: memory.cpp
  3. //
  4. // Debug memory tracking per-module
  5. #include "precomp.h"
  6. static BOOL s_fZeroInit = FALSE;
  7. #if defined(DEBUG)
  8. #define DBG_NAME_LENGTH 16
  9. typedef struct tagMemTag
  10. {
  11. DWORD dwSignature;
  12. BOOL fActive;
  13. LPVOID callerAddress;
  14. CHAR szFileName[DBG_NAME_LENGTH];
  15. UINT nLineNumber;
  16. UINT cbSize;
  17. struct tagMemTag *next;
  18. }
  19. MEM_TAG;
  20. static MEM_TAG *s_pDbgActiveMemPool = NULL;
  21. #define CLEAN_BYTE ((BYTE) 0xCD)
  22. static UINT s_cDbgActiveMemAlloc = 0;
  23. static UINT s_cbDbgActiveMem = 0;
  24. const DWORD MEM_TAG_SIGNATURE = 0x12345678UL;
  25. static CRITICAL_SECTION s_DbgCritSect;
  26. static char s_szDbgModuleName[DBG_NAME_LENGTH] = { 0 };
  27. static void _GetFileName(LPSTR pszTarget, LPSTR pszSrc);
  28. static void _DbgGetFileLine(LPSTR *, UINT *);
  29. #define DBG_MEM_TRACK_DUMP_ALL ((UINT) -1)
  30. //
  31. // DbgMemTrackReverseList()
  32. //
  33. void WINAPI DbgMemTrackReverseList(void)
  34. {
  35. EnterCriticalSection(&s_DbgCritSect);
  36. if (NULL != s_pDbgActiveMemPool && NULL != s_pDbgActiveMemPool->next)
  37. {
  38. MEM_TAG *p, *q, *r;;
  39. for (q = (p = s_pDbgActiveMemPool)->next, r = q; // make sure r is not null in the beginning
  40. NULL != r;
  41. p = q, q = r)
  42. {
  43. r = q->next;
  44. q->next = p;
  45. }
  46. s_pDbgActiveMemPool->next = NULL;
  47. s_pDbgActiveMemPool = p;
  48. }
  49. LeaveCriticalSection(&s_DbgCritSect);
  50. }
  51. //
  52. // DbgMemTrackDumpCurrent()
  53. //
  54. void WINAPI DbgMemTrackDumpCurrent(void)
  55. {
  56. MEM_TAG *p;
  57. int i;
  58. char szBuf[128];
  59. EnterCriticalSection(&s_DbgCritSect);
  60. for (p = s_pDbgActiveMemPool, i = 0; p; p = p->next, i++)
  61. {
  62. if (p->callerAddress)
  63. {
  64. // No file/line, just caller
  65. wsprintfA(szBuf, "%s: mem leak [%u]: caller address=0x%p, size=%u, ptr=0x%p\r\n",
  66. s_szDbgModuleName, i,
  67. p->callerAddress, p->cbSize, (p+1));
  68. }
  69. else
  70. {
  71. // File & line number
  72. wsprintfA(szBuf, "%s: mem leak [%u]: file=%s, line=%u, size=%u, ptr=0x%p\r\n",
  73. s_szDbgModuleName, i,
  74. p->szFileName, p->nLineNumber, p->cbSize, (p+1));
  75. }
  76. OutputDebugStringA(szBuf);
  77. }
  78. LeaveCriticalSection(&s_DbgCritSect);
  79. }
  80. //
  81. // DbgMemTrackFinalCheck()
  82. //
  83. // Dumps any left-around (leaked) memory blocks. Call this on
  84. // DLL_PROCESS_DETACH from your .DLL or at the end of WinMain of your .EXE
  85. //
  86. void WINAPI DbgMemTrackFinalCheck(void)
  87. {
  88. DbgMemTrackReverseList();
  89. DbgMemTrackDumpCurrent();
  90. if (NULL != s_pDbgActiveMemPool ||
  91. NULL != s_cDbgActiveMemAlloc ||
  92. NULL != s_cbDbgActiveMem)
  93. {
  94. DebugBreak();
  95. }
  96. DeleteCriticalSection(&s_DbgCritSect);
  97. }
  98. //
  99. // _GetFileName()
  100. //
  101. static void _GetFileName(LPSTR pszTarget, LPSTR pszSrc)
  102. {
  103. LPSTR psz = pszSrc;
  104. while (*psz != '\0')
  105. {
  106. if (*psz++ == '\\')
  107. {
  108. pszSrc = psz;
  109. }
  110. }
  111. lstrcpynA(pszTarget, pszSrc, DBG_NAME_LENGTH);
  112. }
  113. //
  114. // DbgMemAlloc()
  115. //
  116. // Debug memory allocation
  117. //
  118. LPVOID WINAPI DbgMemAlloc
  119. (
  120. UINT cbSize,
  121. LPVOID callerAddress,
  122. LPSTR pszFileName,
  123. UINT nLineNumber
  124. )
  125. {
  126. MEM_TAG *p;
  127. UINT cbToAlloc;
  128. cbToAlloc = sizeof(MEM_TAG) + cbSize;
  129. EnterCriticalSection(&s_DbgCritSect);
  130. p = (MEM_TAG *) LocalAlloc(LPTR, cbToAlloc);
  131. if (p != NULL)
  132. {
  133. p->dwSignature = MEM_TAG_SIGNATURE;
  134. p->fActive = TRUE;
  135. p->callerAddress = callerAddress;
  136. if (pszFileName)
  137. {
  138. _GetFileName(p->szFileName, pszFileName);
  139. p->nLineNumber = nLineNumber;
  140. }
  141. p->cbSize = cbSize;
  142. p->next = s_pDbgActiveMemPool;
  143. s_pDbgActiveMemPool = p;
  144. s_cDbgActiveMemAlloc++;
  145. s_cbDbgActiveMem += p->cbSize;
  146. p++;
  147. //
  148. // If no zero-init, fill with clean byte
  149. //
  150. if (!s_fZeroInit)
  151. {
  152. FillMemory(p, cbSize, CLEAN_BYTE);
  153. }
  154. }
  155. LeaveCriticalSection(&s_DbgCritSect);
  156. return (LPVOID) p;
  157. }
  158. //
  159. // DbgMemFree()
  160. //
  161. // Debug memory free
  162. //
  163. void WINAPI DbgMemFree(LPVOID ptr)
  164. {
  165. if (ptr != NULL)
  166. {
  167. MEM_TAG *p = (MEM_TAG *) ptr;
  168. p--;
  169. if (! IsBadWritePtr(p, sizeof(MEM_TAG)) &&
  170. (p->dwSignature == MEM_TAG_SIGNATURE))
  171. {
  172. if (! p->fActive)
  173. {
  174. //
  175. // This memory has been freed already.
  176. //
  177. ERROR_OUT(("DbgMemFree called with invalid pointer 0x%08x", p));
  178. return;
  179. }
  180. MEM_TAG *q, *q0;
  181. EnterCriticalSection(&s_DbgCritSect);
  182. for (q = s_pDbgActiveMemPool; q != NULL; q = (q0 = q)->next)
  183. {
  184. if (q == p)
  185. {
  186. if (q == s_pDbgActiveMemPool)
  187. {
  188. s_pDbgActiveMemPool = p->next;
  189. }
  190. else
  191. {
  192. q0->next = p->next;
  193. }
  194. s_cDbgActiveMemAlloc--;
  195. s_cbDbgActiveMem -= p->cbSize;
  196. p->fActive = FALSE;
  197. //
  198. // Fill app pointer data with CLEAN_BYTE, to see if
  199. // anybody tries later to access it after it's been
  200. // freed.
  201. //
  202. FillMemory(p+1, p->cbSize, CLEAN_BYTE);
  203. break;
  204. }
  205. }
  206. LeaveCriticalSection(&s_DbgCritSect);
  207. }
  208. else
  209. {
  210. ERROR_OUT(("DbgMemFree called with invalid pointer 0x%08x", p));
  211. return;
  212. }
  213. LocalFree(p);
  214. }
  215. }
  216. //
  217. // DbgMemReAlloc()
  218. //
  219. // Debug memory reallocate
  220. //
  221. LPVOID WINAPI DbgMemReAlloc(LPVOID ptr, UINT cbSize, UINT uFlags, LPSTR pszFileName, UINT nLineNumber)
  222. {
  223. MEM_TAG *p;
  224. void *q;
  225. if (ptr == NULL)
  226. return DbgMemAlloc(cbSize, 0, pszFileName, nLineNumber);
  227. p = (MEM_TAG *) ptr;
  228. p--;
  229. if (IsBadWritePtr(p, sizeof(MEM_TAG)) ||
  230. p->dwSignature != MEM_TAG_SIGNATURE)
  231. {
  232. DebugBreak();
  233. return LocalReAlloc(ptr, cbSize, uFlags);
  234. }
  235. q = DbgMemAlloc(cbSize, 0, pszFileName, nLineNumber);
  236. if (q != NULL)
  237. {
  238. CopyMemory(q, ptr, p->cbSize);
  239. DbgMemFree(ptr);
  240. }
  241. return q;
  242. }
  243. typedef struct
  244. {
  245. DWORD dwThreadID;
  246. LPSTR pszFileName;
  247. UINT nLineNumber;
  248. }
  249. DBG_THREAD_FILE_LINE;
  250. #define DBG_MAX_THREADS 32
  251. static DBG_THREAD_FILE_LINE s_aThreadFileLine[DBG_MAX_THREADS] = { 0 };
  252. void WINAPI DbgSaveFileLine(LPSTR pszFileName, UINT nLineNumber)
  253. {
  254. DWORD dwThreadID = GetCurrentThreadId();
  255. EnterCriticalSection(&s_DbgCritSect);
  256. UINT c = DBG_MAX_THREADS;
  257. DBG_THREAD_FILE_LINE *p;
  258. for (p = s_aThreadFileLine; c--; p++)
  259. {
  260. if (p->dwThreadID == 0)
  261. {
  262. p->dwThreadID = dwThreadID;
  263. p->pszFileName = pszFileName;
  264. p->nLineNumber = nLineNumber;
  265. break;
  266. }
  267. else
  268. if (p->dwThreadID == dwThreadID)
  269. {
  270. p->pszFileName = pszFileName;
  271. p->nLineNumber = nLineNumber;
  272. break;
  273. }
  274. }
  275. LeaveCriticalSection(&s_DbgCritSect);
  276. }
  277. void WINAPI DbgGetFileLine(LPSTR *ppszFileName, UINT *pnLineNumber)
  278. {
  279. *ppszFileName = NULL;
  280. *pnLineNumber = 0;
  281. DWORD dwThreadID = GetCurrentThreadId();
  282. EnterCriticalSection(&s_DbgCritSect);
  283. UINT c = DBG_MAX_THREADS;
  284. DBG_THREAD_FILE_LINE *p;
  285. for (p = s_aThreadFileLine; c--; p++)
  286. {
  287. if (p->dwThreadID == 0)
  288. {
  289. break;
  290. }
  291. else if (p->dwThreadID == dwThreadID)
  292. {
  293. *ppszFileName = p->pszFileName;
  294. *pnLineNumber = p->nLineNumber;
  295. p->pszFileName = NULL;
  296. p->nLineNumber = 0;
  297. break;
  298. }
  299. }
  300. LeaveCriticalSection(&s_DbgCritSect);
  301. }
  302. LPVOID __cdecl ::operator new(size_t uObjSize)
  303. {
  304. LPVOID callerAddress;
  305. LPSTR pszFileName;
  306. UINT nLineNumber;
  307. DbgGetFileLine(&pszFileName, &nLineNumber);
  308. if (pszFileName)
  309. {
  310. callerAddress = NULL;
  311. }
  312. else
  313. {
  314. #ifdef _X86_
  315. LPVOID * lpParams;
  316. //
  317. // LAURABU HACK: This doesn't work for alpha. But it's not bad
  318. // for normal debugging. We're going to grab the return address
  319. // of whomever called new()
  320. //
  321. lpParams = (LPVOID *)&uObjSize;
  322. callerAddress = *(lpParams - 1);
  323. #else
  324. callerAddress = NULL;
  325. #endif // _X86_
  326. }
  327. return(DbgMemAlloc(uObjSize, callerAddress, pszFileName, nLineNumber));
  328. }
  329. #else // RETAIL
  330. LPVOID __cdecl ::operator new(size_t uObjSize)
  331. {
  332. if (s_fZeroInit)
  333. {
  334. return(LocalAlloc(LPTR, uObjSize));
  335. }
  336. else
  337. {
  338. return(LocalAlloc(LMEM_FIXED, uObjSize));
  339. }
  340. }
  341. #endif // defined(DEBUG)
  342. //
  343. // delete() is the same for both debug and retail
  344. //
  345. void __cdecl ::operator delete(LPVOID pObj)
  346. {
  347. MemFree(pObj);
  348. }
  349. //
  350. // DbgInitMemTrack()
  351. //
  352. // Initialize debug memory tracking. Call this on DLL_PROCESS_ATTACH in
  353. // your .DLL or at beginning of WinMain of your .EXE
  354. //
  355. void WINAPI DbgInitMemTrack(HINSTANCE hDllInst, BOOL fZeroInit)
  356. {
  357. s_fZeroInit = fZeroInit;
  358. #if defined(DEBUG)
  359. InitializeCriticalSection(&s_DbgCritSect);
  360. char szPath[MAX_PATH];
  361. if (0 != GetModuleFileNameA(hDllInst, szPath, MAX_PATH))
  362. {
  363. _GetFileName(s_szDbgModuleName, szPath);
  364. LPSTR psz = s_szDbgModuleName;
  365. while (*psz != '\0')
  366. {
  367. if (*psz == '.')
  368. {
  369. *psz = '\0';
  370. break;
  371. }
  372. psz++;
  373. }
  374. }
  375. else
  376. {
  377. lstrcpyA(s_szDbgModuleName, "unknown");
  378. }
  379. #endif // DEBUG
  380. }
  381.