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.

2383 lines
58 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. heapdbg.c
  5. Abstract:
  6. This module implements a debugging layer on top of heap allocator.
  7. Author:
  8. Steve Wood (stevewo) 20-Sep-1994
  9. Revision History:
  10. --*/
  11. #include "ntrtlp.h"
  12. #include "heap.h"
  13. #include "heappriv.h"
  14. BOOLEAN RtlpValidateHeapHdrsEnable = FALSE; // Set to TRUE if headers are being corrupted
  15. BOOLEAN RtlpValidateHeapTagsEnable; // Set to TRUE if tag counts are off and you want to know why
  16. HEAP_STOP_ON_VALUES RtlpHeapStopOn;
  17. const struct {
  18. ULONG Offset;
  19. LPSTR Description;
  20. } RtlpHeapHeaderFieldOffsets[] = {
  21. FIELD_OFFSET( HEAP, Entry ), "Entry",
  22. FIELD_OFFSET( HEAP, Signature ), "Signature",
  23. FIELD_OFFSET( HEAP, Flags ), "Flags",
  24. FIELD_OFFSET( HEAP, ForceFlags ), "ForceFlags",
  25. FIELD_OFFSET( HEAP, VirtualMemoryThreshold ), "VirtualMemoryThreshold",
  26. FIELD_OFFSET( HEAP, SegmentReserve ), "SegmentReserve",
  27. FIELD_OFFSET( HEAP, SegmentCommit ), "SegmentCommit",
  28. FIELD_OFFSET( HEAP, DeCommitFreeBlockThreshold ), "DeCommitFreeBlockThreshold",
  29. FIELD_OFFSET( HEAP, DeCommitTotalFreeThreshold ), "DeCommitTotalFreeThreshold",
  30. FIELD_OFFSET( HEAP, TotalFreeSize ), "TotalFreeSize",
  31. FIELD_OFFSET( HEAP, MaximumAllocationSize ), "MaximumAllocationSize",
  32. FIELD_OFFSET( HEAP, ProcessHeapsListIndex ), "ProcessHeapsListIndex",
  33. FIELD_OFFSET( HEAP, HeaderValidateLength ), "HeaderValidateLength",
  34. FIELD_OFFSET( HEAP, HeaderValidateCopy ), "HeaderValidateCopy",
  35. FIELD_OFFSET( HEAP, NextAvailableTagIndex ), "NextAvailableTagIndex",
  36. FIELD_OFFSET( HEAP, MaximumTagIndex ), "MaximumTagIndex",
  37. FIELD_OFFSET( HEAP, TagEntries ), "TagEntries",
  38. FIELD_OFFSET( HEAP, UCRSegments ), "UCRSegments",
  39. FIELD_OFFSET( HEAP, UnusedUnCommittedRanges ), "UnusedUnCommittedRanges",
  40. FIELD_OFFSET( HEAP, AlignRound ), "AlignRound",
  41. FIELD_OFFSET( HEAP, AlignMask ), "AlignMask",
  42. FIELD_OFFSET( HEAP, VirtualAllocdBlocks ), "VirtualAllocdBlocks",
  43. FIELD_OFFSET( HEAP, Segments ), "Segments",
  44. FIELD_OFFSET( HEAP, u ), "FreeListsInUse",
  45. FIELD_OFFSET( HEAP, u2 ), "FreeListsInUseTerminate",
  46. FIELD_OFFSET( HEAP, AllocatorBackTraceIndex ), "AllocatorBackTraceIndex",
  47. FIELD_OFFSET( HEAP, NonDedicatedListLength ), "NonDedicatedListLength",
  48. FIELD_OFFSET( HEAP, PseudoTagEntries ), "PseudoTagEntries",
  49. FIELD_OFFSET( HEAP, FreeLists ), "FreeLists",
  50. FIELD_OFFSET( HEAP, LockVariable ), "LockVariable",
  51. FIELD_OFFSET( HEAP, FrontEndHeap ), "FrontEndHeap",
  52. FIELD_OFFSET( HEAP, FrontHeapLockCount ), "FrontHeapLockCount",
  53. FIELD_OFFSET( HEAP, FrontEndHeapType ), "FrontEndHeapType",
  54. FIELD_OFFSET( HEAP, LastSegmentIndex ), "LastSegmentIndex",
  55. sizeof( HEAP ), "Uncommitted Ranges",
  56. 0xFFFF, NULL
  57. };
  58. VOID
  59. RtlpUpdateHeapListIndex (
  60. USHORT OldIndex,
  61. USHORT NewIndex
  62. )
  63. /*++
  64. Routine Description:
  65. Arguments:
  66. Return Value:
  67. --*/
  68. {
  69. if (RtlpHeapStopOn.AllocTag.HeapIndex == OldIndex) {
  70. RtlpHeapStopOn.AllocTag.HeapIndex = NewIndex;
  71. }
  72. if (RtlpHeapStopOn.ReAllocTag.HeapIndex == OldIndex) {
  73. RtlpHeapStopOn.ReAllocTag.HeapIndex = NewIndex;
  74. }
  75. if (RtlpHeapStopOn.FreeTag.HeapIndex == OldIndex) {
  76. RtlpHeapStopOn.FreeTag.HeapIndex = NewIndex;
  77. }
  78. return;
  79. }
  80. BOOLEAN
  81. RtlpValidateHeapHeaders (
  82. IN PHEAP Heap,
  83. IN BOOLEAN Recompute
  84. )
  85. /*++
  86. Routine Description:
  87. Arguments:
  88. Return Value:
  89. --*/
  90. {
  91. ULONG i;
  92. SIZE_T n;
  93. SIZE_T nEqual;
  94. NTSTATUS Status;
  95. if (!RtlpValidateHeapHdrsEnable) {
  96. return TRUE;
  97. }
  98. if (Heap->HeaderValidateCopy == NULL) {
  99. n = Heap->HeaderValidateLength;
  100. Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  101. &Heap->HeaderValidateCopy,
  102. 0,
  103. &n,
  104. MEM_COMMIT,
  105. PAGE_READWRITE );
  106. if (!NT_SUCCESS( Status )) {
  107. return TRUE;
  108. }
  109. Recompute = TRUE;
  110. }
  111. n = Heap->HeaderValidateLength;
  112. if (!Recompute) {
  113. nEqual = RtlCompareMemory( Heap,
  114. Heap->HeaderValidateCopy,
  115. n );
  116. } else {
  117. RtlCopyMemory( Heap->HeaderValidateCopy,
  118. Heap,
  119. n );
  120. nEqual = n;
  121. }
  122. if (n != nEqual) {
  123. HeapDebugPrint(( "Heap %x - headers modified (%x is %x instead of %x)\n",
  124. Heap,
  125. (PCHAR)Heap + nEqual,
  126. *(PULONG)((PCHAR)Heap + nEqual),
  127. *(PULONG)((PCHAR)Heap->HeaderValidateCopy + nEqual)));
  128. for (i=0; RtlpHeapHeaderFieldOffsets[ i ].Description != NULL; i++) {
  129. if ((nEqual >= RtlpHeapHeaderFieldOffsets[ i ].Offset) &&
  130. (nEqual < RtlpHeapHeaderFieldOffsets[ i+1 ].Offset)) {
  131. DbgPrint( " This is located in the %s field of the heap header.\n",
  132. RtlpHeapHeaderFieldOffsets[ i ].Description );
  133. break;
  134. }
  135. }
  136. return FALSE;
  137. } else {
  138. return TRUE;
  139. }
  140. }
  141. PVOID
  142. RtlDebugCreateHeap (
  143. IN ULONG Flags,
  144. IN PVOID HeapBase OPTIONAL,
  145. IN SIZE_T ReserveSize OPTIONAL,
  146. IN SIZE_T CommitSize OPTIONAL,
  147. IN PVOID Lock OPTIONAL,
  148. IN PRTL_HEAP_PARAMETERS Parameters
  149. )
  150. /*++
  151. Routine Description:
  152. Arguments:
  153. Return Value:
  154. --*/
  155. {
  156. PHEAP Heap;
  157. NTSTATUS Status;
  158. MEMORY_BASIC_INFORMATION MemoryInformation;
  159. if (ReserveSize <= sizeof( HEAP_ENTRY )) {
  160. HeapDebugPrint(( "Invalid ReserveSize parameter - %p\n", ReserveSize ));
  161. HeapDebugBreak( NULL );
  162. return NULL;
  163. }
  164. if (ReserveSize < CommitSize) {
  165. HeapDebugPrint(( "Invalid CommitSize parameter - %p\n", CommitSize ));
  166. HeapDebugBreak( NULL );
  167. return NULL;
  168. }
  169. if ((Flags & HEAP_NO_SERIALIZE) && ARGUMENT_PRESENT( Lock )) {
  170. HeapDebugPrint(( "May not specify Lock parameter with HEAP_NO_SERIALIZE\n" ));
  171. HeapDebugBreak( NULL );
  172. return NULL;
  173. }
  174. if (ARGUMENT_PRESENT( HeapBase )) {
  175. Status = NtQueryVirtualMemory( NtCurrentProcess(),
  176. HeapBase,
  177. MemoryBasicInformation,
  178. &MemoryInformation,
  179. sizeof( MemoryInformation ),
  180. NULL );
  181. if (!NT_SUCCESS( Status )) {
  182. HeapDebugPrint(( "Specified HeapBase (%p) invalid, Status = %lx\n",
  183. HeapBase,
  184. Status ));
  185. HeapDebugBreak( NULL );
  186. return NULL;
  187. }
  188. if (MemoryInformation.BaseAddress != HeapBase) {
  189. HeapDebugPrint(( "Specified HeapBase (%p) != to BaseAddress (%p)\n",
  190. HeapBase,
  191. MemoryInformation.BaseAddress ));
  192. HeapDebugBreak( NULL );
  193. return NULL;
  194. }
  195. if (MemoryInformation.State == MEM_FREE) {
  196. HeapDebugPrint(( "Specified HeapBase (%p) is free or not writable\n",
  197. MemoryInformation.BaseAddress ));
  198. HeapDebugBreak( NULL );
  199. return NULL;
  200. }
  201. }
  202. Heap = RtlCreateHeap( Flags |
  203. HEAP_SKIP_VALIDATION_CHECKS |
  204. HEAP_TAIL_CHECKING_ENABLED |
  205. HEAP_FREE_CHECKING_ENABLED,
  206. HeapBase,
  207. ReserveSize,
  208. CommitSize,
  209. Lock,
  210. Parameters );
  211. if (Heap != NULL) {
  212. if (Heap->Flags & HEAP_CAPTURE_STACK_BACKTRACES) {
  213. Heap->AllocatorBackTraceIndex = (USHORT)RtlLogStackBackTrace();
  214. }
  215. RtlpValidateHeapHeaders( Heap, TRUE );
  216. }
  217. return Heap;
  218. }
  219. BOOLEAN
  220. RtlpSerializeHeap (
  221. IN PVOID HeapHandle
  222. )
  223. /*++
  224. Routine Description:
  225. Arguments:
  226. Return Value:
  227. --*/
  228. {
  229. NTSTATUS Status;
  230. PHEAP Heap = (PHEAP)HeapHandle;
  231. PHEAP_LOCK Lock;
  232. IF_DEBUG_PAGE_HEAP_THEN_RETURN( HeapHandle,
  233. RtlpDebugPageHeapSerialize( HeapHandle ));
  234. //
  235. // Validate that HeapAddress points to a HEAP structure.
  236. //
  237. if (!RtlpCheckHeapSignature( Heap, "RtlpSerializeHeap" )) {
  238. return FALSE;
  239. }
  240. //
  241. // Lock the heap.
  242. //
  243. if (Heap->Flags & HEAP_NO_SERIALIZE) {
  244. Lock = RtlAllocateHeap( HeapHandle, HEAP_NO_SERIALIZE, sizeof( *Lock ) );
  245. if ( Lock == NULL ) {
  246. return FALSE;
  247. }
  248. Status = RtlInitializeLockRoutine( Lock );
  249. if (!NT_SUCCESS( Status )) {
  250. RtlFreeHeap( HeapHandle, HEAP_NO_SERIALIZE, Lock );
  251. return FALSE;
  252. }
  253. Heap->LockVariable = Lock;
  254. Heap->Flags &= ~HEAP_NO_SERIALIZE;
  255. Heap->ForceFlags &= ~HEAP_NO_SERIALIZE;
  256. RtlpValidateHeapHeaders( Heap, TRUE );
  257. }
  258. return TRUE;
  259. }
  260. BOOLEAN
  261. RtlDebugDestroyHeap (
  262. IN PVOID HeapHandle
  263. )
  264. /*++
  265. Routine Description:
  266. Arguments:
  267. Return Value:
  268. --*/
  269. {
  270. PHEAP Heap = (PHEAP)HeapHandle;
  271. LIST_ENTRY ListEntry;
  272. SIZE_T n;
  273. if (HeapHandle == NtCurrentPeb()->ProcessHeap) {
  274. HeapDebugPrint(( "May not destroy the process heap at %x\n", HeapHandle ));
  275. return FALSE;
  276. }
  277. if (!RtlpCheckHeapSignature( Heap, "RtlDestroyHeap" )) {
  278. return FALSE;
  279. }
  280. if (!RtlpValidateHeap( Heap, FALSE )) {
  281. return FALSE;
  282. }
  283. //
  284. // Now mark the heap as invalid by zeroing the signature field.
  285. //
  286. Heap->Signature = 0;
  287. if (Heap->HeaderValidateCopy != NULL) {
  288. n = 0;
  289. RtlpHeapFreeVirtualMemory( NtCurrentProcess(),
  290. &Heap->HeaderValidateCopy,
  291. &n,
  292. MEM_RELEASE );
  293. }
  294. return TRUE;
  295. }
  296. PVOID
  297. RtlDebugAllocateHeap (
  298. IN PVOID HeapHandle,
  299. IN ULONG Flags,
  300. IN SIZE_T Size
  301. )
  302. /*++
  303. Routine Description:
  304. Arguments:
  305. Return Value:
  306. --*/
  307. {
  308. PHEAP Heap = (PHEAP)HeapHandle;
  309. BOOLEAN LockAcquired = FALSE;
  310. PVOID ReturnValue = NULL;
  311. SIZE_T AllocationSize;
  312. USHORT TagIndex;
  313. PHEAP_ENTRY BusyBlock;
  314. PHEAP_ENTRY_EXTRA ExtraStuff;
  315. IF_DEBUG_PAGE_HEAP_THEN_RETURN( HeapHandle,
  316. RtlpDebugPageHeapAllocate( HeapHandle, Flags, Size ));
  317. try {
  318. try {
  319. //
  320. // Validate that HeapAddress points to a HEAP structure.
  321. //
  322. if (!RtlpCheckHeapSignature( Heap, "RtlAllocateHeap" )) {
  323. ReturnValue = NULL;
  324. leave;
  325. }
  326. Flags |= Heap->ForceFlags | HEAP_SETTABLE_USER_VALUE | HEAP_SKIP_VALIDATION_CHECKS;
  327. //
  328. // Verify that the size did not wrap or exceed the limit for this heap.
  329. //
  330. AllocationSize = (((Size ? Size : 1) + Heap->AlignRound) & Heap->AlignMask) +
  331. sizeof( HEAP_ENTRY_EXTRA );
  332. if ((AllocationSize < Size) || (AllocationSize > Heap->MaximumAllocationSize)) {
  333. HeapDebugPrint(( "Invalid allocation size - %p (exceeded %x)\n",
  334. Size,
  335. Heap->MaximumAllocationSize ));
  336. ReturnValue = NULL;
  337. leave;
  338. }
  339. //
  340. // Lock the heap
  341. //
  342. if (!(Flags & HEAP_NO_SERIALIZE)) {
  343. RtlAcquireLockRoutine( Heap->LockVariable );
  344. LockAcquired = TRUE;
  345. Flags |= HEAP_NO_SERIALIZE;
  346. }
  347. RtlpValidateHeap( Heap, FALSE );
  348. ReturnValue = RtlAllocateHeapSlowly( HeapHandle, Flags, Size );
  349. RtlpValidateHeapHeaders( Heap, TRUE );
  350. if (ReturnValue != NULL) {
  351. BusyBlock = (PHEAP_ENTRY)ReturnValue - 1;
  352. if (BusyBlock->Flags & HEAP_ENTRY_EXTRA_PRESENT) {
  353. ExtraStuff = RtlpGetExtraStuffPointer( BusyBlock );
  354. if (Heap->Flags & HEAP_CAPTURE_STACK_BACKTRACES) {
  355. ExtraStuff->AllocatorBackTraceIndex = (USHORT)RtlLogStackBackTrace();
  356. } else {
  357. ExtraStuff->AllocatorBackTraceIndex = 0;
  358. }
  359. TagIndex = ExtraStuff->TagIndex;
  360. } else {
  361. TagIndex = RtlpGetSmallTagIndex( Heap, BusyBlock );
  362. }
  363. if (Heap->Flags & HEAP_VALIDATE_ALL_ENABLED) {
  364. RtlpValidateHeap( Heap, FALSE );
  365. }
  366. }
  367. if (ReturnValue != NULL) {
  368. if ((ULONG_PTR)ReturnValue == RtlpHeapStopOn.AllocAddress) {
  369. HeapDebugPrint(( "Just allocated block at %p for 0x%x bytes\n",
  370. RtlpHeapStopOn.AllocAddress,
  371. Size ));
  372. HeapDebugBreak( NULL );
  373. } else if ((IS_HEAP_TAGGING_ENABLED()) &&
  374. (TagIndex != 0) &&
  375. (TagIndex == RtlpHeapStopOn.AllocTag.TagIndex) &&
  376. (Heap->ProcessHeapsListIndex == RtlpHeapStopOn.AllocTag.HeapIndex)) {
  377. HeapDebugPrint(( "Just allocated block at %p for 0x%x bytes with tag %ws\n",
  378. ReturnValue,
  379. Size,
  380. RtlpGetTagName( Heap, TagIndex )));
  381. HeapDebugBreak( NULL );
  382. }
  383. }
  384. } except( GetExceptionCode() == STATUS_NO_MEMORY ? EXCEPTION_CONTINUE_SEARCH :
  385. EXCEPTION_EXECUTE_HANDLER ) {
  386. SET_LAST_STATUS( GetExceptionCode() );
  387. ReturnValue = NULL;
  388. }
  389. } finally {
  390. if (LockAcquired) {
  391. RtlReleaseLockRoutine( Heap->LockVariable );
  392. }
  393. }
  394. return ReturnValue;
  395. }
  396. PVOID
  397. RtlDebugReAllocateHeap (
  398. IN PVOID HeapHandle,
  399. IN ULONG Flags,
  400. IN PVOID BaseAddress,
  401. IN SIZE_T Size
  402. )
  403. /*++
  404. Routine Description:
  405. Arguments:
  406. Return Value:
  407. --*/
  408. {
  409. PHEAP Heap = (PHEAP)HeapHandle;
  410. SIZE_T AllocationSize;
  411. PHEAP_ENTRY BusyBlock;
  412. PHEAP_ENTRY_EXTRA ExtraStuff;
  413. BOOLEAN LockAcquired = FALSE;
  414. PVOID ReturnValue = NULL;
  415. USHORT TagIndex;
  416. IF_DEBUG_PAGE_HEAP_THEN_RETURN( HeapHandle,
  417. RtlpDebugPageHeapReAllocate( HeapHandle, Flags, BaseAddress, Size ));
  418. try {
  419. try {
  420. //
  421. // Validate that HeapAddress points to a HEAP structure.
  422. //
  423. if (!RtlpCheckHeapSignature( Heap, "RtlReAllocateHeap" )) {
  424. ReturnValue = NULL;
  425. leave;
  426. }
  427. Flags |= Heap->ForceFlags | HEAP_SETTABLE_USER_VALUE | HEAP_SKIP_VALIDATION_CHECKS;
  428. //
  429. // Verify that the size did not wrap or exceed the limit for this heap.
  430. //
  431. AllocationSize = (((Size ? Size : 1) + Heap->AlignRound) & Heap->AlignMask) +
  432. sizeof( HEAP_ENTRY_EXTRA );
  433. if (AllocationSize < Size || AllocationSize > Heap->MaximumAllocationSize) {
  434. HeapDebugPrint(( "Invalid allocation size - %p (exceeded %x)\n",
  435. Size,
  436. Heap->MaximumAllocationSize ));
  437. HeapDebugBreak( NULL );
  438. ReturnValue = NULL;
  439. leave;
  440. }
  441. //
  442. // Lock the heap
  443. //
  444. if (!(Flags & HEAP_NO_SERIALIZE)) {
  445. RtlAcquireLockRoutine( Heap->LockVariable );
  446. LockAcquired = TRUE;
  447. Flags |= HEAP_NO_SERIALIZE;
  448. }
  449. RtlpValidateHeap( Heap, FALSE );
  450. BusyBlock = (PHEAP_ENTRY)BaseAddress - 1;
  451. if (RtlpValidateHeapEntry( Heap, BusyBlock, "RtlReAllocateHeap" )) {
  452. if ((ULONG_PTR)BaseAddress == RtlpHeapStopOn.ReAllocAddress) {
  453. HeapDebugPrint(( "About to reallocate block at %p to 0x%x bytes\n",
  454. RtlpHeapStopOn.ReAllocAddress,
  455. Size ));
  456. HeapDebugBreak( NULL );
  457. } else if (IS_HEAP_TAGGING_ENABLED() && RtlpHeapStopOn.ReAllocTag.HeapAndTagIndex != 0) {
  458. if (BusyBlock->Flags & HEAP_ENTRY_EXTRA_PRESENT) {
  459. ExtraStuff = RtlpGetExtraStuffPointer( BusyBlock );
  460. TagIndex = ExtraStuff->TagIndex;
  461. } else {
  462. TagIndex = RtlpGetSmallTagIndex( Heap, BusyBlock);
  463. }
  464. if ((TagIndex != 0) &&
  465. (TagIndex == RtlpHeapStopOn.ReAllocTag.TagIndex) &&
  466. (Heap->ProcessHeapsListIndex == RtlpHeapStopOn.ReAllocTag.HeapIndex)) {
  467. HeapDebugPrint(( "About to rellocate block at %p to 0x%x bytes with tag %ws\n",
  468. BaseAddress,
  469. Size,
  470. RtlpGetTagName( Heap, TagIndex )));
  471. HeapDebugBreak( NULL );
  472. }
  473. }
  474. ReturnValue = RtlReAllocateHeap( HeapHandle, Flags, BaseAddress, Size );
  475. if (ReturnValue != NULL) {
  476. BusyBlock = (PHEAP_ENTRY)ReturnValue - 1;
  477. if (BusyBlock->Flags & HEAP_ENTRY_EXTRA_PRESENT) {
  478. ExtraStuff = RtlpGetExtraStuffPointer( BusyBlock );
  479. if (Heap->Flags & HEAP_CAPTURE_STACK_BACKTRACES) {
  480. ExtraStuff->AllocatorBackTraceIndex = (USHORT)RtlLogStackBackTrace();
  481. } else {
  482. ExtraStuff->AllocatorBackTraceIndex = 0;
  483. }
  484. TagIndex = ExtraStuff->TagIndex;
  485. } else {
  486. TagIndex = RtlpGetSmallTagIndex( Heap, BusyBlock );
  487. }
  488. }
  489. RtlpValidateHeapHeaders( Heap, TRUE );
  490. RtlpValidateHeap( Heap, FALSE );
  491. }
  492. if (ReturnValue != NULL) {
  493. if ((ULONG_PTR)ReturnValue == RtlpHeapStopOn.ReAllocAddress) {
  494. HeapDebugPrint(( "Just reallocated block at %p to 0x%x bytes\n",
  495. RtlpHeapStopOn.ReAllocAddress,
  496. Size ));
  497. HeapDebugBreak( NULL );
  498. } else if ((IS_HEAP_TAGGING_ENABLED()) &&
  499. (TagIndex == RtlpHeapStopOn.ReAllocTag.TagIndex) &&
  500. (Heap->ProcessHeapsListIndex == RtlpHeapStopOn.ReAllocTag.HeapIndex)) {
  501. HeapDebugPrint(( "Just reallocated block at %p to 0x%x bytes with tag %ws\n",
  502. ReturnValue,
  503. Size,
  504. RtlpGetTagName( Heap, TagIndex )));
  505. HeapDebugBreak( NULL );
  506. }
  507. }
  508. } except( GetExceptionCode() == STATUS_NO_MEMORY ? EXCEPTION_CONTINUE_SEARCH :
  509. EXCEPTION_EXECUTE_HANDLER ) {
  510. SET_LAST_STATUS( GetExceptionCode() );
  511. ReturnValue = NULL;
  512. }
  513. } finally {
  514. if (LockAcquired) {
  515. RtlReleaseLockRoutine( Heap->LockVariable );
  516. }
  517. }
  518. return ReturnValue;
  519. }
  520. BOOLEAN
  521. RtlDebugFreeHeap (
  522. IN PVOID HeapHandle,
  523. IN ULONG Flags,
  524. IN PVOID BaseAddress
  525. )
  526. /*++
  527. Routine Description:
  528. Arguments:
  529. Return Value:
  530. --*/
  531. {
  532. PHEAP Heap = (PHEAP)HeapHandle;
  533. PHEAP_ENTRY BusyBlock;
  534. PHEAP_ENTRY_EXTRA ExtraStuff;
  535. SIZE_T Size;
  536. BOOLEAN Result = FALSE;
  537. BOOLEAN LockAcquired = FALSE;
  538. USHORT TagIndex;
  539. IF_DEBUG_PAGE_HEAP_THEN_RETURN( HeapHandle,
  540. RtlpDebugPageHeapFree( HeapHandle, Flags, BaseAddress ));
  541. try {
  542. try {
  543. //
  544. // Validate that HeapAddress points to a HEAP structure.
  545. //
  546. if (!RtlpCheckHeapSignature( Heap, "RtlFreeHeap" )) {
  547. Result = FALSE;
  548. leave;
  549. }
  550. Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS;
  551. //
  552. // Lock the heap
  553. //
  554. if (!(Flags & HEAP_NO_SERIALIZE)) {
  555. RtlAcquireLockRoutine( Heap->LockVariable );
  556. LockAcquired = TRUE;
  557. Flags |= HEAP_NO_SERIALIZE;
  558. }
  559. RtlpValidateHeap( Heap, FALSE );
  560. BusyBlock = (PHEAP_ENTRY)BaseAddress - 1;
  561. Size = BusyBlock->Size << HEAP_GRANULARITY_SHIFT;
  562. if (RtlpValidateHeapEntry( Heap, BusyBlock, "RtlFreeHeap" )) {
  563. if ((ULONG_PTR)BaseAddress == RtlpHeapStopOn.FreeAddress) {
  564. HeapDebugPrint(( "About to free block at %p\n",
  565. RtlpHeapStopOn.FreeAddress ));
  566. HeapDebugBreak( NULL );
  567. } else if ((IS_HEAP_TAGGING_ENABLED()) && (RtlpHeapStopOn.FreeTag.HeapAndTagIndex != 0)) {
  568. if (BusyBlock->Flags & HEAP_ENTRY_EXTRA_PRESENT) {
  569. ExtraStuff = RtlpGetExtraStuffPointer( BusyBlock );
  570. TagIndex = ExtraStuff->TagIndex;
  571. } else {
  572. TagIndex = RtlpGetSmallTagIndex( Heap, BusyBlock );
  573. }
  574. if ((TagIndex != 0) &&
  575. (TagIndex == RtlpHeapStopOn.FreeTag.TagIndex) &&
  576. (Heap->ProcessHeapsListIndex == RtlpHeapStopOn.FreeTag.HeapIndex)) {
  577. HeapDebugPrint(( "About to free block at %p with tag %ws\n",
  578. BaseAddress,
  579. RtlpGetTagName( Heap, TagIndex )));
  580. HeapDebugBreak( NULL );
  581. }
  582. }
  583. Result = RtlFreeHeapSlowly( HeapHandle, Flags, BaseAddress );
  584. RtlpValidateHeapHeaders( Heap, TRUE );
  585. RtlpValidateHeap( Heap, FALSE );
  586. }
  587. } except( RtlpHeapExceptionFilter(GetExceptionCode()) ) {
  588. SET_LAST_STATUS( GetExceptionCode() );
  589. Result = FALSE;
  590. }
  591. } finally {
  592. if (LockAcquired) {
  593. RtlReleaseLockRoutine( Heap->LockVariable );
  594. }
  595. }
  596. return Result;
  597. }
  598. BOOLEAN
  599. RtlDebugGetUserInfoHeap (
  600. IN PVOID HeapHandle,
  601. IN ULONG Flags,
  602. IN PVOID BaseAddress,
  603. OUT PVOID *UserValue OPTIONAL,
  604. OUT PULONG UserFlags OPTIONAL
  605. )
  606. /*++
  607. Routine Description:
  608. Arguments:
  609. Return Value:
  610. --*/
  611. {
  612. PHEAP Heap = (PHEAP)HeapHandle;
  613. PHEAP_ENTRY BusyBlock;
  614. BOOLEAN Result = FALSE;
  615. BOOLEAN LockAcquired = FALSE;
  616. IF_DEBUG_PAGE_HEAP_THEN_RETURN( HeapHandle,
  617. RtlpDebugPageHeapGetUserInfo( HeapHandle, Flags, BaseAddress, UserValue, UserFlags ));
  618. try {
  619. try {
  620. //
  621. // Validate that HeapAddress points to a HEAP structure.
  622. //
  623. if (!RtlpCheckHeapSignature( Heap, "RtlGetUserInfoHeap" )) {
  624. Result = FALSE;
  625. leave;
  626. }
  627. Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS;
  628. //
  629. // Lock the heap
  630. //
  631. if (!(Flags & HEAP_NO_SERIALIZE)) {
  632. RtlAcquireLockRoutine( Heap->LockVariable );
  633. LockAcquired = TRUE;
  634. Flags |= HEAP_NO_SERIALIZE;
  635. }
  636. RtlpValidateHeap( Heap, FALSE );
  637. BusyBlock = (PHEAP_ENTRY)BaseAddress - 1;
  638. if (RtlpValidateHeapEntry( Heap, BusyBlock, "RtlGetUserInfoHeap" )) {
  639. Result = RtlGetUserInfoHeap( HeapHandle, Flags, BaseAddress, UserValue, UserFlags );
  640. }
  641. } except( RtlpHeapExceptionFilter(GetExceptionCode()) ) {
  642. SET_LAST_STATUS( GetExceptionCode() );
  643. }
  644. } finally {
  645. if (LockAcquired) {
  646. RtlReleaseLockRoutine( Heap->LockVariable );
  647. }
  648. }
  649. return Result;
  650. }
  651. BOOLEAN
  652. RtlDebugSetUserValueHeap (
  653. IN PVOID HeapHandle,
  654. IN ULONG Flags,
  655. IN PVOID BaseAddress,
  656. IN PVOID UserValue
  657. )
  658. /*++
  659. Routine Description:
  660. Arguments:
  661. Return Value:
  662. --*/
  663. {
  664. PHEAP Heap = (PHEAP)HeapHandle;
  665. PHEAP_ENTRY BusyBlock;
  666. BOOLEAN Result = FALSE;
  667. BOOLEAN LockAcquired = FALSE;
  668. IF_DEBUG_PAGE_HEAP_THEN_RETURN( HeapHandle,
  669. RtlpDebugPageHeapSetUserValue( HeapHandle, Flags, BaseAddress, UserValue ));
  670. try {
  671. try {
  672. //
  673. // Validate that HeapAddress points to a HEAP structure.
  674. //
  675. if (!RtlpCheckHeapSignature( Heap, "RtlSetUserValueHeap" )) {
  676. Result = FALSE;
  677. leave;
  678. }
  679. Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS;
  680. //
  681. // Lock the heap
  682. //
  683. if (!(Flags & HEAP_NO_SERIALIZE)) {
  684. RtlAcquireLockRoutine( Heap->LockVariable );
  685. LockAcquired = TRUE;
  686. Flags |= HEAP_NO_SERIALIZE;
  687. }
  688. RtlpValidateHeap( Heap, FALSE );
  689. BusyBlock = (PHEAP_ENTRY)BaseAddress - 1;
  690. if (RtlpValidateHeapEntry( Heap, BusyBlock, "RtlSetUserValueHeap" )) {
  691. Result = RtlSetUserValueHeap( HeapHandle, Flags, BaseAddress, UserValue );
  692. RtlpValidateHeap( Heap, FALSE );
  693. }
  694. } except( RtlpHeapExceptionFilter(GetExceptionCode()) ) {
  695. SET_LAST_STATUS( GetExceptionCode() );
  696. }
  697. } finally {
  698. if (LockAcquired) {
  699. RtlReleaseLockRoutine( Heap->LockVariable );
  700. }
  701. }
  702. return Result;
  703. }
  704. BOOLEAN
  705. RtlDebugSetUserFlagsHeap (
  706. IN PVOID HeapHandle,
  707. IN ULONG Flags,
  708. IN PVOID BaseAddress,
  709. IN ULONG UserFlagsReset,
  710. IN ULONG UserFlagsSet
  711. )
  712. /*++
  713. Routine Description:
  714. Arguments:
  715. Return Value:
  716. --*/
  717. {
  718. PHEAP Heap = (PHEAP)HeapHandle;
  719. PHEAP_ENTRY BusyBlock;
  720. BOOLEAN Result = FALSE;
  721. BOOLEAN LockAcquired = FALSE;
  722. IF_DEBUG_PAGE_HEAP_THEN_RETURN( HeapHandle,
  723. RtlpDebugPageHeapSetUserFlags( HeapHandle, Flags, BaseAddress, UserFlagsReset, UserFlagsSet ));
  724. if ((UserFlagsReset & ~HEAP_SETTABLE_USER_FLAGS) ||
  725. (UserFlagsSet & ~HEAP_SETTABLE_USER_FLAGS)) {
  726. return FALSE;
  727. }
  728. try {
  729. try {
  730. //
  731. // Validate that HeapAddress points to a HEAP structure.
  732. //
  733. if (!RtlpCheckHeapSignature( Heap, "RtlSetUserFlagsHeap" )) {
  734. Result = FALSE;
  735. leave;
  736. }
  737. Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS;
  738. //
  739. // Lock the heap
  740. //
  741. if (!(Flags & HEAP_NO_SERIALIZE)) {
  742. RtlAcquireLockRoutine( Heap->LockVariable );
  743. LockAcquired = TRUE;
  744. Flags |= HEAP_NO_SERIALIZE;
  745. }
  746. RtlpValidateHeap( Heap, FALSE );
  747. BusyBlock = (PHEAP_ENTRY)BaseAddress - 1;
  748. if (RtlpValidateHeapEntry( Heap, BusyBlock, "RtlSetUserFlagsHeap" )) {
  749. Result = RtlSetUserFlagsHeap( HeapHandle, Flags, BaseAddress, UserFlagsReset, UserFlagsSet );
  750. RtlpValidateHeap( Heap, FALSE );
  751. }
  752. } except( RtlpHeapExceptionFilter(GetExceptionCode()) ) {
  753. SET_LAST_STATUS( GetExceptionCode() );
  754. }
  755. } finally {
  756. if (LockAcquired) {
  757. RtlReleaseLockRoutine( Heap->LockVariable );
  758. }
  759. }
  760. return Result;
  761. }
  762. SIZE_T
  763. RtlDebugSizeHeap (
  764. IN PVOID HeapHandle,
  765. IN ULONG Flags,
  766. IN PVOID BaseAddress
  767. )
  768. /*++
  769. Routine Description:
  770. Arguments:
  771. Return Value:
  772. --*/
  773. {
  774. PHEAP Heap = (PHEAP)HeapHandle;
  775. PHEAP_ENTRY BusyBlock;
  776. BOOLEAN LockAcquired = FALSE;
  777. SIZE_T BusySize;
  778. IF_DEBUG_PAGE_HEAP_THEN_RETURN( HeapHandle,
  779. RtlpDebugPageHeapSize( HeapHandle, Flags, BaseAddress ));
  780. BusySize = 0xFFFFFFFF;
  781. try {
  782. try {
  783. //
  784. // Validate that HeapAddress points to a HEAP structure.
  785. //
  786. if (!RtlpCheckHeapSignature( Heap, "RtlSizeHeap" )) {
  787. BusySize = FALSE;
  788. leave;
  789. }
  790. Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS;
  791. //
  792. // Lock the heap
  793. //
  794. if (!(Flags & HEAP_NO_SERIALIZE)) {
  795. RtlAcquireLockRoutine( Heap->LockVariable );
  796. Flags |= HEAP_NO_SERIALIZE;
  797. LockAcquired = TRUE;
  798. }
  799. RtlpValidateHeap( Heap, FALSE );
  800. BusyBlock = (PHEAP_ENTRY)BaseAddress - 1;
  801. if (RtlpValidateHeapEntry( Heap, BusyBlock, "RtlSizeHeap" )) {
  802. BusySize = RtlSizeHeap( HeapHandle, Flags, BaseAddress );
  803. }
  804. } except( RtlpHeapExceptionFilter(GetExceptionCode()) ) {
  805. SET_LAST_STATUS( GetExceptionCode() );
  806. }
  807. } finally {
  808. if (LockAcquired) {
  809. RtlReleaseLockRoutine( Heap->LockVariable );
  810. }
  811. }
  812. return BusySize;
  813. }
  814. SIZE_T
  815. RtlDebugCompactHeap (
  816. IN PVOID HeapHandle,
  817. IN ULONG Flags
  818. )
  819. /*++
  820. Routine Description:
  821. Arguments:
  822. Return Value:
  823. --*/
  824. {
  825. PHEAP Heap = (PHEAP)HeapHandle;
  826. BOOLEAN LockAcquired = FALSE;
  827. SIZE_T LargestFreeSize;
  828. IF_DEBUG_PAGE_HEAP_THEN_RETURN( HeapHandle,
  829. RtlpDebugPageHeapCompact( HeapHandle, Flags ));
  830. LargestFreeSize = 0;
  831. try {
  832. try {
  833. //
  834. // Validate that HeapAddress points to a HEAP structure.
  835. //
  836. if (!RtlpCheckHeapSignature( Heap, "RtlCompactHeap" )) {
  837. LargestFreeSize = 0;
  838. leave;
  839. }
  840. Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS;
  841. //
  842. // Lock the heap
  843. //
  844. if (!(Flags & HEAP_NO_SERIALIZE)) {
  845. RtlAcquireLockRoutine( Heap->LockVariable );
  846. LockAcquired = TRUE;
  847. Flags |= HEAP_NO_SERIALIZE;
  848. }
  849. RtlpValidateHeap( Heap, FALSE );
  850. LargestFreeSize = RtlCompactHeap( HeapHandle, Flags );
  851. RtlpValidateHeapHeaders( Heap, TRUE );
  852. } except( RtlpHeapExceptionFilter(GetExceptionCode()) ) {
  853. SET_LAST_STATUS( GetExceptionCode() );
  854. }
  855. } finally {
  856. if (LockAcquired) {
  857. RtlReleaseLockRoutine( Heap->LockVariable );
  858. }
  859. }
  860. return LargestFreeSize;
  861. }
  862. NTSTATUS
  863. RtlDebugZeroHeap (
  864. IN PVOID HeapHandle,
  865. IN ULONG Flags
  866. )
  867. /*++
  868. Routine Description:
  869. Arguments:
  870. Return Value:
  871. --*/
  872. {
  873. NTSTATUS Status;
  874. PHEAP Heap = (PHEAP)HeapHandle;
  875. BOOLEAN LockAcquired = FALSE;
  876. SIZE_T LargestFreeSize;
  877. IF_DEBUG_PAGE_HEAP_THEN_RETURN( HeapHandle,
  878. RtlpDebugPageHeapZero( HeapHandle, Flags ));
  879. Status = STATUS_SUCCESS;
  880. LargestFreeSize = 0;
  881. try {
  882. try {
  883. //
  884. // Validate that HeapAddress points to a HEAP structure.
  885. //
  886. if (!RtlpCheckHeapSignature( Heap, "RtlZeroHeap" )) {
  887. Status = STATUS_INVALID_PARAMETER;
  888. leave;
  889. }
  890. Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS;
  891. //
  892. // Lock the heap
  893. //
  894. if (!(Flags & HEAP_NO_SERIALIZE)) {
  895. RtlAcquireLockRoutine( Heap->LockVariable );
  896. LockAcquired = TRUE;
  897. Flags |= HEAP_NO_SERIALIZE;
  898. }
  899. if (!RtlpValidateHeap( Heap, FALSE )) {
  900. Status = STATUS_INVALID_PARAMETER;
  901. } else {
  902. Status = RtlZeroHeap( HeapHandle, Flags );
  903. }
  904. } except( RtlpHeapExceptionFilter(GetExceptionCode()) ) {
  905. Status = GetExceptionCode();
  906. }
  907. } finally {
  908. if (LockAcquired) {
  909. RtlReleaseLockRoutine( Heap->LockVariable );
  910. }
  911. }
  912. return Status;
  913. }
  914. NTSTATUS
  915. RtlDebugCreateTagHeap (
  916. IN PVOID HeapHandle,
  917. IN ULONG Flags,
  918. IN PWSTR TagPrefix OPTIONAL,
  919. IN PWSTR TagNames
  920. )
  921. /*++
  922. Routine Description:
  923. Arguments:
  924. Return Value:
  925. --*/
  926. {
  927. PHEAP Heap = (PHEAP)HeapHandle;
  928. BOOLEAN LockAcquired = FALSE;
  929. ULONG TagIndex;
  930. TagIndex = 0;
  931. try {
  932. try {
  933. //
  934. // Validate that HeapAddress points to a HEAP structure.
  935. //
  936. if (RtlpCheckHeapSignature( Heap, "RtlCreateTagHeap" )) {
  937. Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS;
  938. //
  939. // Lock the heap
  940. //
  941. if (!(Flags & HEAP_NO_SERIALIZE)) {
  942. RtlAcquireLockRoutine( Heap->LockVariable );
  943. LockAcquired = TRUE;
  944. Flags |= HEAP_NO_SERIALIZE;
  945. }
  946. if (RtlpValidateHeap( Heap, FALSE )) {
  947. TagIndex = RtlCreateTagHeap( HeapHandle, Flags, TagPrefix, TagNames );
  948. }
  949. RtlpValidateHeapHeaders( Heap, TRUE );
  950. }
  951. } except( RtlpHeapExceptionFilter(GetExceptionCode()) ) {
  952. SET_LAST_STATUS( GetExceptionCode() );
  953. }
  954. } finally {
  955. if (LockAcquired) {
  956. RtlReleaseLockRoutine( Heap->LockVariable );
  957. }
  958. }
  959. return TagIndex;
  960. }
  961. NTSYSAPI
  962. PWSTR
  963. NTAPI
  964. RtlDebugQueryTagHeap (
  965. IN PVOID HeapHandle,
  966. IN ULONG Flags,
  967. IN USHORT TagIndex,
  968. IN BOOLEAN ResetCounters,
  969. OUT PRTL_HEAP_TAG_INFO TagInfo OPTIONAL
  970. )
  971. /*++
  972. Routine Description:
  973. Arguments:
  974. Return Value:
  975. --*/
  976. {
  977. PHEAP Heap = (PHEAP)HeapHandle;
  978. BOOLEAN LockAcquired = FALSE;
  979. PWSTR Result;
  980. Result = NULL;
  981. try {
  982. try {
  983. //
  984. // Validate that HeapAddress points to a HEAP structure.
  985. //
  986. if (RtlpCheckHeapSignature( Heap, "RtlQueryTagHeap" )) {
  987. Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS;
  988. //
  989. // Lock the heap
  990. //
  991. if (!(Flags & HEAP_NO_SERIALIZE)) {
  992. RtlAcquireLockRoutine( Heap->LockVariable );
  993. LockAcquired = TRUE;
  994. Flags |= HEAP_NO_SERIALIZE;
  995. }
  996. if (RtlpValidateHeap( Heap, FALSE )) {
  997. Result = RtlQueryTagHeap( HeapHandle, Flags, TagIndex, ResetCounters, TagInfo );
  998. }
  999. }
  1000. } except( RtlpHeapExceptionFilter(GetExceptionCode()) ) {
  1001. SET_LAST_STATUS( GetExceptionCode() );
  1002. }
  1003. } finally {
  1004. if (LockAcquired) {
  1005. RtlReleaseLockRoutine( Heap->LockVariable );
  1006. }
  1007. }
  1008. return Result;
  1009. }
  1010. NTSTATUS
  1011. RtlDebugUsageHeap (
  1012. IN PVOID HeapHandle,
  1013. IN ULONG Flags,
  1014. IN OUT PRTL_HEAP_USAGE Usage
  1015. )
  1016. /*++
  1017. Routine Description:
  1018. Arguments:
  1019. Return Value:
  1020. --*/
  1021. {
  1022. PHEAP Heap = (PHEAP)HeapHandle;
  1023. NTSTATUS Status;
  1024. BOOLEAN LockAcquired = FALSE;
  1025. IF_DEBUG_PAGE_HEAP_THEN_RETURN( HeapHandle,
  1026. RtlpDebugPageHeapUsage( HeapHandle, Flags, Usage ));
  1027. Status = STATUS_SUCCESS;
  1028. try {
  1029. try {
  1030. //
  1031. // Validate that HeapAddress points to a HEAP structure.
  1032. //
  1033. if (!RtlpCheckHeapSignature( Heap, "RtlUsageHeap" )) {
  1034. Status = STATUS_INVALID_PARAMETER;
  1035. leave;
  1036. }
  1037. Flags |= Heap->ForceFlags | HEAP_SKIP_VALIDATION_CHECKS;
  1038. //
  1039. // Lock the heap
  1040. //
  1041. if (!(Flags & HEAP_NO_SERIALIZE)) {
  1042. RtlAcquireLockRoutine( Heap->LockVariable );
  1043. LockAcquired = TRUE;
  1044. Flags |= HEAP_NO_SERIALIZE;
  1045. }
  1046. if (!RtlpValidateHeap( Heap, FALSE )) {
  1047. Status = STATUS_INVALID_PARAMETER;
  1048. } else {
  1049. Status = RtlUsageHeap( HeapHandle, Flags, Usage );
  1050. }
  1051. } except( RtlpHeapExceptionFilter(GetExceptionCode()) ) {
  1052. Status = GetExceptionCode();
  1053. }
  1054. } finally {
  1055. if (LockAcquired) {
  1056. RtlReleaseLockRoutine( Heap->LockVariable );
  1057. }
  1058. }
  1059. return Status;
  1060. }
  1061. BOOLEAN
  1062. RtlDebugWalkHeap (
  1063. IN PVOID HeapHandle,
  1064. IN OUT PRTL_HEAP_WALK_ENTRY Entry
  1065. )
  1066. /*++
  1067. Routine Description:
  1068. Arguments:
  1069. Return Value:
  1070. --*/
  1071. {
  1072. PHEAP Heap = (PHEAP)HeapHandle;
  1073. BOOLEAN Result;
  1074. //
  1075. // Assumed the caller has serialized via RtlLockHeap or their own locking mechanism.
  1076. //
  1077. Result = FALSE;
  1078. try {
  1079. if (RtlpCheckHeapSignature( Heap, "RtlWalkHeap" )) {
  1080. Result = RtlpValidateHeap( Heap, FALSE );
  1081. }
  1082. } except( RtlpHeapExceptionFilter(GetExceptionCode()) ) {
  1083. SET_LAST_STATUS( GetExceptionCode() );
  1084. }
  1085. return Result;
  1086. }
  1087. BOOLEAN
  1088. RtlpValidateHeapEntry (
  1089. IN PHEAP Heap,
  1090. IN PHEAP_ENTRY BusyBlock,
  1091. IN PCHAR Reason
  1092. )
  1093. /*++
  1094. Routine Description:
  1095. Arguments:
  1096. Return Value:
  1097. --*/
  1098. {
  1099. PHEAP_SEGMENT Segment;
  1100. UCHAR SegmentIndex;
  1101. BOOLEAN Result;
  1102. if ((BusyBlock != NULL) &&
  1103. (BusyBlock->SegmentIndex == HEAP_LFH_INDEX)) {
  1104. if ((RtlpGetLowFragHeap(Heap) == NULL)
  1105. ||
  1106. ((ULONG_PTR)BusyBlock & (HEAP_GRANULARITY-1))
  1107. ||
  1108. (BusyBlock->Flags & HEAP_ENTRY_VIRTUAL_ALLOC)
  1109. ||
  1110. !(BusyBlock->Flags & HEAP_ENTRY_BUSY)) {
  1111. goto InvalidBlock;
  1112. }
  1113. return TRUE;
  1114. }
  1115. if ((BusyBlock == NULL)
  1116. ||
  1117. ((ULONG_PTR)BusyBlock & (HEAP_GRANULARITY-1))
  1118. ||
  1119. ((BusyBlock->Flags & HEAP_ENTRY_VIRTUAL_ALLOC) &&
  1120. ((ULONG_PTR)BusyBlock & (PAGE_SIZE-1)) != FIELD_OFFSET( HEAP_VIRTUAL_ALLOC_ENTRY, BusyBlock ))
  1121. ||
  1122. (!(BusyBlock->Flags & HEAP_ENTRY_VIRTUAL_ALLOC) &&
  1123. ((BusyBlock->SegmentIndex >= HEAP_MAXIMUM_SEGMENTS) ||
  1124. !(Segment = Heap->Segments[ BusyBlock->SegmentIndex ]) ||
  1125. (BusyBlock < Segment->FirstEntry) ||
  1126. (BusyBlock >= Segment->LastValidEntry)))
  1127. ||
  1128. !(BusyBlock->Flags & HEAP_ENTRY_BUSY)
  1129. ||
  1130. ((BusyBlock->Flags & HEAP_ENTRY_FILL_PATTERN) && !RtlpCheckBusyBlockTail( BusyBlock ))) {
  1131. InvalidBlock:
  1132. HeapDebugPrint(( "Invalid Address specified to %s( %p, %p )\n",
  1133. Reason,
  1134. Heap,
  1135. BusyBlock + 1 ));
  1136. HeapDebugBreak( BusyBlock );
  1137. return FALSE;
  1138. } else {
  1139. if (BusyBlock->Flags & HEAP_ENTRY_VIRTUAL_ALLOC) {
  1140. Result = TRUE;
  1141. } else {
  1142. for (SegmentIndex=0; SegmentIndex<HEAP_MAXIMUM_SEGMENTS; SegmentIndex++) {
  1143. Segment = Heap->Segments[ SegmentIndex ];
  1144. if (Segment) {
  1145. if ((BusyBlock >= Segment->FirstEntry) &&
  1146. (BusyBlock < Segment->LastValidEntry)) {
  1147. Result = TRUE;
  1148. break;
  1149. }
  1150. }
  1151. }
  1152. }
  1153. if (!Result) {
  1154. goto InvalidBlock;
  1155. }
  1156. return TRUE;
  1157. }
  1158. }
  1159. BOOLEAN
  1160. RtlpValidateHeapSegment (
  1161. IN PHEAP Heap,
  1162. IN PHEAP_SEGMENT Segment,
  1163. IN UCHAR SegmentIndex,
  1164. IN OUT PULONG CountOfFreeBlocks,
  1165. IN OUT PSIZE_T TotalFreeSize,
  1166. OUT PVOID *BadAddress,
  1167. IN OUT PSIZE_T ComputedTagEntries,
  1168. IN OUT PSIZE_T ComputedPseudoTagEntries
  1169. )
  1170. /*++
  1171. Routine Description:
  1172. Arguments:
  1173. Return Value:
  1174. --*/
  1175. {
  1176. PHEAP_ENTRY CurrentBlock, PreviousBlock;
  1177. SIZE_T Size;
  1178. USHORT PreviousSize, TagIndex;
  1179. PHEAP_UNCOMMMTTED_RANGE UnCommittedRange;
  1180. PHEAP_ENTRY_EXTRA ExtraStuff;
  1181. ULONG NumberOfUnCommittedPages;
  1182. ULONG NumberOfUnCommittedRanges;
  1183. RTL_PAGED_CODE();
  1184. NumberOfUnCommittedPages = 0;
  1185. NumberOfUnCommittedRanges = 0;
  1186. UnCommittedRange = Segment->UnCommittedRanges;
  1187. if (Segment->BaseAddress == Heap) {
  1188. CurrentBlock = &Heap->Entry;
  1189. } else {
  1190. CurrentBlock = &Segment->Entry;
  1191. }
  1192. while (CurrentBlock < Segment->LastValidEntry) {
  1193. *BadAddress = CurrentBlock;
  1194. if ((UnCommittedRange != NULL) &&
  1195. ((ULONG_PTR)CurrentBlock >= UnCommittedRange->Address)) {
  1196. HeapDebugPrint(( "Heap entry %p is beyond uncommited range [%x .. %x)\n",
  1197. CurrentBlock,
  1198. UnCommittedRange->Address,
  1199. (PCHAR)UnCommittedRange->Address + UnCommittedRange->Size ));
  1200. return FALSE;
  1201. }
  1202. PreviousSize = 0;
  1203. while (CurrentBlock < Segment->LastValidEntry) {
  1204. *BadAddress = CurrentBlock;
  1205. if (PreviousSize != CurrentBlock->PreviousSize) {
  1206. HeapDebugPrint(( "Heap entry %p has incorrect PreviousSize field (%04x instead of %04x)\n",
  1207. CurrentBlock, CurrentBlock->PreviousSize, PreviousSize ));
  1208. return FALSE;
  1209. }
  1210. PreviousSize = CurrentBlock->Size;
  1211. Size = (ULONG_PTR)CurrentBlock->Size << HEAP_GRANULARITY_SHIFT;
  1212. if (CurrentBlock->Flags & HEAP_ENTRY_BUSY) {
  1213. if (ComputedTagEntries != NULL) {
  1214. if (CurrentBlock->Flags & HEAP_ENTRY_EXTRA_PRESENT) {
  1215. ExtraStuff = RtlpGetExtraStuffPointer( CurrentBlock );
  1216. TagIndex = ExtraStuff->TagIndex;
  1217. } else {
  1218. TagIndex = RtlpGetSmallTagIndex( Heap, CurrentBlock );
  1219. }
  1220. if (TagIndex != 0) {
  1221. if (TagIndex & HEAP_PSEUDO_TAG_FLAG) {
  1222. TagIndex &= ~HEAP_PSEUDO_TAG_FLAG;
  1223. if (TagIndex < HEAP_NUMBER_OF_PSEUDO_TAG) {
  1224. ComputedPseudoTagEntries[ TagIndex ] += CurrentBlock->Size;
  1225. }
  1226. } else if (TagIndex & HEAP_GLOBAL_TAG) {
  1227. //
  1228. // Ignore these since they are global across more than
  1229. // one heap.
  1230. //
  1231. } else if (TagIndex < Heap->NextAvailableTagIndex) {
  1232. ComputedTagEntries[ TagIndex ] += CurrentBlock->Size;
  1233. }
  1234. }
  1235. }
  1236. if (CurrentBlock->Flags & HEAP_ENTRY_FILL_PATTERN) {
  1237. if (!RtlpCheckBusyBlockTail( CurrentBlock )) {
  1238. return FALSE;
  1239. }
  1240. }
  1241. } else {
  1242. *CountOfFreeBlocks += 1;
  1243. *TotalFreeSize += CurrentBlock->Size;
  1244. if ((Heap->Flags & HEAP_FREE_CHECKING_ENABLED) &&
  1245. (CurrentBlock->Flags & HEAP_ENTRY_FILL_PATTERN)) {
  1246. SIZE_T cb, cbEqual;
  1247. cb = Size - sizeof( HEAP_FREE_ENTRY );
  1248. if ((CurrentBlock->Flags & HEAP_ENTRY_EXTRA_PRESENT) &&
  1249. (cb > sizeof( HEAP_FREE_ENTRY_EXTRA ))) {
  1250. cb -= sizeof( HEAP_FREE_ENTRY_EXTRA );
  1251. }
  1252. cbEqual = RtlCompareMemoryUlong( (PCHAR)((PHEAP_FREE_ENTRY)CurrentBlock + 1),
  1253. cb,
  1254. FREE_HEAP_FILL );
  1255. if (cbEqual != cb) {
  1256. HeapDebugPrint(( "Free Heap block %p modified at %p after it was freed\n",
  1257. CurrentBlock,
  1258. (PCHAR)(CurrentBlock + 1) + cbEqual ));
  1259. return FALSE;
  1260. }
  1261. }
  1262. }
  1263. if (CurrentBlock->SegmentIndex != SegmentIndex) {
  1264. HeapDebugPrint(( "Heap block at %p has incorrect segment index (%x)\n",
  1265. CurrentBlock,
  1266. SegmentIndex ));
  1267. return FALSE;
  1268. }
  1269. if (CurrentBlock->Flags & HEAP_ENTRY_LAST_ENTRY) {
  1270. CurrentBlock = (PHEAP_ENTRY)((PCHAR)CurrentBlock + Size);
  1271. if (UnCommittedRange == NULL) {
  1272. if (CurrentBlock != Segment->LastValidEntry) {
  1273. HeapDebugPrint(( "Heap block at %p is not last block in segment (%x)\n",
  1274. CurrentBlock,
  1275. Segment->LastValidEntry ));
  1276. return FALSE;
  1277. }
  1278. } else if ((ULONG_PTR)CurrentBlock != UnCommittedRange->Address) {
  1279. HeapDebugPrint(( "Heap block at %p does not match address of next uncommitted address (%x)\n",
  1280. CurrentBlock,
  1281. UnCommittedRange->Address ));
  1282. return FALSE;
  1283. } else {
  1284. NumberOfUnCommittedPages += (ULONG) (UnCommittedRange->Size / PAGE_SIZE);
  1285. NumberOfUnCommittedRanges += 1;
  1286. CurrentBlock = (PHEAP_ENTRY)
  1287. ((PCHAR)UnCommittedRange->Address + UnCommittedRange->Size);
  1288. UnCommittedRange = UnCommittedRange->Next;
  1289. }
  1290. break;
  1291. }
  1292. CurrentBlock = (PHEAP_ENTRY)((PCHAR)CurrentBlock + Size);
  1293. }
  1294. }
  1295. *BadAddress = Segment;
  1296. if (Segment->NumberOfUnCommittedPages != NumberOfUnCommittedPages) {
  1297. HeapDebugPrint(( "Heap Segment at %p contains invalid NumberOfUnCommittedPages (%x != %x)\n",
  1298. Segment,
  1299. Segment->NumberOfUnCommittedPages,
  1300. NumberOfUnCommittedPages ));
  1301. return FALSE;
  1302. }
  1303. if (Segment->NumberOfUnCommittedRanges != NumberOfUnCommittedRanges) {
  1304. HeapDebugPrint(( "Heap Segment at %p contains invalid NumberOfUnCommittedRanges (%x != %x)\n",
  1305. Segment,
  1306. Segment->NumberOfUnCommittedRanges,
  1307. NumberOfUnCommittedRanges ));
  1308. return FALSE;
  1309. }
  1310. return TRUE;
  1311. }
  1312. BOOLEAN
  1313. RtlpValidateHeap (
  1314. IN PHEAP Heap,
  1315. IN BOOLEAN AlwaysValidate
  1316. )
  1317. /*++
  1318. Routine Description:
  1319. Arguments:
  1320. Return Value:
  1321. --*/
  1322. {
  1323. NTSTATUS Status;
  1324. PHEAP_SEGMENT Segment;
  1325. PLIST_ENTRY Head, Next;
  1326. PHEAP_FREE_ENTRY FreeBlock;
  1327. BOOLEAN EmptyFreeList;
  1328. ULONG NumberOfFreeListEntries;
  1329. ULONG CountOfFreeBlocks;
  1330. SIZE_T TotalFreeSize;
  1331. SIZE_T Size;
  1332. USHORT PreviousSize;
  1333. UCHAR SegmentIndex;
  1334. PVOID BadAddress;
  1335. PSIZE_T ComputedTagEntries = NULL;
  1336. PSIZE_T ComputedPseudoTagEntries = NULL;
  1337. PHEAP_VIRTUAL_ALLOC_ENTRY VirtualAllocBlock;
  1338. USHORT TagIndex;
  1339. RTL_PAGED_CODE();
  1340. BadAddress = Heap;
  1341. if (!RtlpValidateHeapHeaders( Heap, FALSE )) {
  1342. goto errorExit;
  1343. }
  1344. if (!AlwaysValidate && !(Heap->Flags & HEAP_VALIDATE_ALL_ENABLED)) {
  1345. goto exit;
  1346. }
  1347. NumberOfFreeListEntries = 0;
  1348. Head = &Heap->FreeLists[ 0 ];
  1349. for (Size = 0; Size < HEAP_MAXIMUM_FREELISTS; Size++) {
  1350. if (Size != 0) {
  1351. EmptyFreeList = (BOOLEAN)(IsListEmpty( Head ));
  1352. BadAddress = &Heap->u.FreeListsInUseBytes[ Size / 8 ];
  1353. if (Heap->u.FreeListsInUseBytes[ Size / 8 ] & (1 << (Size & 7)) ) {
  1354. if (EmptyFreeList) {
  1355. HeapDebugPrint(( "dedicated (%04x) free list empty but marked as non-empty\n",
  1356. Size ));
  1357. goto errorExit;
  1358. }
  1359. } else {
  1360. if (!EmptyFreeList) {
  1361. HeapDebugPrint(( "dedicated (%04x) free list non-empty but marked as empty\n",
  1362. Size ));
  1363. goto errorExit;
  1364. }
  1365. }
  1366. }
  1367. Next = Head->Flink;
  1368. PreviousSize = 0;
  1369. while (Head != Next) {
  1370. FreeBlock = CONTAINING_RECORD( Next, HEAP_FREE_ENTRY, FreeList );
  1371. Next = Next->Flink;
  1372. BadAddress = FreeBlock;
  1373. if (FreeBlock->Flags & HEAP_ENTRY_BUSY) {
  1374. HeapDebugPrint(( "dedicated (%04x) free list element %p is marked busy\n",
  1375. Size,
  1376. FreeBlock ));
  1377. goto errorExit;
  1378. }
  1379. if ((Size != 0) && (FreeBlock->Size != Size)) {
  1380. HeapDebugPrint(( "Dedicated (%04x) free list element %p is wrong size (%04x)\n",
  1381. Size,
  1382. FreeBlock,
  1383. FreeBlock->Size ));
  1384. goto errorExit;
  1385. } else if ((Size == 0) && (FreeBlock->Size < HEAP_MAXIMUM_FREELISTS)) {
  1386. HeapDebugPrint(( "Non-Dedicated free list element %p with too small size (%04x)\n",
  1387. FreeBlock,
  1388. FreeBlock->Size ));
  1389. goto errorExit;
  1390. } else if ((Size == 0) && (FreeBlock->Size < PreviousSize)) {
  1391. HeapDebugPrint(( "Non-Dedicated free list element %p is out of order\n",
  1392. FreeBlock ));
  1393. goto errorExit;
  1394. } else {
  1395. PreviousSize = FreeBlock->Size;
  1396. }
  1397. NumberOfFreeListEntries++;
  1398. }
  1399. Head++;
  1400. }
  1401. Size = (HEAP_NUMBER_OF_PSEUDO_TAG + Heap->NextAvailableTagIndex + 1) * sizeof( SIZE_T );
  1402. if ((RtlpValidateHeapTagsEnable) && (Heap->PseudoTagEntries != NULL)) {
  1403. Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  1404. &ComputedPseudoTagEntries,
  1405. 0,
  1406. &Size,
  1407. MEM_COMMIT,
  1408. PAGE_READWRITE );
  1409. if (NT_SUCCESS( Status )) {
  1410. ComputedTagEntries = ComputedPseudoTagEntries + HEAP_NUMBER_OF_PSEUDO_TAG;
  1411. }
  1412. }
  1413. Head = &Heap->VirtualAllocdBlocks;
  1414. Next = Head->Flink;
  1415. while (Head != Next) {
  1416. VirtualAllocBlock = CONTAINING_RECORD( Next, HEAP_VIRTUAL_ALLOC_ENTRY, Entry );
  1417. if (ComputedTagEntries != NULL) {
  1418. TagIndex = VirtualAllocBlock->ExtraStuff.TagIndex;
  1419. if (TagIndex != 0) {
  1420. if (TagIndex & HEAP_PSEUDO_TAG_FLAG) {
  1421. TagIndex &= ~HEAP_PSEUDO_TAG_FLAG;
  1422. if (TagIndex < HEAP_NUMBER_OF_PSEUDO_TAG) {
  1423. ComputedPseudoTagEntries[ TagIndex ] +=
  1424. VirtualAllocBlock->CommitSize >> HEAP_GRANULARITY_SHIFT;
  1425. }
  1426. } else if (TagIndex & HEAP_GLOBAL_TAG) {
  1427. //
  1428. // Ignore these since they are global across more than
  1429. // one heap.
  1430. //
  1431. } else if (TagIndex < Heap->NextAvailableTagIndex) {
  1432. ComputedTagEntries[ TagIndex ] +=
  1433. VirtualAllocBlock->CommitSize >> HEAP_GRANULARITY_SHIFT;
  1434. }
  1435. }
  1436. }
  1437. if (VirtualAllocBlock->BusyBlock.Flags & HEAP_ENTRY_FILL_PATTERN) {
  1438. if (!RtlpCheckBusyBlockTail( &VirtualAllocBlock->BusyBlock )) {
  1439. return FALSE;
  1440. }
  1441. }
  1442. Next = Next->Flink;
  1443. }
  1444. CountOfFreeBlocks = 0;
  1445. TotalFreeSize = 0;
  1446. for (SegmentIndex=0; SegmentIndex<HEAP_MAXIMUM_SEGMENTS; SegmentIndex++) {
  1447. Segment = Heap->Segments[ SegmentIndex ];
  1448. if (Segment) {
  1449. if (!RtlpValidateHeapSegment( Heap,
  1450. Segment,
  1451. SegmentIndex,
  1452. &CountOfFreeBlocks,
  1453. &TotalFreeSize,
  1454. &BadAddress,
  1455. ComputedTagEntries,
  1456. ComputedPseudoTagEntries )) {
  1457. goto errorExit;
  1458. }
  1459. }
  1460. }
  1461. BadAddress = Heap;
  1462. if (NumberOfFreeListEntries != CountOfFreeBlocks) {
  1463. HeapDebugPrint(( "Number of free blocks in arena (%ld) does not match number in the free lists (%ld)\n",
  1464. CountOfFreeBlocks,
  1465. NumberOfFreeListEntries ));
  1466. goto errorExit;
  1467. }
  1468. if (Heap->TotalFreeSize != TotalFreeSize) {
  1469. HeapDebugPrint(( "Total size of free blocks in arena (%ld) does not match number total in heap header (%ld)\n",
  1470. TotalFreeSize,
  1471. Heap->TotalFreeSize ));
  1472. goto errorExit;
  1473. }
  1474. if (ComputedPseudoTagEntries != NULL) {
  1475. PHEAP_PSEUDO_TAG_ENTRY PseudoTagEntries;
  1476. PHEAP_TAG_ENTRY TagEntries;
  1477. USHORT xTagIndex;
  1478. PseudoTagEntries = Heap->PseudoTagEntries;
  1479. if (PseudoTagEntries != NULL) {
  1480. for (xTagIndex=1; xTagIndex<HEAP_NUMBER_OF_PSEUDO_TAG; xTagIndex++) {
  1481. PseudoTagEntries += 1;
  1482. if (ComputedPseudoTagEntries[ xTagIndex ] != PseudoTagEntries->Size) {
  1483. HeapDebugPrint(( "Pseudo Tag %04x size incorrect (%x != %x) %x\n",
  1484. xTagIndex,
  1485. PseudoTagEntries->Size,
  1486. ComputedPseudoTagEntries[ xTagIndex ]
  1487. &ComputedPseudoTagEntries[ xTagIndex ] ));
  1488. goto errorExit;
  1489. }
  1490. }
  1491. }
  1492. TagEntries = Heap->TagEntries;
  1493. if (TagEntries != NULL) {
  1494. for (xTagIndex=1; xTagIndex<Heap->NextAvailableTagIndex; xTagIndex++) {
  1495. TagEntries += 1;
  1496. if (ComputedTagEntries[ xTagIndex ] != TagEntries->Size) {
  1497. HeapDebugPrint(( "Tag %04x (%ws) size incorrect (%x != %x) %x\n",
  1498. xTagIndex,
  1499. TagEntries->TagName,
  1500. TagEntries->Size,
  1501. ComputedTagEntries[ xTagIndex ],
  1502. &ComputedTagEntries[ xTagIndex ] ));
  1503. goto errorExit;
  1504. }
  1505. }
  1506. }
  1507. Size = 0;
  1508. RtlpHeapFreeVirtualMemory( NtCurrentProcess(),
  1509. &ComputedPseudoTagEntries,
  1510. &Size,
  1511. MEM_RELEASE );
  1512. }
  1513. exit:
  1514. return TRUE;
  1515. errorExit:
  1516. HeapDebugBreak( BadAddress );
  1517. if (ComputedPseudoTagEntries != NULL) {
  1518. Size = 0;
  1519. RtlpHeapFreeVirtualMemory( NtCurrentProcess(),
  1520. &ComputedPseudoTagEntries,
  1521. &Size,
  1522. MEM_RELEASE );
  1523. }
  1524. return FALSE;
  1525. }
  1526. BOOLEAN RtlpHeapInvalidBreakPoint;
  1527. PVOID RtlpHeapInvalidBadAddress;
  1528. VOID
  1529. RtlpBreakPointHeap (
  1530. IN PVOID BadAddress
  1531. )
  1532. /*++
  1533. Routine Description:
  1534. Arguments:
  1535. Return Value:
  1536. --*/
  1537. {
  1538. if (NtCurrentPeb()->BeingDebugged) {
  1539. *(BOOLEAN volatile *)&RtlpHeapInvalidBreakPoint = TRUE;
  1540. RtlpHeapInvalidBadAddress = BadAddress;
  1541. DbgBreakPoint();
  1542. *(BOOLEAN volatile *)&RtlpHeapInvalidBreakPoint = FALSE;
  1543. }
  1544. }