1 /* COPYRIGHT: See COPYING in the top level directory
2 * PROJECT: ReactOS system libraries
3 * FILE: lib/rtl/heappage.c
4 * PURPOSE: RTL Page Heap implementation
5 * PROGRAMMERS: Copyright 2011 Aleksey Bragin
9 http://msdn.microsoft.com/en-us/library/ms220938(VS.80).aspx
10 http://blogs.msdn.com/b/jiangyue/archive/2010/03/16/windows-heap-overrun-monitoring.aspx
13 /* INCLUDES *****************************************************************/
21 /* TYPES **********************************************************************/
23 typedef struct _DPH_BLOCK_INFORMATION
32 SINGLE_LIST_ENTRY FreePushList
;
37 } DPH_BLOCK_INFORMATION
, *PDPH_BLOCK_INFORMATION
;
39 typedef struct _DPH_HEAP_BLOCK
43 struct _DPH_HEAP_BLOCK
*pNextAlloc
;
44 LIST_ENTRY AvailableEntry
;
45 RTL_BALANCED_LINKS TableLinks
;
47 PUCHAR pUserAllocation
;
49 ULONG nVirtualBlockSize
;
50 ULONG nVirtualAccessSize
;
51 ULONG nUserRequestedSize
;
52 ULONG nUserActualSize
;
55 PRTL_TRACE_BLOCK StackTrace
;
56 LIST_ENTRY AdjacencyEntry
;
57 PUCHAR pVirtualRegion
;
58 } DPH_HEAP_BLOCK
, *PDPH_HEAP_BLOCK
;
60 typedef struct _DPH_HEAP_ROOT
64 PRTL_CRITICAL_SECTION HeapCritSect
;
65 ULONG nRemoteLockAcquired
;
67 PDPH_HEAP_BLOCK pVirtualStorageListHead
;
68 PDPH_HEAP_BLOCK pVirtualStorageListTail
;
69 ULONG nVirtualStorageRanges
;
70 ULONG nVirtualStorageBytes
;
72 RTL_AVL_TABLE BusyNodesTable
;
73 PDPH_HEAP_BLOCK NodeToAllocate
;
74 ULONG nBusyAllocations
;
75 ULONG nBusyAllocationBytesCommitted
;
77 PDPH_HEAP_BLOCK pFreeAllocationListHead
;
78 PDPH_HEAP_BLOCK pFreeAllocationListTail
;
79 ULONG nFreeAllocations
;
80 ULONG nFreeAllocationBytesCommitted
;
82 LIST_ENTRY AvailableAllocationHead
;
83 ULONG nAvailableAllocations
;
84 ULONG nAvailableAllocationBytesCommitted
;
86 PDPH_HEAP_BLOCK pUnusedNodeListHead
;
87 PDPH_HEAP_BLOCK pUnusedNodeListTail
;
89 ULONG nBusyAllocationBytesAccessible
;
90 PDPH_HEAP_BLOCK pNodePoolListHead
;
91 PDPH_HEAP_BLOCK pNodePoolListTail
;
99 PRTL_TRACE_BLOCK CreateStackTrace
;
101 } DPH_HEAP_ROOT
, *PDPH_HEAP_ROOT
;
103 /* GLOBALS ********************************************************************/
105 BOOLEAN RtlpPageHeapEnabled
= FALSE
;
106 ULONG RtlpDphGlobalFlags
;
107 ULONG RtlpPageHeapSizeRangeStart
, RtlpPageHeapSizeRangeEnd
;
108 ULONG RtlpPageHeapDllRangeStart
, RtlpPageHeapDllRangeEnd
;
109 WCHAR RtlpDphTargetDlls
[512];
111 LIST_ENTRY RtlpDphPageHeapList
;
112 BOOLEAN RtlpDphPageHeapListInitialized
;
113 RTL_CRITICAL_SECTION RtlpDphPageHeapListLock
;
114 ULONG RtlpDphPageHeapListLength
;
115 UNICODE_STRING RtlpDphTargetDllsUnicode
;
117 RTL_CRITICAL_SECTION RtlpDphDelayedFreeQueueLock
;
118 LIST_ENTRY RtlpDphDelayedFreeQueue
;
119 SLIST_HEADER RtlpDphDelayedTemporaryPushList
;
120 ULONG RtlpDphMemoryUsedByDelayedFreeBlocks
;
121 ULONG RtlpDphNumberOfDelayedFreeBlocks
;
125 LONG RtlpDphAllocFails
;
126 LONG RtlpDphReleaseFails
;
127 LONG RtlpDphFreeFails
;
128 LONG RtlpDphProtectFails
;
130 #define DPH_RESERVE_SIZE 0x100000
131 #define DPH_POOL_SIZE 0x4000
132 #define DPH_FREE_LIST_MINIMUM 8
134 /* RtlpDphBreakOptions */
135 #define DPH_BREAK_ON_RESERVE_FAIL 0x01
136 #define DPH_BREAK_ON_COMMIT_FAIL 0x02
137 #define DPH_BREAK_ON_RELEASE_FAIL 0x04
138 #define DPH_BREAK_ON_FREE_FAIL 0x08
139 #define DPH_BREAK_ON_PROTECT_FAIL 0x10
140 #define DPH_BREAK_ON_NULL_FREE 0x80
142 /* RtlpDphDebugOptions */
143 #define DPH_DEBUG_INTERNAL_VALIDATE 0x01
144 #define DPH_DEBUG_VERBOSE 0x04
147 #define DPH_EXTRA_LOG_STACK_TRACES 0x02
148 #define DPH_EXTRA_CHECK_UNDERRUN 0x10
151 #define DPH_FILL 0xEEEEEEEE
152 #define DPH_FILL_START_STAMP_1 0xABCDBBBB
153 #define DPH_FILL_START_STAMP_2 0xABCDBBBA
154 #define DPH_FILL_END_STAMP_1 0xDCBABBBB
155 #define DPH_FILL_END_STAMP_2 0xDCBABBBA
156 #define DPH_FILL_SUFFIX 0xD0
157 #define DPH_FILL_INFIX 0xC0
159 /* Validation info flags */
160 #define DPH_VALINFO_BAD_START_STAMP 0x01
161 #define DPH_VALINFO_BAD_END_STAMP 0x02
162 #define DPH_VALINFO_BAD_POINTER 0x04
163 #define DPH_VALINFO_BAD_PREFIX_PATTERN 0x08
164 #define DPH_VALINFO_BAD_SUFFIX_PATTERN 0x10
165 #define DPH_VALINFO_EXCEPTION 0x20
166 #define DPH_VALINFO_1 0x40
167 #define DPH_VALINFO_BAD_INFIX_PATTERN 0x80
168 #define DPH_VALINFO_ALREADY_FREED 0x100
169 #define DPH_VALINFO_CORRUPTED_AFTER_FREE 0x200
172 #define DPH_SIGNATURE 0xFFEEDDCC
174 /* Biased pointer macros */
175 #define IS_BIASED_POINTER(ptr) ((ULONG_PTR)(ptr) & 1)
176 #define POINTER_REMOVE_BIAS(ptr) ((ULONG_PTR)(ptr) & ~(ULONG_PTR)1)
177 #define POINTER_ADD_BIAS(ptr) ((ULONG_PTR)(ptr) | 1)
180 ULONG RtlpDphBreakOptions
= 0;//0xFFFFFFFF;
181 ULONG RtlpDphDebugOptions
;
183 /* FUNCTIONS ******************************************************************/
186 RtlpDphGrowVirtual(PDPH_HEAP_ROOT DphRoot
, SIZE_T Size
);
189 RtlpDphIsNormalFreeHeapBlock(PVOID Block
, PULONG ValidationInformation
, BOOLEAN CheckFillers
);
192 RtlpDphReportCorruptedBlock(PDPH_HEAP_ROOT DphRoot
, ULONG Reserved
, PVOID Block
, ULONG ValidationInfo
);
195 RtlpDphNormalHeapValidate(PDPH_HEAP_ROOT DphRoot
, ULONG Flags
, PVOID BaseAddress
);
199 RtlpDphRaiseException(NTSTATUS Status
)
201 EXCEPTION_RECORD Exception
;
203 /* Initialize exception record */
204 Exception
.ExceptionCode
= Status
;
205 Exception
.ExceptionAddress
= RtlpDphRaiseException
;
206 Exception
.ExceptionFlags
= 0;
207 Exception
.ExceptionRecord
= NULL
;
208 Exception
.NumberParameters
= 0;
210 /* Raise the exception */
211 RtlRaiseException(&Exception
);
215 RtlpDphPointerFromHandle(PVOID Handle
)
217 PHEAP NormalHeap
= (PHEAP
)Handle
;
218 PDPH_HEAP_ROOT DphHeap
= (PDPH_HEAP_ROOT
)((PUCHAR
)Handle
+ PAGE_SIZE
);
220 if (NormalHeap
->ForceFlags
& HEAP_FLAG_PAGE_ALLOCS
)
222 if (DphHeap
->Signature
== DPH_SIGNATURE
)
226 DPRINT1("heap handle with incorrect signature\n");
232 RtlpDphEnterCriticalSection(PDPH_HEAP_ROOT DphRoot
, ULONG Flags
)
234 if (Flags
& HEAP_NO_SERIALIZE
)
236 /* More complex scenario */
237 if (!RtlTryEnterCriticalSection(DphRoot
->HeapCritSect
))
239 if (!DphRoot
->nRemoteLockAcquired
)
241 DPRINT1("multithreaded access in HEAP_NO_SERIALIZE heap\n");
244 /* Clear out the no serialize flag */
245 DphRoot
->HeapFlags
&= ~HEAP_NO_SERIALIZE
;
248 /* Enter the heap's critical section */
249 RtlEnterCriticalSection(DphRoot
->HeapCritSect
);
254 /* Just enter the heap's critical section */
255 RtlEnterCriticalSection(DphRoot
->HeapCritSect
);
260 RtlpDphLeaveCriticalSection(PDPH_HEAP_ROOT DphRoot
)
262 /* Just leave the heap's critical section */
263 RtlLeaveCriticalSection(DphRoot
->HeapCritSect
);
268 RtlpDphPreProcessing(PDPH_HEAP_ROOT DphRoot
, ULONG Flags
)
270 RtlpDphEnterCriticalSection(DphRoot
, Flags
);
272 /* FIXME: Validate integrity, internal lists if necessary */
276 RtlpDphPostProcessing(PDPH_HEAP_ROOT DphRoot
)
278 if (!DphRoot
) return;
280 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
)
282 /* FIXME: Validate integrity, internal lists if necessary */
285 /* Release the lock */
286 RtlpDphLeaveCriticalSection(DphRoot
);
290 RtlpSecMemFreeVirtualMemory(HANDLE Process
, PVOID
*Base
, PSIZE_T Size
, ULONG Type
)
293 //PVOID *SavedBase = Base;
294 //PSIZE_T SavedSize = Size;
296 /* Free the memory */
297 Status
= ZwFreeVirtualMemory(Process
, Base
, Size
, Type
);
299 /* Flush secure memory cache if needed and retry freeing */
301 if (Status
== STATUS_INVALID_PAGE_PROTECTION
&&
302 Process
== NtCurrentProcess() &&
303 RtlFlushSecureMemoryCache(*SavedBase
, *SavedSize
))
305 Status
= ZwFreeVirtualMemory(NtCurrentProcess(), SavedBase
, SavedSize
, Type
);
313 RtlpDphAllocateVm(PVOID
*Base
, SIZE_T Size
, ULONG Type
, ULONG Protection
)
316 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(),
322 DPRINT("Page heap: AllocVm (%p, %p, %x) status %x \n", Base
, Size
, Type
, Status
);
323 /* Check for failures */
324 if (!NT_SUCCESS(Status
))
326 if (Type
== MEM_RESERVE
)
328 _InterlockedIncrement(&RtlpDphCounter
);
329 if (RtlpDphBreakOptions
& DPH_BREAK_ON_RESERVE_FAIL
)
331 DPRINT1("Page heap: AllocVm (%p, %p, %x) failed with %x \n", Base
, Size
, Type
, Status
);
338 _InterlockedIncrement(&RtlpDphAllocFails
);
339 if (RtlpDphBreakOptions
& DPH_BREAK_ON_COMMIT_FAIL
)
341 DPRINT1("Page heap: AllocVm (%p, %p, %x) failed with %x \n", Base
, Size
, Type
, Status
);
352 RtlpDphFreeVm(PVOID Base
, SIZE_T Size
, ULONG Type
)
356 /* Free the memory */
357 Status
= RtlpSecMemFreeVirtualMemory(NtCurrentProcess(), &Base
, &Size
, Type
);
358 DPRINT1("Page heap: FreeVm (%p, %p, %x) status %x \n", Base
, Size
, Type
, Status
);
359 /* Log/report failures */
360 if (!NT_SUCCESS(Status
))
362 if (Type
== MEM_RELEASE
)
364 _InterlockedIncrement(&RtlpDphReleaseFails
);
365 if (RtlpDphBreakOptions
& DPH_BREAK_ON_RELEASE_FAIL
)
367 DPRINT1("Page heap: FreeVm (%p, %p, %x) failed with %x \n", Base
, Size
, Type
, Status
);
374 _InterlockedIncrement(&RtlpDphFreeFails
);
375 if (RtlpDphBreakOptions
& DPH_BREAK_ON_FREE_FAIL
)
377 DPRINT1("Page heap: FreeVm (%p, %p, %x) failed with %x \n", Base
, Size
, Type
, Status
);
388 RtlpDphProtectVm(PVOID Base
, SIZE_T Size
, ULONG Protection
)
393 /* Change protection */
394 Status
= ZwProtectVirtualMemory(NtCurrentProcess(), &Base
, &Size
, Protection
, &OldProtection
);
396 /* Log/report failures */
397 if (!NT_SUCCESS(Status
))
399 _InterlockedIncrement(&RtlpDphProtectFails
);
400 if (RtlpDphBreakOptions
& DPH_BREAK_ON_PROTECT_FAIL
)
402 DPRINT1("Page heap: ProtectVm (%p, %p, %x) failed with %x \n", Base
, Size
, Protection
, Status
);
412 RtlpDphWritePageHeapBlockInformation(PDPH_HEAP_ROOT DphRoot
, PVOID UserAllocation
, SIZE_T Size
, SIZE_T UserSize
)
414 PDPH_BLOCK_INFORMATION BlockInfo
;
417 /* Get pointer to the block info structure */
418 BlockInfo
= (PDPH_BLOCK_INFORMATION
)UserAllocation
- 1;
420 /* Set up basic fields */
421 BlockInfo
->Heap
= DphRoot
;
422 BlockInfo
->ActualSize
= UserSize
;
423 BlockInfo
->RequestedSize
= Size
;
424 BlockInfo
->StartStamp
= DPH_FILL_START_STAMP_1
;
425 BlockInfo
->EndStamp
= DPH_FILL_END_STAMP_1
;
427 /* Fill with a pattern */
428 FillPtr
= (PUCHAR
)UserAllocation
+ Size
;
429 RtlFillMemory(FillPtr
, ROUND_UP(FillPtr
, PAGE_SIZE
) - (ULONG_PTR
)FillPtr
, DPH_FILL_SUFFIX
);
431 /* FIXME: Check if logging stack traces is turned on */
432 //if (DphRoot->ExtraFlags &
438 RtlpDphPlaceOnBusyList(PDPH_HEAP_ROOT DphRoot
, PDPH_HEAP_BLOCK DphNode
)
441 PVOID AddressUserData
;
443 DPRINT("RtlpDphPlaceOnBusyList(%p %p)\n", DphRoot
, DphNode
);
445 /* Add it to the AVL busy nodes table */
446 DphRoot
->NodeToAllocate
= DphNode
;
447 AddressUserData
= RtlInsertElementGenericTableAvl(&DphRoot
->BusyNodesTable
,
448 &DphNode
->pUserAllocation
,
452 ASSERT(AddressUserData
== &DphNode
->pUserAllocation
);
453 ASSERT(NewElement
== TRUE
);
455 /* Update heap counters */
456 DphRoot
->nBusyAllocations
++;
457 DphRoot
->nBusyAllocationBytesAccessible
+= DphNode
->nVirtualAccessSize
;
458 DphRoot
->nBusyAllocationBytesCommitted
+= DphNode
->nVirtualBlockSize
;
462 RtlpDphPlaceOnFreeList(PDPH_HEAP_ROOT DphRoot
, PDPH_HEAP_BLOCK Node
)
464 DPRINT("RtlpDphPlaceOnFreeList(%p %p)\n", DphRoot
, Node
);
466 /* Node is being added to the tail of the list */
467 Node
->pNextAlloc
= NULL
;
469 /* Add it to the tail of the linked list */
470 if (DphRoot
->pFreeAllocationListTail
)
471 DphRoot
->pFreeAllocationListTail
->pNextAlloc
= Node
;
473 DphRoot
->pFreeAllocationListHead
= Node
;
474 DphRoot
->pFreeAllocationListTail
= Node
;
476 /* Update byte counts taking in account this new node */
477 DphRoot
->nFreeAllocations
++;
478 DphRoot
->nFreeAllocationBytesCommitted
+= Node
->nVirtualBlockSize
;
482 RtlpDphPlaceOnPoolList(PDPH_HEAP_ROOT DphRoot
, PDPH_HEAP_BLOCK Node
)
484 DPRINT("RtlpDphPlaceOnPoolList(%p %p)\n", DphRoot
, Node
);
486 /* Node is being added to the tail of the list */
487 Node
->pNextAlloc
= NULL
;
489 /* Add it to the tail of the linked list */
490 if (DphRoot
->pNodePoolListTail
)
491 DphRoot
->pNodePoolListTail
->pNextAlloc
= Node
;
493 DphRoot
->pNodePoolListHead
= Node
;
494 DphRoot
->pNodePoolListTail
= Node
;
496 /* Update byte counts taking in account this new node */
497 DphRoot
->nNodePools
++;
498 DphRoot
->nNodePoolBytes
+= Node
->nVirtualBlockSize
;
502 RtlpDphPlaceOnVirtualList(PDPH_HEAP_ROOT DphRoot
, PDPH_HEAP_BLOCK Node
)
504 DPRINT("RtlpDphPlaceOnVirtualList(%p %p)\n", DphRoot
, Node
);
506 /* Add it to the head of the virtual list */
507 Node
->pNextAlloc
= DphRoot
->pVirtualStorageListHead
;
508 if (!DphRoot
->pVirtualStorageListHead
)
509 DphRoot
->pVirtualStorageListTail
= Node
;
510 DphRoot
->pVirtualStorageListHead
= Node
;
512 /* Update byte counts taking in account this new node */
513 DphRoot
->nVirtualStorageRanges
++;
514 DphRoot
->nVirtualStorageBytes
+= Node
->nVirtualBlockSize
;
517 PDPH_HEAP_BLOCK NTAPI
518 RtlpDphTakeNodeFromUnusedList(PDPH_HEAP_ROOT DphRoot
)
520 PDPH_HEAP_BLOCK Node
= DphRoot
->pUnusedNodeListHead
;
521 PDPH_HEAP_BLOCK Next
;
523 DPRINT("RtlpDphTakeNodeFromUnusedList(%p), ret %p\n", DphRoot
, Node
);
525 /* Take the first entry */
526 if (!Node
) return NULL
;
528 /* Remove that entry (Node) from the list */
529 Next
= Node
->pNextAlloc
;
530 if (DphRoot
->pUnusedNodeListHead
== Node
) DphRoot
->pUnusedNodeListHead
= Next
;
531 if (DphRoot
->pUnusedNodeListTail
== Node
) DphRoot
->pUnusedNodeListTail
= NULL
;
533 /* Decrease amount of unused nodes */
534 DphRoot
->nUnusedNodes
--;
540 RtlpDphReturnNodeToUnusedList(PDPH_HEAP_ROOT DphRoot
,
541 PDPH_HEAP_BLOCK Node
)
543 DPRINT("RtlpDphReturnNodeToUnusedList(%p, %p)\n", DphRoot
, Node
);
545 /* Add it back to the head of the unused list */
546 Node
->pNextAlloc
= DphRoot
->pUnusedNodeListHead
;
547 if (!DphRoot
->pUnusedNodeListHead
)
548 DphRoot
->pUnusedNodeListTail
= Node
;
549 DphRoot
->pUnusedNodeListHead
= Node
;
551 /* Increase amount of unused nodes */
552 DphRoot
->nUnusedNodes
++;
556 RtlpDphRemoveFromAvailableList(PDPH_HEAP_ROOT DphRoot
,
557 PDPH_HEAP_BLOCK Node
)
559 /* Make sure Adjacency list pointers are biased */
560 //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Flink));
561 //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Blink));
563 DPRINT("RtlpDphRemoveFromAvailableList(%p %p)\n", DphRoot
, Node
);
565 /* Check if it is in the list */
568 PLIST_ENTRY CurEntry
;
569 PDPH_HEAP_BLOCK NodeEntry
;
570 BOOLEAN Found
= FALSE
;
572 /* Find where to put this node according to its virtual address */
573 CurEntry
= DphRoot
->AvailableAllocationHead
.Flink
;
575 while (CurEntry
!= &DphRoot
->AvailableAllocationHead
)
577 NodeEntry
= CONTAINING_RECORD(CurEntry
, DPH_HEAP_BLOCK
, AvailableEntry
);
579 if (NodeEntry
== Node
)
585 CurEntry
= CurEntry
->Flink
;
590 DPRINT1("Trying to remove non-existing in availlist node!\n");
596 /* Remove it from the list */
597 RemoveEntryList(&Node
->AvailableEntry
);
599 /* Decrease heap counters */
600 DphRoot
->nAvailableAllocations
--;
601 DphRoot
->nAvailableAllocationBytesCommitted
-= Node
->nVirtualBlockSize
;
603 /* Remove bias from the AdjacencyEntry pointer */
604 Node
->AdjacencyEntry
.Flink
= (PLIST_ENTRY
)POINTER_REMOVE_BIAS(Node
->AdjacencyEntry
.Flink
);
605 Node
->AdjacencyEntry
.Blink
= (PLIST_ENTRY
)POINTER_REMOVE_BIAS(Node
->AdjacencyEntry
.Blink
);
609 RtlpDphRemoveFromBusyList(PDPH_HEAP_ROOT DphRoot
,
610 PDPH_HEAP_BLOCK Node
)
612 BOOLEAN ElementPresent
;
614 DPRINT("RtlpDphRemoveFromBusyList(%p %p)\n", DphRoot
, Node
);
616 /* Delete it from busy nodes table */
617 ElementPresent
= RtlDeleteElementGenericTableAvl(&DphRoot
->BusyNodesTable
, &Node
->pUserAllocation
);
618 ASSERT(ElementPresent
== TRUE
);
620 /* Update counters */
621 DphRoot
->nBusyAllocations
--;
622 DphRoot
->nBusyAllocationBytesCommitted
-= Node
->nVirtualBlockSize
;
623 DphRoot
->nBusyAllocationBytesAccessible
-= Node
->nVirtualAccessSize
;
627 RtlpDphRemoveFromFreeList(PDPH_HEAP_ROOT DphRoot
,
628 PDPH_HEAP_BLOCK Node
,
629 PDPH_HEAP_BLOCK Prev
)
631 PDPH_HEAP_BLOCK Next
;
633 DPRINT("RtlpDphRemoveFromFreeList(%p %p %p)\n", DphRoot
, Node
, Prev
);
635 /* Detach it from the list */
636 Next
= Node
->pNextAlloc
;
637 if (DphRoot
->pFreeAllocationListHead
== Node
)
638 DphRoot
->pFreeAllocationListHead
= Next
;
639 if (DphRoot
->pFreeAllocationListTail
== Node
)
640 DphRoot
->pFreeAllocationListTail
= Prev
;
641 if (Prev
) Prev
->pNextAlloc
= Next
;
643 /* Decrease heap counters */
644 DphRoot
->nFreeAllocations
--;
645 DphRoot
->nFreeAllocationBytesCommitted
-= Node
->nVirtualBlockSize
;
647 Node
->StackTrace
= NULL
;
651 RtlpDphCoalesceNodeIntoAvailable(PDPH_HEAP_ROOT DphRoot
,
652 PDPH_HEAP_BLOCK Node
)
654 PDPH_HEAP_BLOCK NodeEntry
, PrevNode
= NULL
, NextNode
;
655 PLIST_ENTRY AvailListHead
;
656 PLIST_ENTRY CurEntry
;
658 DPRINT("RtlpDphCoalesceNodeIntoAvailable(%p %p)\n", DphRoot
, Node
);
660 /* Update heap counters */
661 DphRoot
->nAvailableAllocationBytesCommitted
+= Node
->nVirtualBlockSize
;
662 DphRoot
->nAvailableAllocations
++;
664 /* Find where to put this node according to its virtual address */
665 AvailListHead
= &DphRoot
->AvailableAllocationHead
;
667 /* Find a point where to insert an available node */
668 CurEntry
= AvailListHead
->Flink
;
670 while (CurEntry
!= AvailListHead
)
672 NodeEntry
= CONTAINING_RECORD(CurEntry
, DPH_HEAP_BLOCK
, AvailableEntry
);
673 if (NodeEntry
->pVirtualBlock
>= Node
->pVirtualBlock
)
675 PrevNode
= NodeEntry
;
678 CurEntry
= CurEntry
->Flink
;
683 /* That means either this list is empty, or we should add to the head of it */
684 InsertHeadList(AvailListHead
, &Node
->AvailableEntry
);
688 /* Check the previous node and merge if possible */
689 if (PrevNode
->pVirtualBlock
+ PrevNode
->nVirtualBlockSize
== Node
->pVirtualBlock
)
691 /* They are adjacent - merge! */
692 PrevNode
->nVirtualBlockSize
+= Node
->nVirtualBlockSize
;
693 RtlpDphReturnNodeToUnusedList(DphRoot
, Node
);
694 DphRoot
->nAvailableAllocations
--;
700 /* Insert after PrevNode */
701 InsertTailList(&PrevNode
->AvailableEntry
, &Node
->AvailableEntry
);
704 /* Now check the next entry after our one */
705 if (Node
->AvailableEntry
.Flink
!= AvailListHead
)
707 NextNode
= CONTAINING_RECORD(Node
->AvailableEntry
.Flink
, DPH_HEAP_BLOCK
, AvailableEntry
);
708 /* Node is not at the tail of the list, check if it's adjacent */
709 if (Node
->pVirtualBlock
+ Node
->nVirtualBlockSize
== NextNode
->pVirtualBlock
)
711 /* They are adjacent - merge! */
712 Node
->nVirtualBlockSize
+= NextNode
->nVirtualBlockSize
;
714 /* Remove next entry from the list and put it into unused entries list */
715 RemoveEntryList(&NextNode
->AvailableEntry
);
716 RtlpDphReturnNodeToUnusedList(DphRoot
, NextNode
);
717 DphRoot
->nAvailableAllocations
--;
724 RtlpDphCoalesceFreeIntoAvailable(PDPH_HEAP_ROOT DphRoot
,
725 ULONG LeaveOnFreeList
)
727 PDPH_HEAP_BLOCK Node
= DphRoot
->pFreeAllocationListHead
, Next
;
728 SIZE_T FreeAllocations
= DphRoot
->nFreeAllocations
;
730 /* Make sure requested size is not too big */
731 ASSERT(FreeAllocations
>= LeaveOnFreeList
);
733 DPRINT("RtlpDphCoalesceFreeIntoAvailable(%p %d)\n", DphRoot
, LeaveOnFreeList
);
738 if (FreeAllocations
< LeaveOnFreeList
) break;
740 /* Get the next pointer, because it may be changed after following two calls */
741 Next
= Node
->pNextAlloc
;
743 /* Remove it from the free list */
744 RtlpDphRemoveFromFreeList(DphRoot
, Node
, NULL
);
746 /* And put into the available */
747 RtlpDphCoalesceNodeIntoAvailable(DphRoot
, Node
);
749 /* Go to the next node */
755 RtlpDphAddNewPool(PDPH_HEAP_ROOT DphRoot
, PDPH_HEAP_BLOCK NodeBlock
, PVOID Virtual
, SIZE_T Size
, BOOLEAN PlaceOnPool
)
757 PDPH_HEAP_BLOCK DphNode
, DphStartNode
;
760 //NodeCount = (Size >> 6) - 1;
761 NodeCount
= (Size
/ sizeof(DPH_HEAP_BLOCK
));
762 DphStartNode
= Virtual
;
764 /* Set pNextAlloc for all blocks */
765 for (DphNode
= Virtual
, i
=NodeCount
-1; i
> 0; i
--)
767 DphNode
->pNextAlloc
= DphNode
+ 1;
768 DphNode
= DphNode
->pNextAlloc
;
771 /* and the last one */
772 DphNode
->pNextAlloc
= NULL
;
774 /* Add it to the tail of unused node list */
775 if (DphRoot
->pUnusedNodeListTail
)
776 DphRoot
->pUnusedNodeListTail
->pNextAlloc
= DphStartNode
;
778 DphRoot
->pUnusedNodeListHead
= DphStartNode
;
780 DphRoot
->pUnusedNodeListTail
= DphNode
;
782 /* Increase counters */
783 DphRoot
->nUnusedNodes
+= NodeCount
;
785 /* Check if we need to place it on the pool list */
788 /* Get a node from the unused list */
789 DphNode
= RtlpDphTakeNodeFromUnusedList(DphRoot
);
792 /* Set its virtual block values */
793 DphNode
->pVirtualBlock
= Virtual
;
794 DphNode
->nVirtualBlockSize
= Size
;
796 /* Place it on the pool list */
797 RtlpDphPlaceOnPoolList(DphRoot
, DphNode
);
801 PDPH_HEAP_BLOCK NTAPI
802 RtlpDphSearchAvailableMemoryListForBestFit(PDPH_HEAP_ROOT DphRoot
,
805 PLIST_ENTRY CurEntry
;
806 PDPH_HEAP_BLOCK Node
, NodeFound
= NULL
;
808 CurEntry
= DphRoot
->AvailableAllocationHead
.Flink
;
810 while (CurEntry
!= &DphRoot
->AvailableAllocationHead
)
812 /* Get the current available node */
813 Node
= CONTAINING_RECORD(CurEntry
, DPH_HEAP_BLOCK
, AvailableEntry
);
816 if (Node
->nVirtualBlockSize
>= Size
)
822 /* Move to the next available entry */
823 CurEntry
= CurEntry
->Flink
;
826 /* Make sure Adjacency list pointers are biased */
827 //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Flink));
828 //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Blink));
833 PDPH_HEAP_BLOCK NTAPI
834 RtlpDphFindAvailableMemory(PDPH_HEAP_ROOT DphRoot
,
838 PDPH_HEAP_BLOCK Node
;
841 /* Find an available best fitting node */
842 Node
= RtlpDphSearchAvailableMemoryListForBestFit(DphRoot
, Size
);
844 /* If that didn't work, try to search a smaller one in the loop */
847 /* Break if the free list becomes too small */
848 if (DphRoot
->nFreeAllocations
<= DPH_FREE_LIST_MINIMUM
) break;
850 /* Calculate a new free list size */
851 NewSize
= DphRoot
->nFreeAllocations
>> 2;
852 if (NewSize
< DPH_FREE_LIST_MINIMUM
) NewSize
= DPH_FREE_LIST_MINIMUM
;
854 /* Coalesce free into available */
855 RtlpDphCoalesceFreeIntoAvailable(DphRoot
, NewSize
);
857 /* Try to find an available best fitting node again */
858 Node
= RtlpDphSearchAvailableMemoryListForBestFit(DphRoot
, Size
);
861 /* If Node is NULL, then we could fix the situation only by
862 growing the available VM size */
865 /* Grow VM size, if it fails - return failure directly */
866 if (!RtlpDphGrowVirtual(DphRoot
, Size
)) return NULL
;
868 /* Try to find an available best fitting node again */
869 Node
= RtlpDphSearchAvailableMemoryListForBestFit(DphRoot
, Size
);
873 /* Do the last attempt: coalesce all free into available (if Size fits there) */
874 if (DphRoot
->nFreeAllocationBytesCommitted
+ DphRoot
->nAvailableAllocationBytesCommitted
>= Size
)
876 /* Coalesce free into available */
877 RtlpDphCoalesceFreeIntoAvailable(DphRoot
, 0);
879 /* Try to find an available best fitting node again */
880 Node
= RtlpDphSearchAvailableMemoryListForBestFit(DphRoot
, Size
);
885 /* Return node we found */
889 PDPH_HEAP_BLOCK NTAPI
890 RtlpDphFindBusyMemory(PDPH_HEAP_ROOT DphRoot
,
893 PDPH_HEAP_BLOCK Node
;
896 /* Lookup busy block in AVL */
897 Ptr
= RtlLookupElementGenericTableAvl(&DphRoot
->BusyNodesTable
, &pUserMem
);
898 if (!Ptr
) return NULL
;
900 /* Restore pointer to the heap block */
901 Node
= CONTAINING_RECORD(Ptr
, DPH_HEAP_BLOCK
, pUserAllocation
);
902 ASSERT(Node
->pUserAllocation
== pUserMem
);
907 RtlpDphSetProtectionBeforeUse(PDPH_HEAP_ROOT DphRoot
, PUCHAR VirtualBlock
, ULONG UserSize
)
912 // FIXME: Check this, when we should add up usersize and when we shouldn't!
913 if (!(DphRoot
->ExtraFlags
& DPH_EXTRA_CHECK_UNDERRUN
))
919 Base
= VirtualBlock
+ PAGE_SIZE
;
922 // FIXME: It should be different, but for now it's fine
923 Protection
= PAGE_READWRITE
;
925 return RtlpDphProtectVm(Base
, UserSize
, Protection
);
929 RtlpDphSetProtectionAfterUse(PDPH_HEAP_ROOT DphRoot
, /*PUCHAR VirtualBlock*/PDPH_HEAP_BLOCK Node
)
931 // FIXME: Bring stuff here
932 if (DphRoot
->ExtraFlags
& DPH_EXTRA_CHECK_UNDERRUN
)
939 return STATUS_SUCCESS
;
942 PDPH_HEAP_BLOCK NTAPI
943 RtlpDphAllocateNode(PDPH_HEAP_ROOT DphRoot
)
945 PDPH_HEAP_BLOCK Node
;
947 SIZE_T Size
= DPH_POOL_SIZE
, SizeVirtual
;
950 /* Check for the easy case */
951 if (DphRoot
->pUnusedNodeListHead
)
953 /* Just take a node from this list */
954 Node
= RtlpDphTakeNodeFromUnusedList(DphRoot
);
959 /* There is a need to make free space */
960 Node
= RtlpDphFindAvailableMemory(DphRoot
, DPH_POOL_SIZE
, FALSE
);
962 if (!DphRoot
->pUnusedNodeListHead
&& !Node
)
964 /* Retry with a smaller request */
966 Node
= RtlpDphFindAvailableMemory(DphRoot
, PAGE_SIZE
, FALSE
);
969 if (!DphRoot
->pUnusedNodeListHead
)
973 RtlpDphRemoveFromAvailableList(DphRoot
, Node
);
974 Ptr
= Node
->pVirtualBlock
;
975 SizeVirtual
= Node
->nVirtualBlockSize
;
979 /* No free space, need to alloc a new VM block */
980 Size
= DPH_POOL_SIZE
;
981 SizeVirtual
= DPH_RESERVE_SIZE
;
982 Status
= RtlpDphAllocateVm(&Ptr
, SizeVirtual
, MEM_COMMIT
, PAGE_NOACCESS
);
984 if (!NT_SUCCESS(Status
))
986 /* Retry with a smaller size */
987 SizeVirtual
= 0x10000;
988 Status
= RtlpDphAllocateVm(&Ptr
, SizeVirtual
, MEM_COMMIT
, PAGE_NOACCESS
);
989 if (!NT_SUCCESS(Status
)) return NULL
;
993 /* VM is allocated at this point, set protection */
994 Status
= RtlpDphProtectVm(Ptr
, Size
, PAGE_READWRITE
);
995 if (!NT_SUCCESS(Status
))
999 RtlpDphCoalesceNodeIntoAvailable(DphRoot
, Node
);
1010 /* Zero the memory */
1011 if (Node
) RtlZeroMemory(Ptr
, Size
);
1013 /* Add a new pool based on this VM */
1014 RtlpDphAddNewPool(DphRoot
, Node
, Ptr
, Size
, TRUE
);
1018 if (Node
->nVirtualBlockSize
> Size
)
1020 Node
->pVirtualBlock
+= Size
;
1021 Node
->nVirtualBlockSize
-= Size
;
1023 RtlpDphCoalesceNodeIntoAvailable(DphRoot
, Node
);
1027 RtlpDphReturnNodeToUnusedList(DphRoot
, Node
);
1032 /* The new VM block was just allocated a few code lines ago,
1034 Node
= RtlpDphTakeNodeFromUnusedList(DphRoot
);
1035 Node
->pVirtualBlock
= Ptr
;
1036 Node
->nVirtualBlockSize
= SizeVirtual
;
1037 RtlpDphPlaceOnVirtualList(DphRoot
, Node
);
1039 Node
= RtlpDphTakeNodeFromUnusedList(DphRoot
);
1040 Node
->pVirtualBlock
= (PUCHAR
)Ptr
+ Size
;
1041 Node
->nVirtualBlockSize
= SizeVirtual
- Size
;
1042 RtlpDphPlaceOnVirtualList(DphRoot
, Node
);
1044 /* Coalesce them into available list */
1045 RtlpDphCoalesceNodeIntoAvailable(DphRoot
, Node
);
1049 return RtlpDphTakeNodeFromUnusedList(DphRoot
);
1053 RtlpDphGrowVirtual(PDPH_HEAP_ROOT DphRoot
,
1056 PDPH_HEAP_BLOCK Node
, AvailableNode
;
1061 /* Start with allocating a couple of nodes */
1062 Node
= RtlpDphAllocateNode(DphRoot
);
1063 if (!Node
) return FALSE
;
1065 AvailableNode
= RtlpDphAllocateNode(DphRoot
);
1068 /* Free the allocated node and return failure */
1069 RtlpDphReturnNodeToUnusedList(DphRoot
, Node
);
1073 /* Calculate size of VM to allocate by rounding it up */
1074 Size
= ROUND_UP(Size
, 0xFFFF);
1076 if (Size
< DPH_RESERVE_SIZE
)
1077 VirtualSize
= DPH_RESERVE_SIZE
;
1079 /* Allocate the virtual memory */
1080 // FIXME: Shouldn't it be MEM_RESERVE with later committing?
1081 Status
= RtlpDphAllocateVm(&Base
, VirtualSize
, MEM_COMMIT
, PAGE_NOACCESS
);
1082 if (!NT_SUCCESS(Status
))
1084 /* Retry again with a smaller size */
1086 Status
= RtlpDphAllocateVm(&Base
, VirtualSize
, MEM_COMMIT
, PAGE_NOACCESS
);
1087 if (!NT_SUCCESS(Status
))
1089 /* Free the allocated node and return failure */
1090 RtlpDphReturnNodeToUnusedList(DphRoot
, Node
);
1091 RtlpDphReturnNodeToUnusedList(DphRoot
, AvailableNode
);
1096 /* Set up our two nodes describing this VM */
1097 Node
->pVirtualBlock
= Base
;
1098 Node
->nVirtualBlockSize
= VirtualSize
;
1099 AvailableNode
->pVirtualBlock
= Base
;
1100 AvailableNode
->nVirtualBlockSize
= VirtualSize
;
1102 /* Add them to virtual and available lists respectively */
1103 RtlpDphPlaceOnVirtualList(DphRoot
, Node
);
1104 RtlpDphCoalesceNodeIntoAvailable(DphRoot
, AvailableNode
);
1106 /* Return success */
1110 RTL_GENERIC_COMPARE_RESULTS
1112 RtlpDphCompareNodeForTable(IN PRTL_AVL_TABLE Table
,
1113 IN PVOID FirstStruct
,
1114 IN PVOID SecondStruct
)
1116 ULONG_PTR FirstBlock
, SecondBlock
;
1118 FirstBlock
= *((ULONG_PTR
*)FirstStruct
);
1119 SecondBlock
= *((ULONG_PTR
*)SecondStruct
);
1121 if (FirstBlock
< SecondBlock
)
1122 return GenericLessThan
;
1123 else if (FirstBlock
> SecondBlock
)
1124 return GenericGreaterThan
;
1126 return GenericEqual
;
1131 RtlpDphAllocateNodeForTable(IN PRTL_AVL_TABLE Table
,
1134 PDPH_HEAP_BLOCK pBlock
;
1135 PDPH_HEAP_ROOT DphRoot
;
1137 /* This mega-assert comes from a text search over Windows 2003 checked binary of ntdll.dll */
1138 ASSERT((ULONG_PTR
)(((PRTL_BALANCED_LINKS
)0)+1) + sizeof(PUCHAR
) == ByteSize
);
1140 /* Get pointer to the containing heap root record */
1141 DphRoot
= CONTAINING_RECORD(Table
, DPH_HEAP_ROOT
, BusyNodesTable
);
1142 pBlock
= DphRoot
->NodeToAllocate
;
1144 DphRoot
->NodeToAllocate
= NULL
;
1147 return &(pBlock
->TableLinks
);
1152 RtlpDphFreeNodeForTable(IN PRTL_AVL_TABLE Table
,
1159 RtlpDphInitializeDelayedFreeQueue()
1163 Status
= RtlInitializeCriticalSection(&RtlpDphDelayedFreeQueueLock
);
1164 if (!NT_SUCCESS(Status
))
1166 // TODO: Log this error!
1167 DPRINT1("Failure initializing delayed free queue critical section\n");
1171 /* Initialize lists */
1172 InitializeListHead(&RtlpDphDelayedFreeQueue
);
1173 RtlInitializeSListHead(&RtlpDphDelayedTemporaryPushList
);
1175 /* Reset counters */
1176 RtlpDphMemoryUsedByDelayedFreeBlocks
= 0;
1177 RtlpDphNumberOfDelayedFreeBlocks
= 0;
1183 RtlpDphFreeDelayedBlocksFromHeap(PDPH_HEAP_ROOT DphRoot
,
1186 PLIST_ENTRY Current
, Next
;
1187 PDPH_BLOCK_INFORMATION BlockInfo
;
1188 ULONG ValidationInfo
;
1190 /* The original routine seems to use a temporary SList to put blocks to be freed,
1191 then it releases the lock and frees the blocks. But let's make it simple for now */
1193 /* Acquire the delayed free queue lock */
1194 RtlEnterCriticalSection(&RtlpDphDelayedFreeQueueLock
);
1196 /* Traverse the list */
1197 Current
= RtlpDphDelayedFreeQueue
.Flink
;
1198 while (Current
!= &RtlpDphDelayedFreeQueue
);
1200 /* Get the next entry pointer */
1201 Next
= Current
->Flink
;
1203 BlockInfo
= CONTAINING_RECORD(Current
, DPH_BLOCK_INFORMATION
, FreeQueue
);
1205 /* Check if it belongs to the same heap */
1206 if (BlockInfo
->Heap
== DphRoot
)
1208 /* Remove it from the list */
1209 RemoveEntryList(Current
);
1211 /* Reset its heap to NULL */
1212 BlockInfo
->Heap
= NULL
;
1214 if (!RtlpDphIsNormalFreeHeapBlock(BlockInfo
+ 1, &ValidationInfo
, TRUE
))
1216 RtlpDphReportCorruptedBlock(DphRoot
, 10, BlockInfo
+ 1, ValidationInfo
);
1219 /* Decrement counters */
1220 RtlpDphMemoryUsedByDelayedFreeBlocks
-= BlockInfo
->ActualSize
;
1221 RtlpDphNumberOfDelayedFreeBlocks
--;
1223 /* Free the normal heap */
1224 RtlFreeHeap (NormalHeap
, 0, BlockInfo
);
1227 /* Move to the next one */
1231 /* Release the delayed free queue lock */
1232 RtlLeaveCriticalSection(&RtlpDphDelayedFreeQueueLock
);
1236 RtlpDphTargetDllsLogicInitialize()
1239 return STATUS_SUCCESS
;
1243 RtlpDphInternalValidatePageHeap(PDPH_HEAP_ROOT DphRoot
, PVOID Address
, ULONG Value
)
1249 RtlpDphVerifyIntegrity(PDPH_HEAP_ROOT DphRoot
)
1255 RtlpDphReportCorruptedBlock(PDPH_HEAP_ROOT DphRoot
,
1258 ULONG ValidationInfo
)
1260 //RtlpDphGetBlockSizeFromCorruptedBlock();
1262 if (ValidationInfo
& DPH_VALINFO_CORRUPTED_AFTER_FREE
)
1264 DPRINT1("block corrupted after having been freed\n");
1267 if (ValidationInfo
& DPH_VALINFO_ALREADY_FREED
)
1269 DPRINT1("block already freed\n");
1272 if (ValidationInfo
& DPH_VALINFO_BAD_INFIX_PATTERN
)
1274 DPRINT1("corrupted infix pattern for freed block\n");
1277 if (ValidationInfo
& DPH_VALINFO_BAD_POINTER
)
1279 DPRINT1("corrupted heap pointer or using wrong heap\n");
1282 if (ValidationInfo
& DPH_VALINFO_BAD_SUFFIX_PATTERN
)
1284 DPRINT1("corrupted suffix pattern\n");
1287 if (ValidationInfo
& DPH_VALINFO_BAD_PREFIX_PATTERN
)
1289 DPRINT1("corrupted prefix pattern\n");
1292 if (ValidationInfo
& DPH_VALINFO_BAD_START_STAMP
)
1294 DPRINT1("corrupted start stamp\n");
1297 if (ValidationInfo
& DPH_VALINFO_BAD_END_STAMP
)
1299 DPRINT1("corrupted end stamp\n");
1302 if (ValidationInfo
& DPH_VALINFO_EXCEPTION
)
1304 DPRINT1("exception raised while verifying block\n");
1307 DPRINT1("Corrupted heap block %p\n", Block
);
1311 RtlpDphIsPageHeapBlock(PDPH_HEAP_ROOT DphRoot
,
1313 PULONG ValidationInformation
,
1314 BOOLEAN CheckFillers
)
1316 PDPH_BLOCK_INFORMATION BlockInfo
;
1317 BOOLEAN SomethingWrong
= FALSE
;
1318 PUCHAR Byte
, Start
, End
;
1320 ASSERT(ValidationInformation
!= NULL
);
1321 *ValidationInformation
= 0;
1324 BlockInfo
= (PDPH_BLOCK_INFORMATION
)Block
- 1;
1327 if (BlockInfo
->StartStamp
!= DPH_FILL_START_STAMP_1
)
1329 *ValidationInformation
|= DPH_VALINFO_BAD_START_STAMP
;
1330 SomethingWrong
= TRUE
;
1332 /* Check if it has an alloc/free mismatch */
1333 if (BlockInfo
->StartStamp
== DPH_FILL_START_STAMP_2
)
1335 /* Notify respectively */
1336 *ValidationInformation
= 0x101;
1340 if (BlockInfo
->EndStamp
!= DPH_FILL_END_STAMP_1
)
1342 *ValidationInformation
|= DPH_VALINFO_BAD_END_STAMP
;
1343 SomethingWrong
= TRUE
;
1346 /* Check root heap pointer */
1347 if (BlockInfo
->Heap
!= DphRoot
)
1349 *ValidationInformation
|= DPH_VALINFO_BAD_POINTER
;
1350 SomethingWrong
= TRUE
;
1353 /* Check other fillers if requested */
1356 /* Check space after the block */
1357 Start
= (PUCHAR
)Block
+ BlockInfo
->RequestedSize
;
1358 End
= (PUCHAR
)ROUND_UP(Start
, PAGE_SIZE
);
1359 for (Byte
= Start
; Byte
< End
; Byte
++)
1361 if (*Byte
!= DPH_FILL_SUFFIX
)
1363 *ValidationInformation
|= DPH_VALINFO_BAD_SUFFIX_PATTERN
;
1364 SomethingWrong
= TRUE
;
1370 return (SomethingWrong
== FALSE
);
1374 RtlpDphIsNormalFreeHeapBlock(PVOID Block
,
1375 PULONG ValidationInformation
,
1376 BOOLEAN CheckFillers
)
1378 ASSERT(ValidationInformation
!= NULL
);
1381 *ValidationInformation
= 0;
1386 RtlpDphProcessStartupInitialization()
1389 PTEB Teb
= NtCurrentTeb();
1391 /* Initialize the DPH heap list and its critical section */
1392 InitializeListHead(&RtlpDphPageHeapList
);
1393 Status
= RtlInitializeCriticalSection(&RtlpDphPageHeapListLock
);
1394 if (!NT_SUCCESS(Status
))
1400 /* Initialize delayed-free queue */
1401 Status
= RtlpDphInitializeDelayedFreeQueue();
1402 if (!NT_SUCCESS(Status
)) return Status
;
1404 /* Initialize the target dlls string */
1405 RtlInitUnicodeString(&RtlpDphTargetDllsUnicode
, RtlpDphTargetDlls
);
1406 Status
= RtlpDphTargetDllsLogicInitialize();
1408 /* Per-process DPH init is done */
1409 RtlpDphPageHeapListInitialized
= TRUE
;
1411 DPRINT1("Page heap: pid 0x%X: page heap enabled with flags 0x%X.\n", Teb
->ClientId
.UniqueProcess
, RtlpDphGlobalFlags
);
1417 RtlpDphShouldAllocateInPageHeap(PDPH_HEAP_ROOT DphRoot
,
1421 /* Always use page heap for now */
1426 RtlpPageHeapCreate(ULONG Flags
,
1431 PRTL_HEAP_PARAMETERS Parameters
)
1435 PDPH_HEAP_ROOT DphRoot
;
1436 PDPH_HEAP_BLOCK DphNode
;
1439 LARGE_INTEGER PerfCounter
;
1441 /* Check for a DPH bypass flag */
1442 if ((ULONG_PTR
)Parameters
== -1) return NULL
;
1444 /* Make sure no user-allocated stuff was provided */
1445 if (Addr
|| Lock
) return NULL
;
1447 /* Allocate minimum amount of virtual memory */
1448 MemSize
= DPH_RESERVE_SIZE
;
1449 Status
= RtlpDphAllocateVm(&Base
, MemSize
, MEM_COMMIT
, PAGE_NOACCESS
);
1450 if (!NT_SUCCESS(Status
))
1456 /* Set protection */
1457 Status
= RtlpDphProtectVm(Base
, 2*PAGE_SIZE
+ DPH_POOL_SIZE
, PAGE_READWRITE
);
1458 if (!NT_SUCCESS(Status
))
1460 //RtlpDphFreeVm(Base, 0, 0, 0);
1465 /* Start preparing the 1st page. Fill it with the default filler */
1466 RtlFillMemory(Base
, PAGE_SIZE
, DPH_FILL
);
1468 /* Set flags in the "HEAP" structure */
1469 HeapPtr
= (PHEAP
)Base
;
1470 HeapPtr
->Flags
= Flags
| HEAP_FLAG_PAGE_ALLOCS
;
1471 HeapPtr
->ForceFlags
= Flags
| HEAP_FLAG_PAGE_ALLOCS
;
1473 /* Set 1st page to read only now */
1474 Status
= RtlpDphProtectVm(Base
, PAGE_SIZE
, PAGE_READONLY
);
1475 if (!NT_SUCCESS(Status
))
1481 /* 2nd page is the real DPH root block */
1482 DphRoot
= (PDPH_HEAP_ROOT
)((PCHAR
)Base
+ PAGE_SIZE
);
1484 /* Initialize the DPH root */
1485 DphRoot
->Signature
= DPH_SIGNATURE
;
1486 DphRoot
->HeapFlags
= Flags
;
1487 DphRoot
->HeapCritSect
= (PRTL_CRITICAL_SECTION
)((PCHAR
)DphRoot
+ DPH_POOL_SIZE
);
1488 DphRoot
->ExtraFlags
= RtlpDphGlobalFlags
;
1490 ZwQueryPerformanceCounter(&PerfCounter
, NULL
);
1491 DphRoot
->Seed
= PerfCounter
.LowPart
;
1493 RtlInitializeCriticalSection(DphRoot
->HeapCritSect
);
1494 InitializeListHead(&DphRoot
->AvailableAllocationHead
);
1496 /* Create a normal heap for this paged heap */
1497 DphRoot
->NormalHeap
= RtlCreateHeap(Flags
, NULL
, TotalSize
, CommitSize
, NULL
, (PRTL_HEAP_PARAMETERS
)-1);
1498 if (!DphRoot
->NormalHeap
)
1504 /* 3rd page: a pool for DPH allocations */
1505 RtlpDphAddNewPool(DphRoot
, NULL
, DphRoot
+ 1, DPH_POOL_SIZE
- sizeof(DPH_HEAP_ROOT
), FALSE
);
1507 /* Allocate internal heap blocks. For the root */
1508 DphNode
= RtlpDphAllocateNode(DphRoot
);
1509 ASSERT(DphNode
!= NULL
);
1510 DphNode
->pVirtualBlock
= (PUCHAR
)DphRoot
;
1511 DphNode
->nVirtualBlockSize
= DPH_POOL_SIZE
;
1512 RtlpDphPlaceOnPoolList(DphRoot
, DphNode
);
1514 /* For the memory we allocated as a whole */
1515 DphNode
= RtlpDphAllocateNode(DphRoot
);
1516 ASSERT(DphNode
!= NULL
);
1517 DphNode
->pVirtualBlock
= Base
;
1518 DphNode
->nVirtualBlockSize
= MemSize
;
1519 RtlpDphPlaceOnVirtualList(DphRoot
, DphNode
);
1521 /* For the remaining part */
1522 DphNode
= RtlpDphAllocateNode(DphRoot
);
1523 ASSERT(DphNode
!= NULL
);
1524 DphNode
->pVirtualBlock
= (PUCHAR
)Base
+ 2*PAGE_SIZE
+ DPH_POOL_SIZE
;
1525 DphNode
->nVirtualBlockSize
= MemSize
- (2*PAGE_SIZE
+ DPH_POOL_SIZE
);
1526 RtlpDphCoalesceNodeIntoAvailable(DphRoot
, DphNode
);
1528 //DphRoot->CreateStackTrace = RtlpDphLogStackTrace(1);
1530 /* Initialize AVL-based busy nodes table */
1531 RtlInitializeGenericTableAvl(&DphRoot
->BusyNodesTable
,
1532 RtlpDphCompareNodeForTable
,
1533 RtlpDphAllocateNodeForTable
,
1534 RtlpDphFreeNodeForTable
,
1537 /* Initialize per-process startup info */
1538 if (!RtlpDphPageHeapListInitialized
) RtlpDphProcessStartupInitialization();
1540 /* Acquire the heap list lock */
1541 RtlEnterCriticalSection(&RtlpDphPageHeapListLock
);
1543 /* Insert this heap to the tail of the global list */
1544 InsertTailList(&RtlpDphPageHeapList
, &DphRoot
->NextHeap
);
1546 /* Note we increased the size of the list */
1547 RtlpDphPageHeapListLength
++;
1549 /* Release the heap list lock */
1550 RtlLeaveCriticalSection(&RtlpDphPageHeapListLock
);
1552 if (RtlpDphDebugOptions
& DPH_DEBUG_VERBOSE
)
1554 DPRINT1("Page heap: process 0x%X created heap @ %p (%p, flags 0x%X)\n",
1555 NtCurrentTeb()->ClientId
.UniqueProcess
, (PUCHAR
)DphRoot
- PAGE_SIZE
, DphRoot
->NormalHeap
, DphRoot
->ExtraFlags
);
1558 /* Perform internal validation if required */
1559 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
)
1560 RtlpDphInternalValidatePageHeap(DphRoot
, NULL
, 0);
1562 return (PUCHAR
)DphRoot
- PAGE_SIZE
;
1566 RtlpPageHeapDestroy(HANDLE HeapPtr
)
1568 PDPH_HEAP_ROOT DphRoot
;
1569 PDPH_HEAP_BLOCK Node
, Next
;
1573 /* Check if it's not a process heap */
1574 if (HeapPtr
== RtlGetProcessHeap())
1580 /* Get pointer to the heap root */
1581 DphRoot
= RtlpDphPointerFromHandle(HeapPtr
);
1582 if (!DphRoot
) return NULL
;
1584 RtlpDphPreProcessing(DphRoot
, DphRoot
->HeapFlags
);
1586 /* Get the pointer to the normal heap */
1587 NormalHeap
= DphRoot
->NormalHeap
;
1589 /* Free the delayed-free blocks */
1590 RtlpDphFreeDelayedBlocksFromHeap(DphRoot
, NormalHeap
);
1592 /* Go through the busy blocks */
1593 Node
= RtlEnumerateGenericTableAvl(&DphRoot
->BusyNodesTable
, TRUE
);
1597 if (!(DphRoot
->ExtraFlags
& DPH_EXTRA_CHECK_UNDERRUN
))
1599 if (!RtlpDphIsPageHeapBlock(DphRoot
, Node
->pUserAllocation
, &Value
, TRUE
))
1601 RtlpDphReportCorruptedBlock(DphRoot
, 3, Node
->pUserAllocation
, Value
);
1605 /* FIXME: Call AV notification */
1606 //AVrfInternalHeapFreeNotification();
1608 /* Go to the next node */
1609 Node
= RtlEnumerateGenericTableAvl(&DphRoot
->BusyNodesTable
, FALSE
);
1612 /* Acquire the global heap list lock */
1613 RtlEnterCriticalSection(&RtlpDphPageHeapListLock
);
1615 /* Remove the entry and decrement the global counter */
1616 RemoveEntryList(&DphRoot
->NextHeap
);
1617 RtlpDphPageHeapListLength
--;
1619 /* Release the global heap list lock */
1620 RtlLeaveCriticalSection(&RtlpDphPageHeapListLock
);
1622 /* Leave and delete this heap's critical section */
1623 RtlLeaveCriticalSection(DphRoot
->HeapCritSect
);
1624 RtlDeleteCriticalSection(DphRoot
->HeapCritSect
);
1626 /* Now go through all virtual list nodes and release the VM */
1627 Node
= DphRoot
->pVirtualStorageListHead
;
1630 Next
= Node
->pNextAlloc
;
1631 /* Release the memory without checking result */
1632 RtlpDphFreeVm(Node
->pVirtualBlock
, 0, MEM_RELEASE
);
1636 /* Destroy the normal heap */
1637 RtlDestroyHeap(NormalHeap
);
1639 /* Report success */
1640 if (RtlpDphDebugOptions
& DPH_DEBUG_VERBOSE
)
1641 DPRINT1("Page heap: process 0x%X destroyed heap @ %p (%p)\n", NtCurrentTeb()->ClientId
.UniqueProcess
, HeapPtr
, NormalHeap
);
1647 RtlpPageHeapAllocate(IN PVOID HeapPtr
,
1651 PDPH_HEAP_ROOT DphRoot
;
1652 PDPH_HEAP_BLOCK Node
, AllocatedNode
;
1653 BOOLEAN Biased
= FALSE
;
1654 ULONG TotalSize
, AccessSize
;
1656 SIZE_T UserActualSize
;
1659 /* Check requested size */
1660 if (Size
> 0x7FF00000)
1662 DPRINT1("extreme size request\n");
1664 /* Generate an exception if needed */
1665 if (Flags
& HEAP_GENERATE_EXCEPTIONS
) RtlpDphRaiseException(STATUS_NO_MEMORY
);
1670 /* Unbias the pointer if necessary */
1671 if (IS_BIASED_POINTER(HeapPtr
))
1673 HeapPtr
= (PVOID
)POINTER_REMOVE_BIAS(HeapPtr
);
1677 /* Get a pointer to the heap root */
1678 DphRoot
= RtlpDphPointerFromHandle(HeapPtr
);
1679 if (!DphRoot
) return NULL
;
1681 /* Acquire the heap lock */
1682 //RtlpDphEnterCriticalSection(DphRoot, Flags);
1683 RtlpDphPreProcessing(DphRoot
, Flags
);
1685 /* Perform internal validation if specified by flags */
1686 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
&& !Biased
)
1688 RtlpDphInternalValidatePageHeap(DphRoot
, NULL
, 0);
1691 /* Add heap flags */
1692 Flags
|= DphRoot
->HeapFlags
;
1694 if (!Biased
&& !RtlpDphShouldAllocateInPageHeap(DphRoot
, Size
))
1696 /* Perform allocation from a normal heap */
1700 /* Perform heap integrity check if specified by flags */
1701 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
)
1703 RtlpDphVerifyIntegrity(DphRoot
);
1706 /* Calculate sizes */
1707 AccessSize
= ROUND_UP(Size
+ sizeof(DPH_BLOCK_INFORMATION
), PAGE_SIZE
);
1708 TotalSize
= AccessSize
+ PAGE_SIZE
;
1710 // RtlpDphAllocateNode(DphRoot);
1711 Node
= RtlpDphFindAvailableMemory(DphRoot
, TotalSize
, TRUE
);
1714 DPRINT1("Page heap: Unable to allocate virtual memory\n");
1717 /* Release the lock */
1718 RtlpDphPostProcessing(DphRoot
);
1722 ASSERT(Node
->nVirtualBlockSize
>= TotalSize
);
1724 /* Set protection */
1725 Status
= RtlpDphSetProtectionBeforeUse(DphRoot
, Node
->pVirtualBlock
, AccessSize
);
1726 if (!NT_SUCCESS(Status
))
1731 Ptr
= Node
->pVirtualBlock
;
1733 /* Check node's size */
1734 if (Node
->nVirtualBlockSize
> TotalSize
)
1736 /* The block contains too much free space, reduce it */
1737 Node
->pVirtualBlock
+= TotalSize
;
1738 Node
->nVirtualBlockSize
-= TotalSize
;
1739 DphRoot
->nAvailableAllocationBytesCommitted
-= TotalSize
;
1741 AllocatedNode
= RtlpDphAllocateNode(DphRoot
);
1742 ASSERT(AllocatedNode
!= NULL
);
1743 AllocatedNode
->pVirtualBlock
= Ptr
;
1744 AllocatedNode
->nVirtualBlockSize
= TotalSize
;
1748 /* The block's size fits exactly */
1749 RtlpDphRemoveFromAvailableList(DphRoot
, Node
);
1750 AllocatedNode
= Node
;
1753 /* Calculate actual user size */
1754 if (DphRoot
->HeapFlags
& HEAP_NO_ALIGNMENT
)
1755 UserActualSize
= Size
;
1757 UserActualSize
= ROUND_UP(Size
, 8);
1759 /* Set up the block */
1760 AllocatedNode
->nVirtualAccessSize
= AccessSize
;
1761 AllocatedNode
->nUserActualSize
= UserActualSize
;
1762 AllocatedNode
->nUserRequestedSize
= Size
;
1764 if (DphRoot
->ExtraFlags
& DPH_EXTRA_CHECK_UNDERRUN
)
1765 AllocatedNode
->pUserAllocation
= AllocatedNode
->pVirtualBlock
+ PAGE_SIZE
;
1767 AllocatedNode
->pUserAllocation
= AllocatedNode
->pVirtualBlock
+ AllocatedNode
->nVirtualAccessSize
- UserActualSize
;
1769 AllocatedNode
->UserValue
= NULL
;
1770 AllocatedNode
->UserFlags
= Flags
& HEAP_SETTABLE_USER_FLAGS
;
1772 // FIXME: Don't forget about stack traces if such flag was set
1773 AllocatedNode
->StackTrace
= NULL
;
1775 /* Place it on busy list */
1776 RtlpDphPlaceOnBusyList(DphRoot
, AllocatedNode
);
1778 /* Zero or patter-fill memory depending on flags */
1779 if (Flags
& HEAP_ZERO_MEMORY
)
1780 RtlZeroMemory(AllocatedNode
->pUserAllocation
, Size
);
1782 RtlFillMemory(AllocatedNode
->pUserAllocation
, Size
, DPH_FILL_INFIX
);
1784 /* Write DPH info */
1785 if (!(DphRoot
->ExtraFlags
& DPH_EXTRA_CHECK_UNDERRUN
))
1787 RtlpDphWritePageHeapBlockInformation(DphRoot
, AllocatedNode
->pUserAllocation
, Size
, AccessSize
);
1790 /* Finally allocation is done, perform validation again if required */
1791 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
&& !Biased
)
1793 RtlpDphInternalValidatePageHeap(DphRoot
, NULL
, 0);
1796 /* Release the lock */
1797 RtlpDphPostProcessing(DphRoot
);
1799 DPRINT("Allocated user block pointer: %p\n", AllocatedNode
->pUserAllocation
);
1801 /* Return pointer to user allocation */
1802 return AllocatedNode
->pUserAllocation
;
1806 RtlpPageHeapFree(HANDLE HeapPtr
,
1810 PDPH_HEAP_ROOT DphRoot
;
1811 PDPH_HEAP_BLOCK Node
;
1812 ULONG ValidationInfo
;
1813 PDPH_BLOCK_INFORMATION Info
;
1815 /* Check for a NULL pointer freeing */
1818 if (RtlpDphBreakOptions
& DPH_BREAK_ON_NULL_FREE
)
1820 DPRINT1("Page heap: freeing a null pointer \n");
1826 /* Get a pointer to the heap root */
1827 DphRoot
= RtlpDphPointerFromHandle(HeapPtr
);
1828 if (!DphRoot
) return FALSE
;
1830 /* Acquire the heap lock */
1831 RtlpDphPreProcessing(DphRoot
, Flags
);
1833 /* Perform internal validation if specified by flags */
1834 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
)
1835 RtlpDphInternalValidatePageHeap(DphRoot
, NULL
, 0);
1837 /* Add heap flags */
1838 Flags
|= DphRoot
->HeapFlags
;
1840 /* Find busy memory */
1841 Node
= RtlpDphFindBusyMemory(DphRoot
, Ptr
);
1845 /* This block was not found in page heap, try a normal heap instead */
1846 //RtlpDphNormalHeapFree();
1850 if (!(DphRoot
->ExtraFlags
& DPH_EXTRA_CHECK_UNDERRUN
))
1852 /* Check and report corrupted block */
1853 if (!RtlpDphIsPageHeapBlock(DphRoot
, Ptr
, &ValidationInfo
, TRUE
))
1855 RtlpDphReportCorruptedBlock(DphRoot
, 1, Ptr
, ValidationInfo
);
1858 // FIXME: Should go inside RtlpDphSetProtectionAfterUse
1859 if (Node
->nVirtualAccessSize
!= 0)
1862 Info
= (PDPH_BLOCK_INFORMATION
)Node
->pUserAllocation
- 1;
1863 Info
->StartStamp
= DPH_FILL_START_STAMP_2
;
1864 Info
->EndStamp
= DPH_FILL_END_STAMP_2
;
1866 RtlpDphProtectVm(Node
->pVirtualBlock
, Node
->nVirtualAccessSize
, PAGE_NOACCESS
);
1871 // FIXME: Should go inside RtlpDphSetProtectionAfterUse
1872 if (Node
->nVirtualAccessSize
!= 0)
1873 RtlpDphProtectVm(Node
->pVirtualBlock
+ PAGE_SIZE
, Node
->nVirtualAccessSize
, PAGE_NOACCESS
);
1876 /* Set new protection */
1877 RtlpDphSetProtectionAfterUse(DphRoot
, Node
);
1879 /* Remove it from the list of busy nodes */
1880 RtlpDphRemoveFromBusyList(DphRoot
, Node
);
1882 /* And put it into the list of free nodes */
1883 RtlpDphPlaceOnFreeList(DphRoot
, Node
);
1885 //if (DphRoot->ExtraFlags & DPH_EXTRA_LOG_STACK_TRACES)
1886 // Node->StackTrace = RtlpDphLogStackTrace(3);
1888 Node
->StackTrace
= NULL
;
1890 /* Leave the heap lock */
1891 RtlpDphPostProcessing(DphRoot
);
1893 /* Return success */
1898 RtlpPageHeapReAllocate(HANDLE HeapPtr
,
1903 PDPH_HEAP_ROOT DphRoot
;
1904 PDPH_HEAP_BLOCK Node
= NULL
, AllocatedNode
;
1905 BOOLEAN Biased
= FALSE
, UseNormalHeap
= FALSE
, OldBlockPageHeap
= TRUE
;
1906 ULONG DataSize
, ValidationInfo
;
1907 PVOID NewAlloc
= NULL
;
1909 /* Check requested size */
1910 if (Size
> 0x7FF00000)
1912 DPRINT1("extreme size request\n");
1914 /* Generate an exception if needed */
1915 if (Flags
& HEAP_GENERATE_EXCEPTIONS
) RtlpDphRaiseException(STATUS_NO_MEMORY
);
1920 /* Unbias the pointer if necessary */
1921 if (IS_BIASED_POINTER(HeapPtr
))
1923 HeapPtr
= (PVOID
)POINTER_REMOVE_BIAS(HeapPtr
);
1927 /* Get a pointer to the heap root */
1928 DphRoot
= RtlpDphPointerFromHandle(HeapPtr
);
1929 if (!DphRoot
) return NULL
;
1931 /* Acquire the heap lock */
1932 RtlpDphPreProcessing(DphRoot
, Flags
);
1934 /* Perform internal validation if specified by flags */
1935 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
)
1937 RtlpDphInternalValidatePageHeap(DphRoot
, NULL
, 0);
1940 /* Add heap flags */
1941 Flags
|= DphRoot
->HeapFlags
;
1943 /* Exit with NULL right away if inplace is specified */
1944 if (Flags
& HEAP_REALLOC_IN_PLACE_ONLY
)
1946 /* Release the lock */
1947 RtlpDphPostProcessing(DphRoot
);
1949 /* Generate an exception if needed */
1950 if (Flags
& HEAP_GENERATE_EXCEPTIONS
) RtlpDphRaiseException(STATUS_NO_MEMORY
);
1955 /* Try to get node of the allocated block */
1956 AllocatedNode
= RtlpDphFindBusyMemory(DphRoot
, Ptr
);
1960 /* This block was not found in page heap, try a normal heap instead */
1961 //RtlpDphNormalHeapFree();
1963 OldBlockPageHeap
= FALSE
;
1966 /* Check the block */
1967 if (!(DphRoot
->ExtraFlags
& DPH_EXTRA_CHECK_UNDERRUN
))
1969 if (!RtlpDphIsPageHeapBlock(DphRoot
, AllocatedNode
->pUserAllocation
, &ValidationInfo
, TRUE
))
1971 RtlpDphReportCorruptedBlock(DphRoot
, 3, AllocatedNode
->pUserAllocation
, ValidationInfo
);
1975 /* Remove old one from the busy list */
1976 RtlpDphRemoveFromBusyList(DphRoot
, AllocatedNode
);
1978 if (!Biased
&& !RtlpDphShouldAllocateInPageHeap(DphRoot
, Size
))
1980 // FIXME: Use normal heap
1982 UseNormalHeap
= TRUE
;
1986 /* Now do a trick: bias the pointer and call our allocate routine */
1987 NewAlloc
= RtlpPageHeapAllocate((PVOID
)POINTER_ADD_BIAS(HeapPtr
), Flags
, Size
);
1992 /* New allocation failed, put the block back (if it was found in page heap) */
1993 RtlpDphPlaceOnBusyList(DphRoot
, AllocatedNode
);
1995 /* Release the lock */
1996 RtlpDphPostProcessing(DphRoot
);
1998 /* Perform validation again if required */
1999 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
)
2001 RtlpDphInternalValidatePageHeap(DphRoot
, NULL
, 0);
2004 /* Generate an exception if needed */
2005 if (Flags
& HEAP_GENERATE_EXCEPTIONS
) RtlpDphRaiseException(STATUS_NO_MEMORY
);
2010 /* Copy contents of the old block */
2011 if (AllocatedNode
->nUserRequestedSize
> Size
)
2014 DataSize
= AllocatedNode
->nUserRequestedSize
;
2016 if (DataSize
!= 0) RtlCopyMemory(NewAlloc
, Ptr
, DataSize
);
2018 /* Copy user flags and values */
2021 /* Get the node of the new block */
2022 Node
= RtlpDphFindBusyMemory(DphRoot
, NewAlloc
);
2023 ASSERT(Node
!= NULL
);
2025 /* Set its values/flags */
2026 Node
->UserValue
= AllocatedNode
->UserValue
;
2027 if (Flags
& HEAP_SETTABLE_USER_FLAGS
)
2028 Node
->UserFlags
= Flags
& HEAP_SETTABLE_USER_FLAGS
;
2030 Node
->UserFlags
= AllocatedNode
->UserFlags
;
2033 if (!OldBlockPageHeap
)
2035 /* Weird scenario, investigate */
2039 /* Mark the old block as no access */
2040 if (AllocatedNode
->nVirtualAccessSize
!= 0)
2042 RtlpDphProtectVm(AllocatedNode
->pVirtualBlock
, AllocatedNode
->nVirtualAccessSize
, PAGE_NOACCESS
);
2045 /* And place it on the free list */
2046 RtlpDphPlaceOnFreeList(DphRoot
, AllocatedNode
);
2048 // FIXME: Capture stack traces if needed
2049 AllocatedNode
->StackTrace
= NULL
;
2051 /* Finally allocation is done, perform validation again if required */
2052 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
&& !Biased
)
2054 RtlpDphInternalValidatePageHeap(DphRoot
, NULL
, 0);
2057 /* Release the lock */
2058 RtlpDphPostProcessing(DphRoot
);
2060 DPRINT("Allocated new user block pointer: %p\n", NewAlloc
);
2062 /* Return pointer to user allocation */
2067 RtlpPageHeapGetUserInfo(PVOID HeapHandle
,
2073 PDPH_HEAP_ROOT DphRoot
;
2074 PDPH_HEAP_BLOCK Node
;
2076 /* Get a pointer to the heap root */
2077 DphRoot
= RtlpDphPointerFromHandle(HeapHandle
);
2078 if (!DphRoot
) return FALSE
;
2080 /* Add heap flags */
2081 Flags
|= DphRoot
->HeapFlags
;
2083 /* Acquire the heap lock */
2084 RtlpDphPreProcessing(DphRoot
, Flags
);
2086 /* Find busy memory */
2087 Node
= RtlpDphFindBusyMemory(DphRoot
, BaseAddress
);
2091 /* This block was not found in page heap, try a normal heap instead */
2092 //RtlpDphNormalHeapGetUserInfo();
2097 /* Get user values and flags and store them in user provided pointers */
2098 if (UserValue
) *UserValue
= Node
->UserValue
;
2099 if (UserFlags
) *UserFlags
= Node
->UserFlags
;
2101 /* Leave the heap lock */
2102 RtlpDphPostProcessing(DphRoot
);
2104 /* Return success */
2109 RtlpPageHeapSetUserValue(PVOID HeapHandle
,
2114 PDPH_HEAP_ROOT DphRoot
;
2115 PDPH_HEAP_BLOCK Node
;
2117 /* Get a pointer to the heap root */
2118 DphRoot
= RtlpDphPointerFromHandle(HeapHandle
);
2119 if (!DphRoot
) return FALSE
;
2121 /* Add heap flags */
2122 Flags
|= DphRoot
->HeapFlags
;
2124 /* Acquire the heap lock */
2125 RtlpDphPreProcessing(DphRoot
, Flags
);
2127 /* Find busy memory */
2128 Node
= RtlpDphFindBusyMemory(DphRoot
, BaseAddress
);
2132 /* This block was not found in page heap, try a normal heap instead */
2133 //RtlpDphNormalHeapSetUserValue();
2138 /* Get user values and flags and store them in user provided pointers */
2139 Node
->UserValue
= UserValue
;
2141 /* Leave the heap lock */
2142 RtlpDphPostProcessing(DphRoot
);
2144 /* Return success */
2150 RtlpPageHeapSetUserFlags(PVOID HeapHandle
,
2153 ULONG UserFlagsReset
,
2156 PDPH_HEAP_ROOT DphRoot
;
2157 PDPH_HEAP_BLOCK Node
;
2159 /* Get a pointer to the heap root */
2160 DphRoot
= RtlpDphPointerFromHandle(HeapHandle
);
2161 if (!DphRoot
) return FALSE
;
2163 /* Add heap flags */
2164 Flags
|= DphRoot
->HeapFlags
;
2166 /* Acquire the heap lock */
2167 RtlpDphPreProcessing(DphRoot
, Flags
);
2169 /* Find busy memory */
2170 Node
= RtlpDphFindBusyMemory(DphRoot
, BaseAddress
);
2174 /* This block was not found in page heap, try a normal heap instead */
2175 //RtlpDphNormalHeapSetUserFlags();
2180 /* Get user values and flags and store them in user provided pointers */
2181 Node
->UserFlags
&= ~(UserFlagsReset
);
2182 Node
->UserFlags
|= UserFlagsSet
;
2184 /* Leave the heap lock */
2185 RtlpDphPostProcessing(DphRoot
);
2187 /* Return success */
2192 RtlpPageHeapSize(HANDLE HeapHandle
,
2196 PDPH_HEAP_ROOT DphRoot
;
2197 PDPH_HEAP_BLOCK Node
;
2200 /* Get a pointer to the heap root */
2201 DphRoot
= RtlpDphPointerFromHandle(HeapHandle
);
2202 if (!DphRoot
) return -1;
2204 /* Add heap flags */
2205 Flags
|= DphRoot
->HeapFlags
;
2207 /* Acquire the heap lock */
2208 RtlpDphPreProcessing(DphRoot
, Flags
);
2210 /* Find busy memory */
2211 Node
= RtlpDphFindBusyMemory(DphRoot
, BaseAddress
);
2215 /* This block was not found in page heap, try a normal heap instead */
2216 //RtlpDphNormalHeapSize();
2221 /* Get heap block size */
2222 Size
= Node
->nUserRequestedSize
;
2224 /* Leave the heap lock */
2225 RtlpDphPostProcessing(DphRoot
);
2227 /* Return user requested size */
2233 RtlpDebugPageHeapValidate(PVOID HeapHandle
,
2237 PDPH_HEAP_ROOT DphRoot
;
2238 PDPH_HEAP_BLOCK Node
= NULL
;
2239 BOOLEAN Valid
= FALSE
;
2241 /* Get a pointer to the heap root */
2242 DphRoot
= RtlpDphPointerFromHandle(HeapHandle
);
2243 if (!DphRoot
) return -1;
2245 /* Add heap flags */
2246 Flags
|= DphRoot
->HeapFlags
;
2248 /* Acquire the heap lock */
2249 RtlpDphPreProcessing(DphRoot
, Flags
);
2251 /* Find busy memory */
2253 Node
= RtlpDphFindBusyMemory(DphRoot
, BaseAddress
);
2257 /* This block was not found in page heap, or the request is to validate all normal heap */
2258 Valid
= RtlpDphNormalHeapValidate(DphRoot
, Flags
, BaseAddress
);
2261 /* Leave the heap lock */
2262 RtlpDphPostProcessing(DphRoot
);
2264 /* Return result of a normal heap validation */
2265 if (BaseAddress
&& !Node
)
2268 /* Otherwise return our own result */
2269 if (!BaseAddress
|| Node
) Valid
= TRUE
;
2276 RtlpDphNormalHeapValidate(PDPH_HEAP_ROOT DphRoot
,
2280 PDPH_BLOCK_INFORMATION BlockInfo
= (PDPH_BLOCK_INFORMATION
)BaseAddress
- 1;
2283 /* Validate all normal heap */
2284 return RtlValidateHeap(DphRoot
->NormalHeap
, Flags
, NULL
);
2287 // FIXME: Check is this a normal heap block
2288 /*if (!RtlpDphIsNormalHeapBlock(DphRoot, BaseAddress, &ValidationInfo))
2292 return RtlValidateHeap(DphRoot
->NormalHeap
, Flags
, BlockInfo
);