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.

472 lines
12 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: pooltrk.cxx
  3. *
  4. * Pool allocation tracker.
  5. *
  6. * Created: 23-Feb-1998 20:09:03
  7. * Author: Gilman Wong [gilmanw]
  8. *
  9. * Copyright (c) 1998-1999 Microsoft Corporation
  10. *
  11. \**************************************************************************/
  12. #include "precomp.hxx"
  13. #include "pooltrk.hxx"
  14. #if DBG
  15. #ifdef _HYDRA_
  16. #ifndef USER_POOL_TAGGING_ON
  17. extern BOOL G_fConsole;
  18. LIST_ENTRY gleDebugGrePoolTrackerHead;
  19. HSEMAPHORE ghsemDebugGrePoolTracker = NULL;
  20. /******************************Public*Routine******************************\
  21. * DebugGrePoolTrackerInit
  22. *
  23. * Initialize the pool tracker.
  24. *
  25. * Returns:
  26. * TRUE if successful, FALSE otherwise.
  27. *
  28. * History:
  29. * 23-Feb-1998 -by- Gilman Wong [gilmanw]
  30. * Wrote it.
  31. \**************************************************************************/
  32. BOOL
  33. DebugGrePoolTrackerInit()
  34. {
  35. //
  36. // Initialize doubly linked list used to track pool allocations.
  37. //
  38. InitializeListHead(&gleDebugGrePoolTrackerHead);
  39. //
  40. // Initialize the list semaphore.
  41. //
  42. // Note: allocate from non-tracked pool. We will trust the pool
  43. // tracker to cleanup its own allocation.
  44. //
  45. ghsemDebugGrePoolTracker = GreCreateSemaphoreNonTracked();
  46. return (ghsemDebugGrePoolTracker != NULL);
  47. }
  48. /******************************Public*Routine******************************\
  49. * DebugGrePoolTrackerAdd
  50. *
  51. * Add specified pool allocation to list.
  52. *
  53. * History:
  54. * 23-Feb-1998 -by- Gilman Wong [gilmanw]
  55. * Wrote it.
  56. \**************************************************************************/
  57. VOID
  58. DebugGrePoolTrackerAdd(POOLTRACKHDR *pTrack, SIZE_T cj, ULONG ulTag)
  59. {
  60. PLIST_ENTRY pleNew = (PLIST_ENTRY) pTrack;
  61. //
  62. // Setup pool track header.
  63. //
  64. // Sundown note: pool allocations in GRE should be < 4GB
  65. //
  66. pTrack->ulSize = cj;
  67. pTrack->ulTag = ulTag;
  68. //
  69. // Lock the pool tracking list.
  70. //
  71. // During GRE initialization, we may be called while allocating
  72. // the ghsemDebugGrePoolTracker. So we actually need to check
  73. // if it exists.
  74. //
  75. if (ghsemDebugGrePoolTracker) GreAcquireSemaphore(ghsemDebugGrePoolTracker);
  76. //
  77. // Insert into the pool tracking list.
  78. //
  79. InsertTailList(&gleDebugGrePoolTrackerHead, pleNew);
  80. //
  81. // Unlock the pool tracking list.
  82. //
  83. if (ghsemDebugGrePoolTracker) GreReleaseSemaphore(ghsemDebugGrePoolTracker);
  84. }
  85. /******************************Public*Routine******************************\
  86. * DebugGrePoolTrackerRemove
  87. *
  88. * Remove specified pool allocation from list.
  89. *
  90. * History:
  91. * 23-Feb-1998 -by- Gilman Wong [gilmanw]
  92. * Wrote it.
  93. \**************************************************************************/
  94. VOID
  95. DebugGrePoolTrackerRemove(POOLTRACKHDR *pTrack)
  96. {
  97. PLIST_ENTRY pleVictim = (PLIST_ENTRY) pTrack;
  98. //
  99. // Lock the pool tracking list.
  100. //
  101. // During GRE initialization, we may be called while allocating
  102. // the ghsemDebugGrePoolTracker. So we actually need to check
  103. // if it exists.
  104. //
  105. if (ghsemDebugGrePoolTracker) GreAcquireSemaphore(ghsemDebugGrePoolTracker);
  106. //
  107. // Remove entry from pool tracking list.
  108. //
  109. RemoveEntryList(pleVictim);
  110. //
  111. // Unlock the pool tracking list.
  112. //
  113. if (ghsemDebugGrePoolTracker) GreReleaseSemaphore(ghsemDebugGrePoolTracker);
  114. }
  115. /******************************Public*Routine******************************\
  116. * DebugGreAllocPool
  117. *
  118. * Allocates paged pool and tracks it in the pool tracking list.
  119. * Free with DebugGreFreePool.
  120. *
  121. * Buffer
  122. * pTrack --> +----------------+
  123. * | POOLTRACKHDR |
  124. * pvRet --> +----------------+
  125. * | Returned |
  126. * | Buffer |
  127. * | Allocation |
  128. * | |
  129. * ...
  130. * | |
  131. * +----------------+
  132. *
  133. *
  134. * History:
  135. * 23-Feb-1998 -by- Gilman Wong [gilmanw]
  136. * Wrote it.
  137. \**************************************************************************/
  138. extern "C" PVOID
  139. DebugGreAllocPool(SIZE_T ulBytes, ULONG ulTag)
  140. {
  141. PVOID pv;
  142. //
  143. // If Hydra, adjust requested size to include tracking header.
  144. //
  145. // Sundown note: sizeof(POOLTRACKHDR) will fit into 32-bits.
  146. //
  147. if (!G_fConsole)
  148. {
  149. if (ulBytes <= (MAXULONG - sizeof(POOLTRACKHDR)))
  150. ulBytes += ((ULONG) sizeof(POOLTRACKHDR));
  151. else
  152. return NULL;
  153. }
  154. //
  155. // Allocate paged pool.
  156. //
  157. pv = ExAllocatePoolWithTag(
  158. (POOL_TYPE) (SESSION_POOL_MASK | PagedPool),
  159. ulBytes, ulTag);
  160. if (pv)
  161. {
  162. //
  163. // Tracking overhead if Hydra.
  164. //
  165. if (!G_fConsole)
  166. {
  167. //
  168. // Add allocation to tracking list.
  169. //
  170. POOLTRACKHDR *pTrack = (POOLTRACKHDR *) pv;
  171. DebugGrePoolTrackerAdd(pTrack, ulBytes, ulTag);
  172. #ifdef POOLTRACK_STACKTRACE_ENABLE
  173. //
  174. // Save the stack back trace.
  175. //
  176. ULONG ulHash;
  177. RtlZeroMemory(pTrack->apvStackTrace,
  178. POOLTRACK_TRACESIZE * sizeof(PVOID));
  179. RtlCaptureStackBackTrace(1,
  180. POOLTRACK_TRACESIZE,
  181. pTrack->apvStackTrace,
  182. &ulHash);
  183. #endif
  184. //
  185. // Adjust return pointer to exclude tracking header.
  186. //
  187. pv = (PVOID) (pTrack + 1);
  188. }
  189. }
  190. return pv;
  191. }
  192. /******************************Public*Routine******************************\
  193. * DebugGreAllocPoolNonPaged
  194. *
  195. * Allocates nonpaged pool and tracks it in the pool tracking list.
  196. * Free with DebugGreFreePool.
  197. *
  198. * History:
  199. * 23-Feb-1998 -by- Gilman Wong [gilmanw]
  200. * Wrote it.
  201. \**************************************************************************/
  202. extern "C" PVOID
  203. DebugGreAllocPoolNonPaged(SIZE_T ulBytes, ULONG ulTag)
  204. {
  205. PVOID pv;
  206. //
  207. // If Hydra, adjust requested size to include tracking header.
  208. //
  209. // Sundown note: sizeof(POOLTRACKHDR) will fit into 32-bits.
  210. //
  211. if (!G_fConsole)
  212. {
  213. ulBytes += ((ULONG) sizeof(POOLTRACKHDR));
  214. }
  215. //
  216. // Allocate nonpaged pool.
  217. //
  218. pv = ExAllocatePoolWithTag(
  219. (POOL_TYPE)NonPagedPool,
  220. ulBytes, ulTag);
  221. if (pv)
  222. {
  223. //
  224. // Tracking overhead if Hydra.
  225. //
  226. if (!G_fConsole)
  227. {
  228. //
  229. // Add allocation to tracking list.
  230. //
  231. POOLTRACKHDR *pTrack = (POOLTRACKHDR *) pv;
  232. DebugGrePoolTrackerAdd(pTrack, ulBytes, ulTag);
  233. //
  234. // Adjust return pointer to exclude tracking header.
  235. //
  236. pv = (PVOID) (pTrack + 1);
  237. }
  238. }
  239. return pv;
  240. }
  241. /******************************Public*Routine******************************\
  242. * DebugGreFreePool
  243. *
  244. * Free pool memory allocated by DebugGreAllocPool and
  245. * DebugGreAllocPoolNonPaged. Removes the allocation from tracking list.
  246. *
  247. * History:
  248. * 23-Feb-1998 -by- Gilman Wong [gilmanw]
  249. * Wrote it.
  250. \**************************************************************************/
  251. extern "C" VOID
  252. DebugGreFreePool(PVOID pv)
  253. {
  254. if (pv)
  255. {
  256. //
  257. // Tracking overhead if Hydra.
  258. //
  259. if (!G_fConsole)
  260. {
  261. //
  262. // Find header and remove from tracking list.
  263. //
  264. POOLTRACKHDR *pTrack = ((POOLTRACKHDR *) pv) - 1;
  265. DebugGrePoolTrackerRemove(pTrack);
  266. //
  267. // Adjust pointer to base of allocation.
  268. //
  269. pv = (PVOID) pTrack;
  270. }
  271. //
  272. // Free the pool allocation.
  273. //
  274. ExFreePool(pv);
  275. }
  276. }
  277. /******************************Public*Routine******************************\
  278. * DebugGreCleanupPoolTracker
  279. *
  280. * Frees any allocations remaining in the tracking list (but asserts so
  281. * that debugger is informed that a leak exists). Free resources used
  282. * to maintain the tracking list.
  283. *
  284. * History:
  285. * 23-Feb-1998 -by- Gilman Wong [gilmanw]
  286. * Wrote it.
  287. \**************************************************************************/
  288. VOID
  289. DebugGreCleanupPoolTracker()
  290. {
  291. BOOL bTitle = FALSE;
  292. ULONG cLeaks = 0;
  293. volatile PLIST_ENTRY pleNext;
  294. //
  295. // Assert if list not empty (i.e., there are leaks!).
  296. //
  297. // What to do if there is a leak?
  298. //
  299. // Well, it might be enough just to look at the tags that leak.
  300. // If that doesn't provide enough detail to track the leak,
  301. // recompile with USER_POOL_TAGGING_ON defined in engine.h and
  302. // define POOL_ALLOC_TRACE in w32\w32inc\usergdi.h to use the
  303. // USER pool tracking code. You'll have build a checked version
  304. // of win32k (clean build both USER and GDI), but this pool tracker
  305. // will record a stack trace for every allocation. If we leak,
  306. // USER will assert during Hydra session shutdown and the userkdx
  307. // dpa extension will dump the allocations (use !dpa -ts 24 to
  308. // dump the leaked TAG_GDI allocations with a stack trace).
  309. //
  310. if (!IsListEmpty(&gleDebugGrePoolTrackerHead))
  311. {
  312. DbgPrint("DebugGreCleanupPoolTracker: "
  313. "gleDebugGrePoolTrackerHead 0x%08lx not empty\n",
  314. &gleDebugGrePoolTrackerHead);
  315. RIP("DebugGreCleanupPoolTracker: leak detected\n");
  316. }
  317. //
  318. // Free all allocations in the list.
  319. //
  320. pleNext = gleDebugGrePoolTrackerHead.Flink;
  321. while (pleNext != &gleDebugGrePoolTrackerHead)
  322. {
  323. //
  324. // Pool allocation starts after the POOLTRACKHDR.
  325. //
  326. PVOID pvVictim = (PVOID) (((POOLTRACKHDR *) pleNext) + 1);
  327. //
  328. // Count the number of leaked allocations.
  329. //
  330. cLeaks++;
  331. //
  332. // Print out the allocation information.
  333. //
  334. if (!bTitle)
  335. {
  336. DbgPrint("\nDebugGreCleanupPoolTracker: cleaning up pool allocations\n");
  337. DbgPrint("----------\t----------\t-----------------\n");
  338. DbgPrint("Address \tSize \tTag\n");
  339. DbgPrint("----------\t----------\t-----------------\n");
  340. bTitle = TRUE;
  341. }
  342. DbgPrint("0x%08lx\t0x%08lx\t0x%08lx (%c%c%c%c)\n",
  343. pleNext,
  344. ((POOLTRACKHDR *) pleNext)->ulSize,
  345. ((POOLTRACKHDR *) pleNext)->ulTag,
  346. ((((POOLTRACKHDR *) pleNext)->ulTag) ) & 0xff,
  347. ((((POOLTRACKHDR *) pleNext)->ulTag) >> 8) & 0xff,
  348. ((((POOLTRACKHDR *) pleNext)->ulTag) >> 16) & 0xff,
  349. ((((POOLTRACKHDR *) pleNext)->ulTag) >> 24) & 0xff);
  350. //
  351. // Delete the allocation.
  352. //
  353. DebugGreFreePool(pvVictim);
  354. //
  355. // Restart at the begining of the list since our
  356. // entry got deleted.
  357. //
  358. pleNext = gleDebugGrePoolTrackerHead.Flink;
  359. }
  360. if (bTitle)
  361. {
  362. DbgPrint("----------\t----------\t-----------------\n");
  363. }
  364. if (cLeaks)
  365. {
  366. DbgPrint("%ld allocations leaked\n\n", cLeaks);
  367. }
  368. //
  369. // Delete the list lock.
  370. //
  371. // Note that the list lock was allocated from non-tracked pool.
  372. // It is also a non-tracked semaphore - that is, it must be deleted
  373. // explicitly.
  374. //
  375. GreDeleteSemaphoreNonTracked(ghsemDebugGrePoolTracker);
  376. ghsemDebugGrePoolTracker = NULL;
  377. }
  378. #endif //USER_POOL_TAGGING_ON
  379. #endif //_HYDRA_
  380. #endif //DBG