Windows NT 4.0 source code leak
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.

1883 lines
59 KiB

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