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.

694 lines
14 KiB

  1. /*++
  2. Copyright (c) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. dbgtrack.c
  5. Abstract:
  6. Allocation tracking implementation.
  7. Author:
  8. Jim Schmidt (jimschm) 18-Sept-2001
  9. Revision History:
  10. --*/
  11. //
  12. // Includes
  13. //
  14. #include "pch.h"
  15. #include "commonp.h"
  16. //
  17. // NOTE: No code should appear outside the #ifdef DEBUG
  18. //
  19. #ifdef DEBUG
  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 ULONG_PTR ALLOCATION_ITEM_OFFSET;
  37. typedef struct TAG_TRACKBUCKETITEM {
  38. struct TAG_TRACKBUCKETITEM *Next;
  39. struct TAG_TRACKBUCKETITEM *Prev;
  40. ALLOCTYPE Type;
  41. PCVOID 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. PCVOID Ptr;
  51. PCSTR FileName;
  52. UINT Line;
  53. BOOL Allocated;
  54. } ALLOCATION_ITEM, *PALLOCATION_ITEM;
  55. typedef struct {
  56. PTRACKBUCKETITEM TrackBuckets[TRACK_BUCKETS];
  57. PTRACKBUCKETITEM TrackPoolDelHead;
  58. PTRACKBUCKETPOOL TrackPool;
  59. UINT DisabledRefCount;
  60. INT UseCount;
  61. CHAR TrackComment[1024];
  62. PCSTR TrackFile;
  63. UINT TrackLine;
  64. BOOL FreeTrackFile;
  65. } THREADTRACK, *PTHREADTRACK;
  66. //
  67. // Globals
  68. //
  69. DWORD g_TlsIndex = TLS_OUT_OF_INDEXES;
  70. CRITICAL_SECTION g_AllocListCs;
  71. GROWBUFFER g_AllocationList;
  72. PVOID g_FirstDeletedAlloc;
  73. //
  74. // Macro expansion list
  75. //
  76. // None
  77. //
  78. // Private function prototypes
  79. //
  80. //
  81. // Macro expansion definition
  82. //
  83. // None
  84. //
  85. // Code
  86. //
  87. PBYTE
  88. pUntrackedGbGrow (
  89. IN OUT PGROWBUFFER GrowBuf,
  90. IN DWORD SpaceNeeded
  91. )
  92. /*++
  93. Routine Description:
  94. pUntrackedGbGrow is the same as GbGrow, but it does not cause any tracking
  95. to occur.
  96. Arguments:
  97. GrowBuf - A pointer to a GROWBUFFER structure.
  98. Initialize this structure to zero for
  99. the first call to GrowBuffer.
  100. SpaceNeeded - The number of free bytes needed in the buffer
  101. Return Value:
  102. A pointer to the SpaceNeeded bytes, or NULL if a memory allocation
  103. error occurred.
  104. --*/
  105. {
  106. PBYTE newBuffer;
  107. DWORD totalSpaceNeeded;
  108. DWORD growTo;
  109. MYASSERT(SpaceNeeded);
  110. //
  111. // Make sure structure is initialized properly
  112. //
  113. if (!GrowBuf->Buf) {
  114. ZeroMemory (GrowBuf, sizeof (GROWBUFFER));
  115. }
  116. if (!GrowBuf->GrowSize) {
  117. GrowBuf->GrowSize = 1024;
  118. }
  119. //
  120. // Compute new buffer size
  121. //
  122. totalSpaceNeeded = GrowBuf->End + SpaceNeeded;
  123. if (totalSpaceNeeded > GrowBuf->Size) {
  124. growTo = (totalSpaceNeeded + GrowBuf->GrowSize) - (totalSpaceNeeded % GrowBuf->GrowSize);
  125. } else {
  126. growTo = 0;
  127. }
  128. //
  129. // If no buffer, allocate one. If buffer is too small, reallocate it.
  130. //
  131. if (!GrowBuf->Buf) {
  132. GrowBuf->Buf = (PBYTE) MemAllocNeverFail (g_hHeap, 0, growTo);
  133. GrowBuf->Size = growTo;
  134. } else if (growTo) {
  135. newBuffer = MemReAllocNeverFail (g_hHeap, 0, GrowBuf->Buf, growTo);
  136. GrowBuf->Size = growTo;
  137. GrowBuf->Buf = newBuffer;
  138. }
  139. newBuffer = GrowBuf->Buf + GrowBuf->End;
  140. GrowBuf->End += SpaceNeeded;
  141. return newBuffer;
  142. }
  143. VOID
  144. pUntrackedGbFree (
  145. IN PGROWBUFFER GrowBuf
  146. )
  147. /*++
  148. Routine Description:
  149. pUntrackedGbFree frees a buffer allocated by pUntrackedGbGrow.
  150. Arguments:
  151. GrowBuf - A pointer to the same structure passed to pUntrackedGbGrow
  152. Return Value:
  153. none
  154. --*/
  155. {
  156. MYASSERT(GrowBuf);
  157. if (GrowBuf->Buf) {
  158. HeapFree (g_hHeap, 0, GrowBuf->Buf);
  159. ZeroMemory (GrowBuf, sizeof (GROWBUFFER));
  160. }
  161. }
  162. PTHREADTRACK
  163. pGetTrackStructForThread (
  164. VOID
  165. )
  166. {
  167. PTHREADTRACK result;
  168. result = (PTHREADTRACK) TlsGetValue (g_TlsIndex);
  169. if (!result) {
  170. //
  171. // Need to allocate a struct
  172. //
  173. result = (PTHREADTRACK) MemAllocNeverFail (
  174. g_hHeap,
  175. HEAP_ZERO_MEMORY,
  176. sizeof (THREADTRACK)
  177. );
  178. TlsSetValue (g_TlsIndex, (PVOID) result);
  179. }
  180. return result;
  181. }
  182. VOID
  183. DisableTrackComment (
  184. VOID
  185. )
  186. {
  187. PTHREADTRACK trackStruct;
  188. trackStruct = pGetTrackStructForThread();
  189. trackStruct->DisabledRefCount += 1;
  190. }
  191. VOID
  192. EnableTrackComment (
  193. VOID
  194. )
  195. {
  196. PTHREADTRACK trackStruct;
  197. trackStruct = pGetTrackStructForThread();
  198. if (trackStruct->DisabledRefCount > 0) {
  199. trackStruct->DisabledRefCount -= 1;
  200. }
  201. }
  202. INT
  203. DbgTrackPushEx (
  204. PCSTR Msg,
  205. PCSTR File,
  206. UINT Line,
  207. BOOL DupFileString
  208. )
  209. {
  210. PTHREADTRACK trackStruct;
  211. trackStruct = pGetTrackStructForThread();
  212. if (trackStruct->DisabledRefCount > 0) {
  213. return 0;
  214. }
  215. if (trackStruct->UseCount > 0) {
  216. trackStruct->UseCount += 1;
  217. return 0;
  218. }
  219. if (Msg) {
  220. wsprintfA (trackStruct->TrackComment, "%s line %u [%s]", File, Line, Msg);
  221. } else {
  222. wsprintfA (trackStruct->TrackComment, "%s line %u", File, Line);
  223. }
  224. if (DupFileString) {
  225. trackStruct->TrackFile = (PCSTR) MemAllocNeverFail (g_hHeap, 0, SzSizeA (File));
  226. SzCopyA ((PSTR) trackStruct->TrackFile, File);
  227. trackStruct->FreeTrackFile = TRUE;
  228. } else {
  229. trackStruct->TrackFile = File;
  230. trackStruct->FreeTrackFile = FALSE;
  231. }
  232. trackStruct->TrackLine = Line;
  233. trackStruct->UseCount = 1;
  234. return 0;
  235. }
  236. INT
  237. DbgTrackPop (
  238. VOID
  239. )
  240. {
  241. PTHREADTRACK trackStruct;
  242. trackStruct = pGetTrackStructForThread();
  243. if (trackStruct->DisabledRefCount > 0) {
  244. return 0;
  245. }
  246. trackStruct->UseCount -= 1;
  247. if (!(trackStruct->UseCount)) {
  248. trackStruct->TrackComment[0] = 0;
  249. if (trackStruct->FreeTrackFile && trackStruct->TrackFile) {
  250. HeapFree (g_hHeap, 0, (PVOID)trackStruct->TrackFile);
  251. }
  252. trackStruct->TrackFile = NULL;
  253. trackStruct->TrackLine = 0;
  254. trackStruct->FreeTrackFile = FALSE;
  255. }
  256. return 0;
  257. }
  258. VOID
  259. DbgTrackDump (
  260. VOID
  261. )
  262. {
  263. PTHREADTRACK trackStruct;
  264. trackStruct = pGetTrackStructForThread();
  265. if (trackStruct->UseCount > 0) {
  266. DEBUGMSGA ((
  267. DBG_INFO,
  268. "Caller : %s line %u (%s)",
  269. trackStruct->TrackFile,
  270. trackStruct->TrackLine,
  271. trackStruct->TrackComment
  272. ));
  273. }
  274. }
  275. BOOL
  276. DbgInitTracking (
  277. VOID
  278. )
  279. {
  280. if (g_TlsIndex == TLS_OUT_OF_INDEXES) {
  281. g_TlsIndex = TlsAlloc();
  282. if (g_TlsIndex == TLS_OUT_OF_INDEXES) {
  283. return FALSE;
  284. }
  285. }
  286. InitializeCriticalSection (&g_AllocListCs);
  287. ZeroMemory (&g_AllocationList, sizeof (g_AllocationList));
  288. g_AllocationList.GrowSize = 65536;
  289. g_FirstDeletedAlloc = NULL;
  290. return TRUE;
  291. }
  292. VOID
  293. DbgTerminateTracking (
  294. VOID
  295. )
  296. {
  297. UINT size;
  298. UINT u;
  299. PALLOCATION_ITEM item;
  300. GROWBUFFER msg = { 0, 0, 0, 0, 0, 0 };
  301. CHAR text[1024];
  302. PSTR p;
  303. UINT byteCount;
  304. PTHREADTRACK trackStruct;
  305. EnterCriticalSection (&g_AllocListCs);
  306. trackStruct = pGetTrackStructForThread();
  307. size = g_AllocationList.End / sizeof (ALLOCATION_ITEM);
  308. for (u = 0 ; u < size ; u++) {
  309. item = (PALLOCATION_ITEM) g_AllocationList.Buf + u;
  310. if (!item->FileName) {
  311. continue;
  312. }
  313. //
  314. // Append the string but not the nul
  315. //
  316. byteCount = (UINT) wsprintfA (text, "%s line %u\r\n", item->FileName, item->Line);
  317. p = (PSTR) pUntrackedGbGrow (&msg, byteCount);
  318. CopyMemory (p, text, byteCount);
  319. }
  320. pUntrackedGbFree (&g_AllocationList);
  321. g_FirstDeletedAlloc = NULL;
  322. LeaveCriticalSection (&g_AllocListCs);
  323. //
  324. // Put the message in the log
  325. //
  326. if (msg.End) {
  327. p = (PSTR) pUntrackedGbGrow (&msg, 1);
  328. *p = 0;
  329. DEBUGMSGA ((DBG_WARNING, "Leaks : %s", msg.Buf));
  330. pUntrackedGbFree (&msg);
  331. }
  332. // Intentional leak -- who cares about track memory
  333. trackStruct->TrackPoolDelHead = NULL;
  334. trackStruct->TrackPool = NULL;
  335. TlsFree (g_TlsIndex);
  336. g_TlsIndex = TLS_OUT_OF_INDEXES;
  337. }
  338. PTRACKBUCKETITEM
  339. pAllocTrackBucketItem (
  340. VOID
  341. )
  342. {
  343. PTRACKBUCKETITEM bucketItem;
  344. PTHREADTRACK trackStruct;
  345. trackStruct = pGetTrackStructForThread();
  346. if (trackStruct->TrackPoolDelHead) {
  347. bucketItem = trackStruct->TrackPoolDelHead;
  348. trackStruct->TrackPoolDelHead = bucketItem->Next;
  349. } else {
  350. if (!trackStruct->TrackPool || trackStruct->TrackPool->Count == BUCKET_ITEMS_PER_POOL) {
  351. trackStruct->TrackPool = (PTRACKBUCKETPOOL) MemAllocNeverFail (g_hHeap, 0, sizeof (TRACKBUCKETPOOL));
  352. trackStruct->TrackPool->Count = 0;
  353. }
  354. bucketItem = trackStruct->TrackPool->Items + trackStruct->TrackPool->Count;
  355. trackStruct->TrackPool->Count++;
  356. }
  357. return bucketItem;
  358. }
  359. VOID
  360. pFreeTrackBucketItem (
  361. PTRACKBUCKETITEM BucketItem
  362. )
  363. {
  364. PTHREADTRACK trackStruct;
  365. trackStruct = pGetTrackStructForThread();
  366. BucketItem->Next = trackStruct->TrackPoolDelHead;
  367. trackStruct->TrackPoolDelHead = BucketItem;
  368. }
  369. UINT
  370. pComputeTrackHashVal (
  371. IN ALLOCTYPE Type,
  372. IN PCVOID Ptr
  373. )
  374. {
  375. ULONG_PTR hash;
  376. hash = ((ULONG_PTR) Type << 16) ^ (ULONG_PTR)Ptr;
  377. return (UINT) (hash % TRACK_BUCKETS);
  378. }
  379. VOID
  380. pTrackHashTableInsert (
  381. IN PBYTE Base,
  382. IN ALLOCATION_ITEM_OFFSET ItemOffset
  383. )
  384. {
  385. UINT hash;
  386. PTRACKBUCKETITEM bucketItem;
  387. PALLOCATION_ITEM item;
  388. PTHREADTRACK trackStruct;
  389. trackStruct = pGetTrackStructForThread();
  390. item = (PALLOCATION_ITEM) (Base + ItemOffset);
  391. hash = pComputeTrackHashVal (item->Type, item->Ptr);
  392. bucketItem = pAllocTrackBucketItem();
  393. bucketItem->Prev = NULL;
  394. bucketItem->Next = trackStruct->TrackBuckets[hash];
  395. bucketItem->Type = item->Type;
  396. bucketItem->Ptr = item->Ptr;
  397. bucketItem->ItemOffset = ItemOffset;
  398. if (bucketItem->Next) {
  399. bucketItem->Next->Prev = bucketItem;
  400. }
  401. trackStruct->TrackBuckets[hash] = bucketItem;
  402. }
  403. VOID
  404. pTrackHashTableDelete (
  405. IN PTRACKBUCKETITEM BucketItem
  406. )
  407. {
  408. UINT hash;
  409. PTHREADTRACK trackStruct;
  410. trackStruct = pGetTrackStructForThread();
  411. hash = pComputeTrackHashVal (BucketItem->Type, BucketItem->Ptr);
  412. if (BucketItem->Prev) {
  413. BucketItem->Prev->Next = BucketItem->Next;
  414. } else {
  415. trackStruct->TrackBuckets[hash] = BucketItem->Next;
  416. }
  417. if (BucketItem->Next) {
  418. BucketItem->Next->Prev = BucketItem->Prev;
  419. }
  420. pFreeTrackBucketItem (BucketItem);
  421. }
  422. PTRACKBUCKETITEM
  423. pTrackHashTableFind (
  424. IN ALLOCTYPE Type,
  425. IN PCVOID Ptr
  426. )
  427. {
  428. PTRACKBUCKETITEM bucketItem;
  429. UINT hash;
  430. PTHREADTRACK trackStruct;
  431. trackStruct = pGetTrackStructForThread();
  432. hash = pComputeTrackHashVal (Type, Ptr);
  433. bucketItem = trackStruct->TrackBuckets[hash];
  434. while (bucketItem) {
  435. if (bucketItem->Type == Type && bucketItem->Ptr == Ptr) {
  436. return bucketItem;
  437. }
  438. bucketItem = bucketItem->Next;
  439. }
  440. return NULL;
  441. }
  442. VOID
  443. DbgRegisterAllocation (
  444. IN ALLOCTYPE Type,
  445. IN PVOID Ptr,
  446. IN PCSTR File,
  447. IN UINT Line
  448. )
  449. {
  450. PALLOCATION_ITEM item;
  451. PTHREADTRACK trackStruct;
  452. PCSTR fileToRecord;
  453. UINT lineToRecord;
  454. trackStruct = pGetTrackStructForThread();
  455. if (!trackStruct->TrackFile) {
  456. fileToRecord = File;
  457. lineToRecord = Line;
  458. } else {
  459. fileToRecord = trackStruct->TrackFile;
  460. lineToRecord = trackStruct->TrackLine;
  461. }
  462. EnterCriticalSection (&g_AllocListCs);
  463. if (!g_FirstDeletedAlloc) {
  464. item = (PALLOCATION_ITEM) pUntrackedGbGrow (&g_AllocationList,sizeof(ALLOCATION_ITEM));
  465. } else {
  466. item = (PALLOCATION_ITEM) g_FirstDeletedAlloc;
  467. g_FirstDeletedAlloc = (PVOID)item->Ptr;
  468. }
  469. item->Type = Type;
  470. item->Ptr = Ptr;
  471. item->FileName = fileToRecord;
  472. item->Line = lineToRecord;
  473. pTrackHashTableInsert (
  474. g_AllocationList.Buf,
  475. (ALLOCATION_ITEM_OFFSET) ((PBYTE) item - g_AllocationList.Buf)
  476. );
  477. LeaveCriticalSection (&g_AllocListCs);
  478. }
  479. VOID
  480. DbgUnregisterAllocation (
  481. IN ALLOCTYPE Type,
  482. IN PCVOID Ptr
  483. )
  484. {
  485. PALLOCATION_ITEM item;
  486. PTRACKBUCKETITEM bucketItem;
  487. EnterCriticalSection (&g_AllocListCs);
  488. bucketItem = pTrackHashTableFind (Type, Ptr);
  489. if (!g_AllocationList.Buf) {
  490. LeaveCriticalSection (&g_AllocListCs);
  491. DEBUGMSG ((DBG_WARNING, "Unregister allocation: Allocation buffer already freed"));
  492. return;
  493. }
  494. if (bucketItem) {
  495. item = (PALLOCATION_ITEM) (g_AllocationList.Buf + bucketItem->ItemOffset);
  496. if (item->Allocated) {
  497. HeapFree (g_hHeap, 0, (PSTR)item->FileName);
  498. }
  499. item->FileName = NULL;
  500. item->Type = (ALLOCTYPE) -1;
  501. item->Ptr = g_FirstDeletedAlloc;
  502. g_FirstDeletedAlloc = item;
  503. pTrackHashTableDelete (bucketItem);
  504. LeaveCriticalSection (&g_AllocListCs);
  505. } else {
  506. LeaveCriticalSection (&g_AllocListCs);
  507. DEBUGMSG ((DBG_WARNING, "Unregister allocation: Pointer not registered"));
  508. }
  509. }
  510. #endif