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.

494 lines
8.3 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. dbgtrack.c
  5. Abstract:
  6. Allocation tracking implementation. From old debug.c
  7. Author:
  8. Marc R. Whitten (marcw) 09-Sept-1999
  9. Revision History:
  10. --*/
  11. //
  12. // Includes
  13. //
  14. #include "pch.h"
  15. //
  16. // NOTE: No code should appear outside the #ifdef DEBUG
  17. //
  18. #ifdef DEBUG
  19. #pragma message("DEBUG macros enabled")
  20. //
  21. // Strings
  22. //
  23. // None
  24. //
  25. // Constants
  26. //
  27. #define TRACK_BUCKETS 1501
  28. #define BUCKET_ITEMS_PER_POOL 8192
  29. //
  30. // Macros
  31. //
  32. // None
  33. //
  34. // Types
  35. //
  36. typedef UBINT ALLOCATION_ITEM_OFFSET;
  37. typedef struct _tagTRACKBUCKETITEM {
  38. struct _tagTRACKBUCKETITEM *Next;
  39. struct _tagTRACKBUCKETITEM *Prev;
  40. ALLOCTYPE Type;
  41. PVOID Ptr;
  42. ALLOCATION_ITEM_OFFSET ItemOffset;
  43. } TRACKBUCKETITEM, *PTRACKBUCKETITEM;
  44. typedef struct _tagBUCKETPOOL {
  45. UINT Count;
  46. TRACKBUCKETITEM Items[BUCKET_ITEMS_PER_POOL];
  47. } TRACKBUCKETPOOL, *PTRACKBUCKETPOOL;
  48. typedef struct {
  49. ALLOCTYPE Type;
  50. PVOID Ptr;
  51. PCSTR FileName;
  52. UINT Line;
  53. } ALLOCATION_ITEM, *PALLOCATION_ITEM;
  54. //
  55. // Globals
  56. //
  57. PTRACKBUCKETITEM g_TrackBuckets[TRACK_BUCKETS];
  58. PTRACKBUCKETITEM g_TrackPoolDelHead;
  59. PTRACKBUCKETPOOL g_TrackPool;
  60. //
  61. // The following pointer can be used to help identify memory leak sources.
  62. // It is copied to the memory tracking log.
  63. //
  64. PCSTR g_TrackComment;
  65. PCSTR g_TrackFile;
  66. UINT g_TrackLine;
  67. INT g_UseCount;
  68. UINT g_DisableTrackComment = 0;
  69. GROWBUFFER g_AllocationList;
  70. PVOID g_FirstDeletedAlloc;
  71. //
  72. // Macro expansion list
  73. //
  74. // None
  75. //
  76. // Private function prototypes
  77. //
  78. //
  79. // Macro expansion definition
  80. //
  81. // None
  82. //
  83. // Code
  84. //
  85. VOID
  86. DisableTrackComment (
  87. VOID
  88. )
  89. {
  90. g_DisableTrackComment ++;
  91. }
  92. VOID
  93. EnableTrackComment (
  94. VOID
  95. )
  96. {
  97. if (g_DisableTrackComment > 0) {
  98. g_DisableTrackComment --;
  99. }
  100. }
  101. PBYTE
  102. pOurTrackedGbGrow (
  103. IN PGROWBUFFER Buffer,
  104. IN UINT Bytes
  105. )
  106. {
  107. PBYTE p;
  108. BOOL trackMsg = FALSE;
  109. //
  110. // Because grow buffers themselves cause tracking, we have to
  111. // call the untracked version. To eliminate confusion, we
  112. // give a helpful note.
  113. //
  114. if (!g_TrackFile) {
  115. trackMsg = TRUE;
  116. g_TrackFile = TEXT("<allocation tracking in dbgtrack.c, not a real leak>");
  117. g_TrackLine = __LINE__;
  118. }
  119. p = (PSTR) RealGbGrow (Buffer, Bytes);
  120. if (trackMsg) {
  121. g_TrackFile = NULL;
  122. }
  123. return p;
  124. }
  125. INT
  126. TrackPush (
  127. PCSTR Msg,
  128. PCSTR File,
  129. UINT Line
  130. )
  131. {
  132. static CHAR Buffer[1024];
  133. static CHAR FileCopy[1024];
  134. if (g_DisableTrackComment > 0) {
  135. return 0;
  136. }
  137. if (g_UseCount > 0) {
  138. g_UseCount++;
  139. return 0;
  140. }
  141. if (Msg) {
  142. wsprintfA (Buffer, "%s", Msg);
  143. } else {
  144. wsprintfA (Buffer, "%s line %u", File, Line);
  145. }
  146. StringCopyA (FileCopy, File);
  147. g_TrackFile = FileCopy;
  148. g_TrackLine = Line;
  149. g_TrackComment = Buffer;
  150. g_UseCount = 1;
  151. return 0;
  152. }
  153. INT
  154. TrackPop (
  155. VOID
  156. )
  157. {
  158. if (g_DisableTrackComment > 0) {
  159. return 0;
  160. }
  161. g_UseCount--;
  162. if (!g_UseCount) {
  163. g_TrackComment = NULL;
  164. g_TrackFile = NULL;
  165. }
  166. return 0;
  167. }
  168. VOID
  169. InitAllocationTracking (
  170. VOID
  171. )
  172. {
  173. ZeroMemory (&g_AllocationList, sizeof (g_AllocationList));
  174. g_AllocationList.GrowSize = 65536;
  175. g_FirstDeletedAlloc = NULL;
  176. }
  177. VOID
  178. FreeAllocationTracking (
  179. VOID
  180. )
  181. {
  182. UINT Size;
  183. UINT u;
  184. PALLOCATION_ITEM Item;
  185. GROWBUFFER Msg = INIT_GROWBUFFER;
  186. CHAR Text[1024];
  187. PSTR p;
  188. UINT Bytes;
  189. Size = g_AllocationList.End / sizeof (ALLOCATION_ITEM);;
  190. for (u = 0 ; u < Size ; u++) {
  191. Item = (PALLOCATION_ITEM) g_AllocationList.Buf + u;
  192. if (!Item->FileName) {
  193. continue;
  194. }
  195. Bytes = (UINT) wsprintfA (Text, "%s line %u\r\n", Item->FileName, Item->Line);
  196. p = (PSTR) pOurTrackedGbGrow (&Msg, Bytes);
  197. if (p) {
  198. CopyMemory (p, Text, Bytes);
  199. }
  200. }
  201. if (Msg.End) {
  202. p = (PSTR) pOurTrackedGbGrow (&Msg, 1);
  203. if (p) {
  204. *p = 0;
  205. DEBUGMSGA (("Leaks", "%s", Msg.Buf));
  206. }
  207. GbFree (&Msg);
  208. }
  209. GbFree (&g_AllocationList);
  210. g_FirstDeletedAlloc = NULL;
  211. // Intentional leak -- who cares about track memory
  212. g_TrackPoolDelHead = NULL;
  213. g_TrackPool = NULL;
  214. }
  215. PTRACKBUCKETITEM
  216. pAllocTrackBucketItem (
  217. VOID
  218. )
  219. {
  220. PTRACKBUCKETITEM BucketItem;
  221. if (g_TrackPoolDelHead) {
  222. BucketItem = g_TrackPoolDelHead;
  223. g_TrackPoolDelHead = BucketItem->Next;
  224. } else {
  225. if (!g_TrackPool || g_TrackPool->Count == BUCKET_ITEMS_PER_POOL) {
  226. g_TrackPool = (PTRACKBUCKETPOOL) SafeHeapAlloc (g_hHeap, 0, sizeof (TRACKBUCKETPOOL));
  227. if (!g_TrackPool) {
  228. return NULL;
  229. }
  230. g_TrackPool->Count = 0;
  231. }
  232. BucketItem = g_TrackPool->Items + g_TrackPool->Count;
  233. g_TrackPool->Count++;
  234. }
  235. return BucketItem;
  236. }
  237. VOID
  238. pFreeTrackBucketItem (
  239. PTRACKBUCKETITEM BucketItem
  240. )
  241. {
  242. BucketItem->Next = g_TrackPoolDelHead;
  243. g_TrackPoolDelHead = BucketItem;
  244. }
  245. DWORD
  246. pComputeTrackHashVal (
  247. IN ALLOCTYPE Type,
  248. IN PVOID Ptr
  249. )
  250. {
  251. DWORD Hash;
  252. Hash = (DWORD) ((DWORD)Type << 16) ^ (DWORD)(UBINT)Ptr;
  253. return Hash % TRACK_BUCKETS;
  254. }
  255. VOID
  256. pTrackHashTableInsert (
  257. IN PBYTE Base,
  258. IN ALLOCATION_ITEM_OFFSET ItemOffset
  259. )
  260. {
  261. DWORD Hash;
  262. PTRACKBUCKETITEM BucketItem;
  263. PALLOCATION_ITEM Item;
  264. Item = (PALLOCATION_ITEM) (Base + ItemOffset);
  265. Hash = pComputeTrackHashVal (Item->Type, Item->Ptr);
  266. BucketItem = pAllocTrackBucketItem();
  267. if (!BucketItem) {
  268. DEBUGMSG ((DBG_WHOOPS, "pTrackHashTableInsert failed to alloc memory"));
  269. return;
  270. }
  271. BucketItem->Prev = NULL;
  272. BucketItem->Next = g_TrackBuckets[Hash];
  273. BucketItem->Type = Item->Type;
  274. BucketItem->Ptr = Item->Ptr;
  275. BucketItem->ItemOffset = ItemOffset;
  276. if (BucketItem->Next) {
  277. BucketItem->Next->Prev = BucketItem;
  278. }
  279. g_TrackBuckets[Hash] = BucketItem;
  280. }
  281. VOID
  282. pTrackHashTableDelete (
  283. IN PTRACKBUCKETITEM BucketItem
  284. )
  285. {
  286. DWORD Hash;
  287. Hash = pComputeTrackHashVal (BucketItem->Type, BucketItem->Ptr);
  288. if (BucketItem->Prev) {
  289. BucketItem->Prev->Next = BucketItem->Next;
  290. } else {
  291. g_TrackBuckets[Hash] = BucketItem->Next;
  292. }
  293. if (BucketItem->Next) {
  294. BucketItem->Next->Prev = BucketItem->Prev;
  295. }
  296. pFreeTrackBucketItem (BucketItem);
  297. }
  298. PTRACKBUCKETITEM
  299. pTrackHashTableFind (
  300. IN ALLOCTYPE Type,
  301. IN PVOID Ptr
  302. )
  303. {
  304. PTRACKBUCKETITEM BucketItem;
  305. DWORD Hash;
  306. Hash = pComputeTrackHashVal (Type, Ptr);
  307. BucketItem = g_TrackBuckets[Hash];
  308. while (BucketItem) {
  309. if (BucketItem->Type == Type && BucketItem->Ptr == Ptr) {
  310. return BucketItem;
  311. }
  312. BucketItem = BucketItem->Next;
  313. }
  314. return NULL;
  315. }
  316. VOID
  317. DebugRegisterAllocation (
  318. IN ALLOCTYPE Type,
  319. IN PVOID Ptr,
  320. IN PCSTR File,
  321. IN UINT Line
  322. )
  323. {
  324. PALLOCATION_ITEM Item;
  325. MYASSERT (File);
  326. if (!g_FirstDeletedAlloc) {
  327. Item = (PALLOCATION_ITEM) pOurTrackedGbGrow (&g_AllocationList,sizeof(ALLOCATION_ITEM));
  328. } else {
  329. Item = (PALLOCATION_ITEM) g_FirstDeletedAlloc;
  330. g_FirstDeletedAlloc = Item->Ptr;
  331. }
  332. if (Item) {
  333. Item->Type = Type;
  334. Item->Ptr = Ptr;
  335. Item->FileName = File;
  336. Item->Line = Line;
  337. pTrackHashTableInsert (
  338. g_AllocationList.Buf,
  339. (ALLOCATION_ITEM_OFFSET) ((PBYTE) Item - g_AllocationList.Buf)
  340. );
  341. }
  342. }
  343. VOID
  344. DebugUnregisterAllocation (
  345. IN ALLOCTYPE Type,
  346. IN PVOID Ptr
  347. )
  348. {
  349. PALLOCATION_ITEM Item;
  350. PTRACKBUCKETITEM BucketItem;
  351. BucketItem = pTrackHashTableFind (Type, Ptr);
  352. if (!g_AllocationList.Buf) {
  353. DEBUGMSG ((DBG_WARNING, "Unregister allocation: Allocation buffer already freed"));
  354. return;
  355. }
  356. if (BucketItem) {
  357. Item = (PALLOCATION_ITEM) (g_AllocationList.Buf + BucketItem->ItemOffset);
  358. Item->FileName = NULL;
  359. Item->Type = (ALLOCTYPE) -1;
  360. Item->Ptr = g_FirstDeletedAlloc;
  361. g_FirstDeletedAlloc = Item;
  362. pTrackHashTableDelete (BucketItem);
  363. } else {
  364. DEBUGMSG ((DBG_WARNING, "Unregister allocation: Pointer not registered"));
  365. }
  366. }
  367. #endif