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 SIZE_T nVirtualBlockSize
;
50 SIZE_T nVirtualAccessSize
;
51 SIZE_T nUserRequestedSize
;
52 SIZE_T 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 PHEAP_LOCK HeapCritSect
;
65 ULONG nRemoteLockAcquired
;
67 PDPH_HEAP_BLOCK pVirtualStorageListHead
;
68 PDPH_HEAP_BLOCK pVirtualStorageListTail
;
69 ULONG nVirtualStorageRanges
;
70 SIZE_T nVirtualStorageBytes
;
72 RTL_AVL_TABLE BusyNodesTable
;
73 PDPH_HEAP_BLOCK NodeToAllocate
;
74 ULONG nBusyAllocations
;
75 SIZE_T nBusyAllocationBytesCommitted
;
77 PDPH_HEAP_BLOCK pFreeAllocationListHead
;
78 PDPH_HEAP_BLOCK pFreeAllocationListTail
;
79 ULONG nFreeAllocations
;
80 SIZE_T nFreeAllocationBytesCommitted
;
82 LIST_ENTRY AvailableAllocationHead
;
83 ULONG nAvailableAllocations
;
84 SIZE_T nAvailableAllocationBytesCommitted
;
86 PDPH_HEAP_BLOCK pUnusedNodeListHead
;
87 PDPH_HEAP_BLOCK pUnusedNodeListTail
;
89 SIZE_T nBusyAllocationBytesAccessible
;
90 PDPH_HEAP_BLOCK pNodePoolListHead
;
91 PDPH_HEAP_BLOCK pNodePoolListTail
;
93 SIZE_T nNodePoolBytes
;
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 HEAP_LOCK _RtlpDphPageHeapListLock
;
114 PHEAP_LOCK RtlpDphPageHeapListLock
= &_RtlpDphPageHeapListLock
;
115 ULONG RtlpDphPageHeapListLength
;
116 UNICODE_STRING RtlpDphTargetDllsUnicode
;
118 HEAP_LOCK _RtlpDphDelayedFreeQueueLock
;
119 PHEAP_LOCK RtlpDphDelayedFreeQueueLock
= &_RtlpDphDelayedFreeQueueLock
;
120 LIST_ENTRY RtlpDphDelayedFreeQueue
;
121 SLIST_HEADER RtlpDphDelayedTemporaryPushList
;
122 SIZE_T RtlpDphMemoryUsedByDelayedFreeBlocks
;
123 ULONG RtlpDphNumberOfDelayedFreeBlocks
;
127 LONG RtlpDphAllocFails
;
128 LONG RtlpDphReleaseFails
;
129 LONG RtlpDphFreeFails
;
130 LONG RtlpDphProtectFails
;
132 #define DPH_RESERVE_SIZE 0x100000
133 #define DPH_POOL_SIZE 0x4000
134 #define DPH_FREE_LIST_MINIMUM 8
136 /* RtlpDphBreakOptions */
137 #define DPH_BREAK_ON_RESERVE_FAIL 0x01
138 #define DPH_BREAK_ON_COMMIT_FAIL 0x02
139 #define DPH_BREAK_ON_RELEASE_FAIL 0x04
140 #define DPH_BREAK_ON_FREE_FAIL 0x08
141 #define DPH_BREAK_ON_PROTECT_FAIL 0x10
142 #define DPH_BREAK_ON_NULL_FREE 0x80
144 /* RtlpDphDebugOptions */
145 #define DPH_DEBUG_INTERNAL_VALIDATE 0x01
146 #define DPH_DEBUG_VERBOSE 0x04
149 #define DPH_EXTRA_LOG_STACK_TRACES 0x02
150 #define DPH_EXTRA_CHECK_UNDERRUN 0x10
153 #define DPH_FILL 0xEEEEEEEE
154 #define DPH_FILL_START_STAMP_1 0xABCDBBBB
155 #define DPH_FILL_START_STAMP_2 0xABCDBBBA
156 #define DPH_FILL_END_STAMP_1 0xDCBABBBB
157 #define DPH_FILL_END_STAMP_2 0xDCBABBBA
158 #define DPH_FILL_SUFFIX 0xD0
159 #define DPH_FILL_INFIX 0xC0
161 /* Validation info flags */
162 #define DPH_VALINFO_BAD_START_STAMP 0x01
163 #define DPH_VALINFO_BAD_END_STAMP 0x02
164 #define DPH_VALINFO_BAD_POINTER 0x04
165 #define DPH_VALINFO_BAD_PREFIX_PATTERN 0x08
166 #define DPH_VALINFO_BAD_SUFFIX_PATTERN 0x10
167 #define DPH_VALINFO_EXCEPTION 0x20
168 #define DPH_VALINFO_1 0x40
169 #define DPH_VALINFO_BAD_INFIX_PATTERN 0x80
170 #define DPH_VALINFO_ALREADY_FREED 0x100
171 #define DPH_VALINFO_CORRUPTED_AFTER_FREE 0x200
174 #define DPH_SIGNATURE 0xFFEEDDCC
176 /* Biased pointer macros */
177 #define IS_BIASED_POINTER(ptr) ((ULONG_PTR)(ptr) & 1)
178 #define POINTER_REMOVE_BIAS(ptr) ((ULONG_PTR)(ptr) & ~(ULONG_PTR)1)
179 #define POINTER_ADD_BIAS(ptr) ((ULONG_PTR)(ptr) | 1)
182 ULONG RtlpDphBreakOptions
= 0;//0xFFFFFFFF;
183 ULONG RtlpDphDebugOptions
;
185 /* FUNCTIONS ******************************************************************/
188 RtlpDphGrowVirtual(PDPH_HEAP_ROOT DphRoot
, SIZE_T Size
);
191 RtlpDphIsNormalFreeHeapBlock(PVOID Block
, PULONG ValidationInformation
, BOOLEAN CheckFillers
);
194 RtlpDphReportCorruptedBlock(PDPH_HEAP_ROOT DphRoot
, ULONG Reserved
, PVOID Block
, ULONG ValidationInfo
);
197 RtlpDphNormalHeapValidate(PDPH_HEAP_ROOT DphRoot
, ULONG Flags
, PVOID BaseAddress
);
201 RtlpDphRaiseException(NTSTATUS Status
)
203 EXCEPTION_RECORD Exception
;
205 /* Initialize exception record */
206 Exception
.ExceptionCode
= Status
;
207 Exception
.ExceptionAddress
= RtlpDphRaiseException
;
208 Exception
.ExceptionFlags
= 0;
209 Exception
.ExceptionRecord
= NULL
;
210 Exception
.NumberParameters
= 0;
212 /* Raise the exception */
213 RtlRaiseException(&Exception
);
217 RtlpDphPointerFromHandle(PVOID Handle
)
219 PHEAP NormalHeap
= (PHEAP
)Handle
;
220 PDPH_HEAP_ROOT DphHeap
= (PDPH_HEAP_ROOT
)((PUCHAR
)Handle
+ PAGE_SIZE
);
222 if (NormalHeap
->ForceFlags
& HEAP_FLAG_PAGE_ALLOCS
)
224 if (DphHeap
->Signature
== DPH_SIGNATURE
)
228 DPRINT1("heap handle with incorrect signature\n");
234 RtlpDphEnterCriticalSection(PDPH_HEAP_ROOT DphRoot
, ULONG Flags
)
236 if (Flags
& HEAP_NO_SERIALIZE
)
238 /* More complex scenario */
239 if (!RtlEnterHeapLock(DphRoot
->HeapCritSect
, TRUE
))
241 if (!DphRoot
->nRemoteLockAcquired
)
243 DPRINT1("multithreaded access in HEAP_NO_SERIALIZE heap\n");
246 /* Clear out the no serialize flag */
247 DphRoot
->HeapFlags
&= ~HEAP_NO_SERIALIZE
;
250 /* Enter the heap's critical section */
251 RtlEnterHeapLock(DphRoot
->HeapCritSect
, TRUE
);
256 /* Just enter the heap's critical section */
257 RtlEnterHeapLock(DphRoot
->HeapCritSect
, TRUE
);
262 RtlpDphLeaveCriticalSection(PDPH_HEAP_ROOT DphRoot
)
264 /* Just leave the heap's critical section */
265 RtlLeaveHeapLock(DphRoot
->HeapCritSect
);
270 RtlpDphPreProcessing(PDPH_HEAP_ROOT DphRoot
, ULONG Flags
)
272 RtlpDphEnterCriticalSection(DphRoot
, Flags
);
274 /* FIXME: Validate integrity, internal lists if necessary */
278 RtlpDphPostProcessing(PDPH_HEAP_ROOT DphRoot
)
280 if (!DphRoot
) return;
282 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
)
284 /* FIXME: Validate integrity, internal lists if necessary */
287 /* Release the lock */
288 RtlpDphLeaveCriticalSection(DphRoot
);
292 RtlpSecMemFreeVirtualMemory(HANDLE Process
, PVOID
*Base
, PSIZE_T Size
, ULONG Type
)
295 //PVOID *SavedBase = Base;
296 //PSIZE_T SavedSize = Size;
298 /* Free the memory */
299 Status
= ZwFreeVirtualMemory(Process
, Base
, Size
, Type
);
301 /* Flush secure memory cache if needed and retry freeing */
303 if (Status
== STATUS_INVALID_PAGE_PROTECTION
&&
304 Process
== NtCurrentProcess() &&
305 RtlFlushSecureMemoryCache(*SavedBase
, *SavedSize
))
307 Status
= ZwFreeVirtualMemory(NtCurrentProcess(), SavedBase
, SavedSize
, Type
);
315 RtlpDphAllocateVm(PVOID
*Base
, SIZE_T Size
, ULONG Type
, ULONG Protection
)
318 Status
= ZwAllocateVirtualMemory(NtCurrentProcess(),
324 DPRINT("Page heap: AllocVm (%p, %Ix, %lx) status %lx \n", Base
, Size
, Type
, Status
);
325 /* Check for failures */
326 if (!NT_SUCCESS(Status
))
328 if (Type
== MEM_RESERVE
)
330 _InterlockedIncrement(&RtlpDphCounter
);
331 if (RtlpDphBreakOptions
& DPH_BREAK_ON_RESERVE_FAIL
)
333 DPRINT1("Page heap: AllocVm (%p, %Ix, %x) failed with %x \n", Base
, Size
, Type
, Status
);
340 _InterlockedIncrement(&RtlpDphAllocFails
);
341 if (RtlpDphBreakOptions
& DPH_BREAK_ON_COMMIT_FAIL
)
343 DPRINT1("Page heap: AllocVm (%p, %Ix, %x) failed with %x \n", Base
, Size
, Type
, Status
);
354 RtlpDphFreeVm(PVOID Base
, SIZE_T Size
, ULONG Type
)
358 /* Free the memory */
359 Status
= RtlpSecMemFreeVirtualMemory(NtCurrentProcess(), &Base
, &Size
, Type
);
360 DPRINT1("Page heap: FreeVm (%p, %Ix, %x) status %x \n", Base
, Size
, Type
, Status
);
361 /* Log/report failures */
362 if (!NT_SUCCESS(Status
))
364 if (Type
== MEM_RELEASE
)
366 _InterlockedIncrement(&RtlpDphReleaseFails
);
367 if (RtlpDphBreakOptions
& DPH_BREAK_ON_RELEASE_FAIL
)
369 DPRINT1("Page heap: FreeVm (%p, %Ix, %x) failed with %x \n", Base
, Size
, Type
, Status
);
376 _InterlockedIncrement(&RtlpDphFreeFails
);
377 if (RtlpDphBreakOptions
& DPH_BREAK_ON_FREE_FAIL
)
379 DPRINT1("Page heap: FreeVm (%p, %Ix, %x) failed with %x \n", Base
, Size
, Type
, Status
);
390 RtlpDphProtectVm(PVOID Base
, SIZE_T Size
, ULONG Protection
)
395 /* Change protection */
396 Status
= ZwProtectVirtualMemory(NtCurrentProcess(), &Base
, &Size
, Protection
, &OldProtection
);
398 /* Log/report failures */
399 if (!NT_SUCCESS(Status
))
401 _InterlockedIncrement(&RtlpDphProtectFails
);
402 if (RtlpDphBreakOptions
& DPH_BREAK_ON_PROTECT_FAIL
)
404 DPRINT1("Page heap: ProtectVm (%p, %Ix, %x) failed with %x \n", Base
, Size
, Protection
, Status
);
414 RtlpDphWritePageHeapBlockInformation(PDPH_HEAP_ROOT DphRoot
, PVOID UserAllocation
, SIZE_T Size
, SIZE_T UserSize
)
416 PDPH_BLOCK_INFORMATION BlockInfo
;
419 /* Get pointer to the block info structure */
420 BlockInfo
= (PDPH_BLOCK_INFORMATION
)UserAllocation
- 1;
422 /* Set up basic fields */
423 BlockInfo
->Heap
= DphRoot
;
424 BlockInfo
->ActualSize
= UserSize
;
425 BlockInfo
->RequestedSize
= Size
;
426 BlockInfo
->StartStamp
= DPH_FILL_START_STAMP_1
;
427 BlockInfo
->EndStamp
= DPH_FILL_END_STAMP_1
;
429 /* Fill with a pattern */
430 FillPtr
= (PUCHAR
)UserAllocation
+ Size
;
431 RtlFillMemory(FillPtr
, ROUND_UP(FillPtr
, PAGE_SIZE
) - (ULONG_PTR
)FillPtr
, DPH_FILL_SUFFIX
);
433 /* FIXME: Check if logging stack traces is turned on */
434 //if (DphRoot->ExtraFlags &
440 RtlpDphPlaceOnBusyList(PDPH_HEAP_ROOT DphRoot
, PDPH_HEAP_BLOCK DphNode
)
443 PVOID AddressUserData
;
445 DPRINT("RtlpDphPlaceOnBusyList(%p %p)\n", DphRoot
, DphNode
);
447 /* Add it to the AVL busy nodes table */
448 DphRoot
->NodeToAllocate
= DphNode
;
449 AddressUserData
= RtlInsertElementGenericTableAvl(&DphRoot
->BusyNodesTable
,
450 &DphNode
->pUserAllocation
,
454 ASSERT(AddressUserData
== &DphNode
->pUserAllocation
);
455 ASSERT(NewElement
== TRUE
);
457 /* Update heap counters */
458 DphRoot
->nBusyAllocations
++;
459 DphRoot
->nBusyAllocationBytesAccessible
+= DphNode
->nVirtualAccessSize
;
460 DphRoot
->nBusyAllocationBytesCommitted
+= DphNode
->nVirtualBlockSize
;
464 RtlpDphPlaceOnFreeList(PDPH_HEAP_ROOT DphRoot
, PDPH_HEAP_BLOCK Node
)
466 DPRINT("RtlpDphPlaceOnFreeList(%p %p)\n", DphRoot
, Node
);
468 /* Node is being added to the tail of the list */
469 Node
->pNextAlloc
= NULL
;
471 /* Add it to the tail of the linked list */
472 if (DphRoot
->pFreeAllocationListTail
)
473 DphRoot
->pFreeAllocationListTail
->pNextAlloc
= Node
;
475 DphRoot
->pFreeAllocationListHead
= Node
;
476 DphRoot
->pFreeAllocationListTail
= Node
;
478 /* Update byte counts taking in account this new node */
479 DphRoot
->nFreeAllocations
++;
480 DphRoot
->nFreeAllocationBytesCommitted
+= Node
->nVirtualBlockSize
;
484 RtlpDphPlaceOnPoolList(PDPH_HEAP_ROOT DphRoot
, PDPH_HEAP_BLOCK Node
)
486 DPRINT("RtlpDphPlaceOnPoolList(%p %p)\n", DphRoot
, Node
);
488 /* Node is being added to the tail of the list */
489 Node
->pNextAlloc
= NULL
;
491 /* Add it to the tail of the linked list */
492 if (DphRoot
->pNodePoolListTail
)
493 DphRoot
->pNodePoolListTail
->pNextAlloc
= Node
;
495 DphRoot
->pNodePoolListHead
= Node
;
496 DphRoot
->pNodePoolListTail
= Node
;
498 /* Update byte counts taking in account this new node */
499 DphRoot
->nNodePools
++;
500 DphRoot
->nNodePoolBytes
+= Node
->nVirtualBlockSize
;
504 RtlpDphPlaceOnVirtualList(PDPH_HEAP_ROOT DphRoot
, PDPH_HEAP_BLOCK Node
)
506 DPRINT("RtlpDphPlaceOnVirtualList(%p %p)\n", DphRoot
, Node
);
508 /* Add it to the head of the virtual list */
509 Node
->pNextAlloc
= DphRoot
->pVirtualStorageListHead
;
510 if (!DphRoot
->pVirtualStorageListHead
)
511 DphRoot
->pVirtualStorageListTail
= Node
;
512 DphRoot
->pVirtualStorageListHead
= Node
;
514 /* Update byte counts taking in account this new node */
515 DphRoot
->nVirtualStorageRanges
++;
516 DphRoot
->nVirtualStorageBytes
+= Node
->nVirtualBlockSize
;
519 PDPH_HEAP_BLOCK NTAPI
520 RtlpDphTakeNodeFromUnusedList(PDPH_HEAP_ROOT DphRoot
)
522 PDPH_HEAP_BLOCK Node
= DphRoot
->pUnusedNodeListHead
;
523 PDPH_HEAP_BLOCK Next
;
525 DPRINT("RtlpDphTakeNodeFromUnusedList(%p), ret %p\n", DphRoot
, Node
);
527 /* Take the first entry */
528 if (!Node
) return NULL
;
530 /* Remove that entry (Node) from the list */
531 Next
= Node
->pNextAlloc
;
532 if (DphRoot
->pUnusedNodeListHead
== Node
) DphRoot
->pUnusedNodeListHead
= Next
;
533 if (DphRoot
->pUnusedNodeListTail
== Node
) DphRoot
->pUnusedNodeListTail
= NULL
;
535 /* Decrease amount of unused nodes */
536 DphRoot
->nUnusedNodes
--;
542 RtlpDphReturnNodeToUnusedList(PDPH_HEAP_ROOT DphRoot
,
543 PDPH_HEAP_BLOCK Node
)
545 DPRINT("RtlpDphReturnNodeToUnusedList(%p, %p)\n", DphRoot
, Node
);
547 /* Add it back to the head of the unused list */
548 Node
->pNextAlloc
= DphRoot
->pUnusedNodeListHead
;
549 if (!DphRoot
->pUnusedNodeListHead
)
550 DphRoot
->pUnusedNodeListTail
= Node
;
551 DphRoot
->pUnusedNodeListHead
= Node
;
553 /* Increase amount of unused nodes */
554 DphRoot
->nUnusedNodes
++;
558 RtlpDphRemoveFromAvailableList(PDPH_HEAP_ROOT DphRoot
,
559 PDPH_HEAP_BLOCK Node
)
561 /* Make sure Adjacency list pointers are biased */
562 //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Flink));
563 //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Blink));
565 DPRINT("RtlpDphRemoveFromAvailableList(%p %p)\n", DphRoot
, Node
);
567 /* Check if it is in the list */
570 PLIST_ENTRY CurEntry
;
571 PDPH_HEAP_BLOCK NodeEntry
;
572 BOOLEAN Found
= FALSE
;
574 /* Find where to put this node according to its virtual address */
575 CurEntry
= DphRoot
->AvailableAllocationHead
.Flink
;
577 while (CurEntry
!= &DphRoot
->AvailableAllocationHead
)
579 NodeEntry
= CONTAINING_RECORD(CurEntry
, DPH_HEAP_BLOCK
, AvailableEntry
);
581 if (NodeEntry
== Node
)
587 CurEntry
= CurEntry
->Flink
;
592 DPRINT1("Trying to remove non-existing in availlist node!\n");
598 /* Remove it from the list */
599 RemoveEntryList(&Node
->AvailableEntry
);
601 /* Decrease heap counters */
602 DphRoot
->nAvailableAllocations
--;
603 DphRoot
->nAvailableAllocationBytesCommitted
-= Node
->nVirtualBlockSize
;
605 /* Remove bias from the AdjacencyEntry pointer */
606 Node
->AdjacencyEntry
.Flink
= (PLIST_ENTRY
)POINTER_REMOVE_BIAS(Node
->AdjacencyEntry
.Flink
);
607 Node
->AdjacencyEntry
.Blink
= (PLIST_ENTRY
)POINTER_REMOVE_BIAS(Node
->AdjacencyEntry
.Blink
);
611 RtlpDphRemoveFromBusyList(PDPH_HEAP_ROOT DphRoot
,
612 PDPH_HEAP_BLOCK Node
)
614 BOOLEAN ElementPresent
;
616 DPRINT("RtlpDphRemoveFromBusyList(%p %p)\n", DphRoot
, Node
);
618 /* Delete it from busy nodes table */
619 ElementPresent
= RtlDeleteElementGenericTableAvl(&DphRoot
->BusyNodesTable
, &Node
->pUserAllocation
);
620 ASSERT(ElementPresent
== TRUE
);
622 /* Update counters */
623 DphRoot
->nBusyAllocations
--;
624 DphRoot
->nBusyAllocationBytesCommitted
-= Node
->nVirtualBlockSize
;
625 DphRoot
->nBusyAllocationBytesAccessible
-= Node
->nVirtualAccessSize
;
629 RtlpDphRemoveFromFreeList(PDPH_HEAP_ROOT DphRoot
,
630 PDPH_HEAP_BLOCK Node
,
631 PDPH_HEAP_BLOCK Prev
)
633 PDPH_HEAP_BLOCK Next
;
635 DPRINT("RtlpDphRemoveFromFreeList(%p %p %p)\n", DphRoot
, Node
, Prev
);
637 /* Detach it from the list */
638 Next
= Node
->pNextAlloc
;
639 if (DphRoot
->pFreeAllocationListHead
== Node
)
640 DphRoot
->pFreeAllocationListHead
= Next
;
641 if (DphRoot
->pFreeAllocationListTail
== Node
)
642 DphRoot
->pFreeAllocationListTail
= Prev
;
643 if (Prev
) Prev
->pNextAlloc
= Next
;
645 /* Decrease heap counters */
646 DphRoot
->nFreeAllocations
--;
647 DphRoot
->nFreeAllocationBytesCommitted
-= Node
->nVirtualBlockSize
;
649 Node
->StackTrace
= NULL
;
653 RtlpDphCoalesceNodeIntoAvailable(PDPH_HEAP_ROOT DphRoot
,
654 PDPH_HEAP_BLOCK Node
)
656 PDPH_HEAP_BLOCK NodeEntry
, PrevNode
= NULL
, NextNode
;
657 PLIST_ENTRY AvailListHead
;
658 PLIST_ENTRY CurEntry
;
660 DPRINT("RtlpDphCoalesceNodeIntoAvailable(%p %p)\n", DphRoot
, Node
);
662 /* Update heap counters */
663 DphRoot
->nAvailableAllocationBytesCommitted
+= Node
->nVirtualBlockSize
;
664 DphRoot
->nAvailableAllocations
++;
666 /* Find where to put this node according to its virtual address */
667 AvailListHead
= &DphRoot
->AvailableAllocationHead
;
669 /* Find a point where to insert an available node */
670 CurEntry
= AvailListHead
->Flink
;
672 while (CurEntry
!= AvailListHead
)
674 NodeEntry
= CONTAINING_RECORD(CurEntry
, DPH_HEAP_BLOCK
, AvailableEntry
);
675 if (NodeEntry
->pVirtualBlock
>= Node
->pVirtualBlock
)
677 PrevNode
= NodeEntry
;
680 CurEntry
= CurEntry
->Flink
;
685 /* That means either this list is empty, or we should add to the head of it */
686 InsertHeadList(AvailListHead
, &Node
->AvailableEntry
);
690 /* Check the previous node and merge if possible */
691 if (PrevNode
->pVirtualBlock
+ PrevNode
->nVirtualBlockSize
== Node
->pVirtualBlock
)
693 /* They are adjacent - merge! */
694 PrevNode
->nVirtualBlockSize
+= Node
->nVirtualBlockSize
;
695 RtlpDphReturnNodeToUnusedList(DphRoot
, Node
);
696 DphRoot
->nAvailableAllocations
--;
702 /* Insert after PrevNode */
703 InsertTailList(&PrevNode
->AvailableEntry
, &Node
->AvailableEntry
);
706 /* Now check the next entry after our one */
707 if (Node
->AvailableEntry
.Flink
!= AvailListHead
)
709 NextNode
= CONTAINING_RECORD(Node
->AvailableEntry
.Flink
, DPH_HEAP_BLOCK
, AvailableEntry
);
710 /* Node is not at the tail of the list, check if it's adjacent */
711 if (Node
->pVirtualBlock
+ Node
->nVirtualBlockSize
== NextNode
->pVirtualBlock
)
713 /* They are adjacent - merge! */
714 Node
->nVirtualBlockSize
+= NextNode
->nVirtualBlockSize
;
716 /* Remove next entry from the list and put it into unused entries list */
717 RemoveEntryList(&NextNode
->AvailableEntry
);
718 RtlpDphReturnNodeToUnusedList(DphRoot
, NextNode
);
719 DphRoot
->nAvailableAllocations
--;
726 RtlpDphCoalesceFreeIntoAvailable(PDPH_HEAP_ROOT DphRoot
,
727 ULONG LeaveOnFreeList
)
729 PDPH_HEAP_BLOCK Node
= DphRoot
->pFreeAllocationListHead
, Next
;
730 SIZE_T FreeAllocations
= DphRoot
->nFreeAllocations
;
732 /* Make sure requested size is not too big */
733 ASSERT(FreeAllocations
>= LeaveOnFreeList
);
735 DPRINT("RtlpDphCoalesceFreeIntoAvailable(%p %lu)\n", DphRoot
, LeaveOnFreeList
);
740 if (FreeAllocations
< LeaveOnFreeList
) break;
742 /* Get the next pointer, because it may be changed after following two calls */
743 Next
= Node
->pNextAlloc
;
745 /* Remove it from the free list */
746 RtlpDphRemoveFromFreeList(DphRoot
, Node
, NULL
);
748 /* And put into the available */
749 RtlpDphCoalesceNodeIntoAvailable(DphRoot
, Node
);
751 /* Go to the next node */
757 RtlpDphAddNewPool(PDPH_HEAP_ROOT DphRoot
, PDPH_HEAP_BLOCK NodeBlock
, PVOID Virtual
, SIZE_T Size
, BOOLEAN PlaceOnPool
)
759 PDPH_HEAP_BLOCK DphNode
, DphStartNode
;
762 //NodeCount = (Size >> 6) - 1;
763 NodeCount
= (ULONG
)(Size
/ sizeof(DPH_HEAP_BLOCK
));
764 DphStartNode
= Virtual
;
766 /* Set pNextAlloc for all blocks */
767 for (DphNode
= Virtual
, i
=NodeCount
-1; i
> 0; i
--)
769 DphNode
->pNextAlloc
= DphNode
+ 1;
770 DphNode
= DphNode
->pNextAlloc
;
773 /* and the last one */
774 DphNode
->pNextAlloc
= NULL
;
776 /* Add it to the tail of unused node list */
777 if (DphRoot
->pUnusedNodeListTail
)
778 DphRoot
->pUnusedNodeListTail
->pNextAlloc
= DphStartNode
;
780 DphRoot
->pUnusedNodeListHead
= DphStartNode
;
782 DphRoot
->pUnusedNodeListTail
= DphNode
;
784 /* Increase counters */
785 DphRoot
->nUnusedNodes
+= NodeCount
;
787 /* Check if we need to place it on the pool list */
790 /* Get a node from the unused list */
791 DphNode
= RtlpDphTakeNodeFromUnusedList(DphRoot
);
794 /* Set its virtual block values */
795 DphNode
->pVirtualBlock
= Virtual
;
796 DphNode
->nVirtualBlockSize
= Size
;
798 /* Place it on the pool list */
799 RtlpDphPlaceOnPoolList(DphRoot
, DphNode
);
803 PDPH_HEAP_BLOCK NTAPI
804 RtlpDphSearchAvailableMemoryListForBestFit(PDPH_HEAP_ROOT DphRoot
,
807 PLIST_ENTRY CurEntry
;
808 PDPH_HEAP_BLOCK Node
, NodeFound
= NULL
;
810 CurEntry
= DphRoot
->AvailableAllocationHead
.Flink
;
812 while (CurEntry
!= &DphRoot
->AvailableAllocationHead
)
814 /* Get the current available node */
815 Node
= CONTAINING_RECORD(CurEntry
, DPH_HEAP_BLOCK
, AvailableEntry
);
818 if (Node
->nVirtualBlockSize
>= Size
)
824 /* Move to the next available entry */
825 CurEntry
= CurEntry
->Flink
;
828 /* Make sure Adjacency list pointers are biased */
829 //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Flink));
830 //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Blink));
835 PDPH_HEAP_BLOCK NTAPI
836 RtlpDphFindAvailableMemory(PDPH_HEAP_ROOT DphRoot
,
840 PDPH_HEAP_BLOCK Node
;
843 /* Find an available best fitting node */
844 Node
= RtlpDphSearchAvailableMemoryListForBestFit(DphRoot
, Size
);
846 /* If that didn't work, try to search a smaller one in the loop */
849 /* Break if the free list becomes too small */
850 if (DphRoot
->nFreeAllocations
<= DPH_FREE_LIST_MINIMUM
) break;
852 /* Calculate a new free list size */
853 NewSize
= DphRoot
->nFreeAllocations
>> 2;
854 if (NewSize
< DPH_FREE_LIST_MINIMUM
) NewSize
= DPH_FREE_LIST_MINIMUM
;
856 /* Coalesce free into available */
857 RtlpDphCoalesceFreeIntoAvailable(DphRoot
, NewSize
);
859 /* Try to find an available best fitting node again */
860 Node
= RtlpDphSearchAvailableMemoryListForBestFit(DphRoot
, Size
);
863 /* If Node is NULL, then we could fix the situation only by
864 growing the available VM size */
867 /* Grow VM size, if it fails - return failure directly */
868 if (!RtlpDphGrowVirtual(DphRoot
, Size
)) return NULL
;
870 /* Try to find an available best fitting node again */
871 Node
= RtlpDphSearchAvailableMemoryListForBestFit(DphRoot
, Size
);
875 /* Do the last attempt: coalesce all free into available (if Size fits there) */
876 if (DphRoot
->nFreeAllocationBytesCommitted
+ DphRoot
->nAvailableAllocationBytesCommitted
>= Size
)
878 /* Coalesce free into available */
879 RtlpDphCoalesceFreeIntoAvailable(DphRoot
, 0);
881 /* Try to find an available best fitting node again */
882 Node
= RtlpDphSearchAvailableMemoryListForBestFit(DphRoot
, Size
);
887 /* Return node we found */
891 PDPH_HEAP_BLOCK NTAPI
892 RtlpDphFindBusyMemory(PDPH_HEAP_ROOT DphRoot
,
895 PDPH_HEAP_BLOCK Node
;
898 /* Lookup busy block in AVL */
899 Ptr
= RtlLookupElementGenericTableAvl(&DphRoot
->BusyNodesTable
, &pUserMem
);
900 if (!Ptr
) return NULL
;
902 /* Restore pointer to the heap block */
903 Node
= CONTAINING_RECORD(Ptr
, DPH_HEAP_BLOCK
, pUserAllocation
);
904 ASSERT(Node
->pUserAllocation
== pUserMem
);
909 RtlpDphSetProtectionBeforeUse(PDPH_HEAP_ROOT DphRoot
, PUCHAR VirtualBlock
, ULONG UserSize
)
914 if (DphRoot
->ExtraFlags
& DPH_EXTRA_CHECK_UNDERRUN
)
916 Base
= VirtualBlock
+ PAGE_SIZE
;
923 // FIXME: It should be different, but for now it's fine
924 Protection
= PAGE_READWRITE
;
926 return RtlpDphProtectVm(Base
, UserSize
, Protection
);
930 RtlpDphSetProtectionAfterUse(PDPH_HEAP_ROOT DphRoot
, /*PUCHAR VirtualBlock*/PDPH_HEAP_BLOCK Node
)
932 ASSERT((Node
->nVirtualAccessSize
+ PAGE_SIZE
) <= Node
->nVirtualBlockSize
);
934 // FIXME: Bring stuff here
935 if (DphRoot
->ExtraFlags
& DPH_EXTRA_CHECK_UNDERRUN
)
942 return STATUS_SUCCESS
;
945 PDPH_HEAP_BLOCK NTAPI
946 RtlpDphAllocateNode(PDPH_HEAP_ROOT DphRoot
)
948 PDPH_HEAP_BLOCK Node
;
950 SIZE_T Size
= DPH_POOL_SIZE
, SizeVirtual
;
953 /* Check for the easy case */
954 if (DphRoot
->pUnusedNodeListHead
)
956 /* Just take a node from this list */
957 Node
= RtlpDphTakeNodeFromUnusedList(DphRoot
);
962 /* There is a need to make free space */
963 Node
= RtlpDphFindAvailableMemory(DphRoot
, DPH_POOL_SIZE
, FALSE
);
965 if (!DphRoot
->pUnusedNodeListHead
&& !Node
)
967 /* Retry with a smaller request */
969 Node
= RtlpDphFindAvailableMemory(DphRoot
, PAGE_SIZE
, FALSE
);
972 if (!DphRoot
->pUnusedNodeListHead
)
976 RtlpDphRemoveFromAvailableList(DphRoot
, Node
);
977 Ptr
= Node
->pVirtualBlock
;
978 SizeVirtual
= Node
->nVirtualBlockSize
;
982 /* No free space, need to alloc a new VM block */
983 Size
= DPH_POOL_SIZE
;
984 SizeVirtual
= DPH_RESERVE_SIZE
;
985 Status
= RtlpDphAllocateVm(&Ptr
, SizeVirtual
, MEM_COMMIT
, PAGE_NOACCESS
);
987 if (!NT_SUCCESS(Status
))
989 /* Retry with a smaller size */
990 SizeVirtual
= 0x10000;
991 Status
= RtlpDphAllocateVm(&Ptr
, SizeVirtual
, MEM_COMMIT
, PAGE_NOACCESS
);
992 if (!NT_SUCCESS(Status
)) return NULL
;
996 /* VM is allocated at this point, set protection */
997 Status
= RtlpDphProtectVm(Ptr
, Size
, PAGE_READWRITE
);
998 if (!NT_SUCCESS(Status
))
1002 RtlpDphCoalesceNodeIntoAvailable(DphRoot
, Node
);
1013 /* Zero the memory */
1014 if (Node
) RtlZeroMemory(Ptr
, Size
);
1016 /* Add a new pool based on this VM */
1017 RtlpDphAddNewPool(DphRoot
, Node
, Ptr
, Size
, TRUE
);
1021 if (Node
->nVirtualBlockSize
> Size
)
1023 Node
->pVirtualBlock
+= Size
;
1024 Node
->nVirtualBlockSize
-= Size
;
1026 RtlpDphCoalesceNodeIntoAvailable(DphRoot
, Node
);
1030 RtlpDphReturnNodeToUnusedList(DphRoot
, Node
);
1035 /* The new VM block was just allocated a few code lines ago,
1037 Node
= RtlpDphTakeNodeFromUnusedList(DphRoot
);
1038 Node
->pVirtualBlock
= Ptr
;
1039 Node
->nVirtualBlockSize
= SizeVirtual
;
1040 RtlpDphPlaceOnVirtualList(DphRoot
, Node
);
1042 Node
= RtlpDphTakeNodeFromUnusedList(DphRoot
);
1043 Node
->pVirtualBlock
= (PUCHAR
)Ptr
+ Size
;
1044 Node
->nVirtualBlockSize
= SizeVirtual
- Size
;
1045 RtlpDphPlaceOnVirtualList(DphRoot
, Node
);
1047 /* Coalesce them into available list */
1048 RtlpDphCoalesceNodeIntoAvailable(DphRoot
, Node
);
1052 return RtlpDphTakeNodeFromUnusedList(DphRoot
);
1056 RtlpDphGrowVirtual(PDPH_HEAP_ROOT DphRoot
,
1059 PDPH_HEAP_BLOCK Node
, AvailableNode
;
1064 /* Start with allocating a couple of nodes */
1065 Node
= RtlpDphAllocateNode(DphRoot
);
1066 if (!Node
) return FALSE
;
1068 AvailableNode
= RtlpDphAllocateNode(DphRoot
);
1071 /* Free the allocated node and return failure */
1072 RtlpDphReturnNodeToUnusedList(DphRoot
, Node
);
1076 /* Calculate size of VM to allocate by rounding it up */
1077 Size
= ROUND_UP(Size
, 0xFFFF);
1079 if (Size
< DPH_RESERVE_SIZE
)
1080 VirtualSize
= DPH_RESERVE_SIZE
;
1082 /* Allocate the virtual memory */
1083 // FIXME: Shouldn't it be MEM_RESERVE with later committing?
1084 Status
= RtlpDphAllocateVm(&Base
, VirtualSize
, MEM_COMMIT
, PAGE_NOACCESS
);
1085 if (!NT_SUCCESS(Status
))
1087 /* Retry again with a smaller size */
1089 Status
= RtlpDphAllocateVm(&Base
, VirtualSize
, MEM_COMMIT
, PAGE_NOACCESS
);
1090 if (!NT_SUCCESS(Status
))
1092 /* Free the allocated node and return failure */
1093 RtlpDphReturnNodeToUnusedList(DphRoot
, Node
);
1094 RtlpDphReturnNodeToUnusedList(DphRoot
, AvailableNode
);
1099 /* Set up our two nodes describing this VM */
1100 Node
->pVirtualBlock
= Base
;
1101 Node
->nVirtualBlockSize
= VirtualSize
;
1102 AvailableNode
->pVirtualBlock
= Base
;
1103 AvailableNode
->nVirtualBlockSize
= VirtualSize
;
1105 /* Add them to virtual and available lists respectively */
1106 RtlpDphPlaceOnVirtualList(DphRoot
, Node
);
1107 RtlpDphCoalesceNodeIntoAvailable(DphRoot
, AvailableNode
);
1109 /* Return success */
1113 RTL_GENERIC_COMPARE_RESULTS
1115 RtlpDphCompareNodeForTable(IN PRTL_AVL_TABLE Table
,
1116 IN PVOID FirstStruct
,
1117 IN PVOID SecondStruct
)
1119 ULONG_PTR FirstBlock
, SecondBlock
;
1121 FirstBlock
= *((ULONG_PTR
*)FirstStruct
);
1122 SecondBlock
= *((ULONG_PTR
*)SecondStruct
);
1124 if (FirstBlock
< SecondBlock
)
1125 return GenericLessThan
;
1126 else if (FirstBlock
> SecondBlock
)
1127 return GenericGreaterThan
;
1129 return GenericEqual
;
1134 RtlpDphAllocateNodeForTable(IN PRTL_AVL_TABLE Table
,
1137 PDPH_HEAP_BLOCK pBlock
;
1138 PDPH_HEAP_ROOT DphRoot
;
1140 /* This mega-assert comes from a text search over Windows 2003 checked binary of ntdll.dll */
1141 ASSERT((ULONG_PTR
)(((PRTL_BALANCED_LINKS
)0)+1) + sizeof(PUCHAR
) == ByteSize
);
1143 /* Get pointer to the containing heap root record */
1144 DphRoot
= CONTAINING_RECORD(Table
, DPH_HEAP_ROOT
, BusyNodesTable
);
1145 pBlock
= DphRoot
->NodeToAllocate
;
1147 DphRoot
->NodeToAllocate
= NULL
;
1150 return &(pBlock
->TableLinks
);
1155 RtlpDphFreeNodeForTable(IN PRTL_AVL_TABLE Table
,
1162 RtlpDphInitializeDelayedFreeQueue()
1166 Status
= RtlInitializeHeapLock(&RtlpDphDelayedFreeQueueLock
);
1167 if (!NT_SUCCESS(Status
))
1169 // TODO: Log this error!
1170 DPRINT1("Failure initializing delayed free queue critical section\n");
1174 /* Initialize lists */
1175 InitializeListHead(&RtlpDphDelayedFreeQueue
);
1176 RtlInitializeSListHead(&RtlpDphDelayedTemporaryPushList
);
1178 /* Reset counters */
1179 RtlpDphMemoryUsedByDelayedFreeBlocks
= 0;
1180 RtlpDphNumberOfDelayedFreeBlocks
= 0;
1186 RtlpDphFreeDelayedBlocksFromHeap(PDPH_HEAP_ROOT DphRoot
,
1189 PLIST_ENTRY Current
, Next
;
1190 PDPH_BLOCK_INFORMATION BlockInfo
;
1191 ULONG ValidationInfo
;
1193 /* The original routine seems to use a temporary SList to put blocks to be freed,
1194 then it releases the lock and frees the blocks. But let's make it simple for now */
1196 /* Acquire the delayed free queue lock */
1197 RtlEnterHeapLock(RtlpDphDelayedFreeQueueLock
, TRUE
);
1199 /* Traverse the list */
1200 Current
= RtlpDphDelayedFreeQueue
.Flink
;
1201 while (Current
!= &RtlpDphDelayedFreeQueue
)
1203 /* Get the next entry pointer */
1204 Next
= Current
->Flink
;
1206 BlockInfo
= CONTAINING_RECORD(Current
, DPH_BLOCK_INFORMATION
, FreeQueue
);
1208 /* Check if it belongs to the same heap */
1209 if (BlockInfo
->Heap
== DphRoot
)
1211 /* Remove it from the list */
1212 RemoveEntryList(Current
);
1214 /* Reset its heap to NULL */
1215 BlockInfo
->Heap
= NULL
;
1217 if (!RtlpDphIsNormalFreeHeapBlock(BlockInfo
+ 1, &ValidationInfo
, TRUE
))
1219 RtlpDphReportCorruptedBlock(DphRoot
, 10, BlockInfo
+ 1, ValidationInfo
);
1222 /* Decrement counters */
1223 RtlpDphMemoryUsedByDelayedFreeBlocks
-= BlockInfo
->ActualSize
;
1224 RtlpDphNumberOfDelayedFreeBlocks
--;
1226 /* Free the normal heap */
1227 RtlFreeHeap (NormalHeap
, 0, BlockInfo
);
1230 /* Move to the next one */
1234 /* Release the delayed free queue lock */
1235 RtlLeaveHeapLock(RtlpDphDelayedFreeQueueLock
);
1239 RtlpDphTargetDllsLogicInitialize()
1242 return STATUS_SUCCESS
;
1246 RtlpDphInternalValidatePageHeap(PDPH_HEAP_ROOT DphRoot
, PVOID Address
, ULONG Value
)
1252 RtlpDphVerifyIntegrity(PDPH_HEAP_ROOT DphRoot
)
1258 RtlpDphReportCorruptedBlock(PDPH_HEAP_ROOT DphRoot
,
1261 ULONG ValidationInfo
)
1263 //RtlpDphGetBlockSizeFromCorruptedBlock();
1265 if (ValidationInfo
& DPH_VALINFO_CORRUPTED_AFTER_FREE
)
1267 DPRINT1("block corrupted after having been freed\n");
1270 if (ValidationInfo
& DPH_VALINFO_ALREADY_FREED
)
1272 DPRINT1("block already freed\n");
1275 if (ValidationInfo
& DPH_VALINFO_BAD_INFIX_PATTERN
)
1277 DPRINT1("corrupted infix pattern for freed block\n");
1280 if (ValidationInfo
& DPH_VALINFO_BAD_POINTER
)
1282 DPRINT1("corrupted heap pointer or using wrong heap\n");
1285 if (ValidationInfo
& DPH_VALINFO_BAD_SUFFIX_PATTERN
)
1287 DPRINT1("corrupted suffix pattern\n");
1290 if (ValidationInfo
& DPH_VALINFO_BAD_PREFIX_PATTERN
)
1292 DPRINT1("corrupted prefix pattern\n");
1295 if (ValidationInfo
& DPH_VALINFO_BAD_START_STAMP
)
1297 DPRINT1("corrupted start stamp\n");
1300 if (ValidationInfo
& DPH_VALINFO_BAD_END_STAMP
)
1302 DPRINT1("corrupted end stamp\n");
1305 if (ValidationInfo
& DPH_VALINFO_EXCEPTION
)
1307 DPRINT1("exception raised while verifying block\n");
1310 DPRINT1("Corrupted heap block %p\n", Block
);
1314 RtlpDphIsPageHeapBlock(PDPH_HEAP_ROOT DphRoot
,
1316 PULONG ValidationInformation
,
1317 BOOLEAN CheckFillers
)
1319 PDPH_BLOCK_INFORMATION BlockInfo
;
1320 BOOLEAN SomethingWrong
= FALSE
;
1321 PUCHAR Byte
, Start
, End
;
1323 ASSERT(ValidationInformation
!= NULL
);
1324 *ValidationInformation
= 0;
1327 BlockInfo
= (PDPH_BLOCK_INFORMATION
)Block
- 1;
1330 if (BlockInfo
->StartStamp
!= DPH_FILL_START_STAMP_1
)
1332 *ValidationInformation
|= DPH_VALINFO_BAD_START_STAMP
;
1333 SomethingWrong
= TRUE
;
1335 /* Check if it has an alloc/free mismatch */
1336 if (BlockInfo
->StartStamp
== DPH_FILL_START_STAMP_2
)
1338 /* Notify respectively */
1339 *ValidationInformation
= 0x101;
1343 if (BlockInfo
->EndStamp
!= DPH_FILL_END_STAMP_1
)
1345 *ValidationInformation
|= DPH_VALINFO_BAD_END_STAMP
;
1346 SomethingWrong
= TRUE
;
1349 /* Check root heap pointer */
1350 if (BlockInfo
->Heap
!= DphRoot
)
1352 *ValidationInformation
|= DPH_VALINFO_BAD_POINTER
;
1353 SomethingWrong
= TRUE
;
1356 /* Check other fillers if requested */
1359 /* Check space after the block */
1360 Start
= (PUCHAR
)Block
+ BlockInfo
->RequestedSize
;
1361 End
= (PUCHAR
)ROUND_UP(Start
, PAGE_SIZE
);
1362 for (Byte
= Start
; Byte
< End
; Byte
++)
1364 if (*Byte
!= DPH_FILL_SUFFIX
)
1366 *ValidationInformation
|= DPH_VALINFO_BAD_SUFFIX_PATTERN
;
1367 SomethingWrong
= TRUE
;
1373 return (SomethingWrong
== FALSE
);
1377 RtlpDphIsNormalFreeHeapBlock(PVOID Block
,
1378 PULONG ValidationInformation
,
1379 BOOLEAN CheckFillers
)
1381 ASSERT(ValidationInformation
!= NULL
);
1384 *ValidationInformation
= 0;
1389 RtlpDphProcessStartupInitialization()
1392 PTEB Teb
= NtCurrentTeb();
1394 /* Initialize the DPH heap list and its critical section */
1395 InitializeListHead(&RtlpDphPageHeapList
);
1396 Status
= RtlInitializeHeapLock(&RtlpDphPageHeapListLock
);
1397 if (!NT_SUCCESS(Status
))
1403 /* Initialize delayed-free queue */
1404 Status
= RtlpDphInitializeDelayedFreeQueue();
1405 if (!NT_SUCCESS(Status
)) return Status
;
1407 /* Initialize the target dlls string */
1408 RtlInitUnicodeString(&RtlpDphTargetDllsUnicode
, RtlpDphTargetDlls
);
1409 Status
= RtlpDphTargetDllsLogicInitialize();
1411 /* Per-process DPH init is done */
1412 RtlpDphPageHeapListInitialized
= TRUE
;
1414 DPRINT1("Page heap: pid 0x%p: page heap enabled with flags 0x%X.\n",
1415 Teb
->ClientId
.UniqueProcess
, RtlpDphGlobalFlags
);
1421 RtlpDphShouldAllocateInPageHeap(PDPH_HEAP_ROOT DphRoot
,
1425 /* Always use page heap for now */
1430 RtlpPageHeapCreate(ULONG Flags
,
1435 PRTL_HEAP_PARAMETERS Parameters
)
1439 PDPH_HEAP_ROOT DphRoot
;
1440 PDPH_HEAP_BLOCK DphNode
;
1443 LARGE_INTEGER PerfCounter
;
1445 /* Check for a DPH bypass flag */
1446 if ((ULONG_PTR
)Parameters
== -1) return NULL
;
1448 /* Make sure no user-allocated stuff was provided */
1449 if (Addr
|| Lock
) return NULL
;
1451 /* Allocate minimum amount of virtual memory */
1452 MemSize
= DPH_RESERVE_SIZE
;
1453 Status
= RtlpDphAllocateVm(&Base
, MemSize
, MEM_COMMIT
, PAGE_NOACCESS
);
1454 if (!NT_SUCCESS(Status
))
1460 /* Set protection */
1461 Status
= RtlpDphProtectVm(Base
, 2*PAGE_SIZE
+ DPH_POOL_SIZE
, PAGE_READWRITE
);
1462 if (!NT_SUCCESS(Status
))
1464 //RtlpDphFreeVm(Base, 0, 0, 0);
1469 /* Start preparing the 1st page. Fill it with the default filler */
1470 RtlFillMemoryUlong(Base
, PAGE_SIZE
, DPH_FILL
);
1472 /* Set flags in the "HEAP" structure */
1473 HeapPtr
= (PHEAP
)Base
;
1474 HeapPtr
->Flags
= Flags
| HEAP_FLAG_PAGE_ALLOCS
;
1475 HeapPtr
->ForceFlags
= Flags
| HEAP_FLAG_PAGE_ALLOCS
;
1477 /* Set 1st page to read only now */
1478 Status
= RtlpDphProtectVm(Base
, PAGE_SIZE
, PAGE_READONLY
);
1479 if (!NT_SUCCESS(Status
))
1485 /* 2nd page is the real DPH root block */
1486 DphRoot
= (PDPH_HEAP_ROOT
)((PCHAR
)Base
+ PAGE_SIZE
);
1488 /* Initialize the DPH root */
1489 DphRoot
->Signature
= DPH_SIGNATURE
;
1490 DphRoot
->HeapFlags
= Flags
;
1491 DphRoot
->HeapCritSect
= (PHEAP_LOCK
)((PCHAR
)DphRoot
+ DPH_POOL_SIZE
);
1492 DphRoot
->ExtraFlags
= RtlpDphGlobalFlags
;
1494 ZwQueryPerformanceCounter(&PerfCounter
, NULL
);
1495 DphRoot
->Seed
= PerfCounter
.LowPart
;
1497 RtlInitializeHeapLock(&DphRoot
->HeapCritSect
);
1498 InitializeListHead(&DphRoot
->AvailableAllocationHead
);
1500 /* Create a normal heap for this paged heap */
1501 DphRoot
->NormalHeap
= RtlCreateHeap(Flags
, NULL
, TotalSize
, CommitSize
, NULL
, (PRTL_HEAP_PARAMETERS
)-1);
1502 if (!DphRoot
->NormalHeap
)
1508 /* 3rd page: a pool for DPH allocations */
1509 RtlpDphAddNewPool(DphRoot
, NULL
, DphRoot
+ 1, DPH_POOL_SIZE
- sizeof(DPH_HEAP_ROOT
), FALSE
);
1511 /* Allocate internal heap blocks. For the root */
1512 DphNode
= RtlpDphAllocateNode(DphRoot
);
1513 ASSERT(DphNode
!= NULL
);
1514 DphNode
->pVirtualBlock
= (PUCHAR
)DphRoot
;
1515 DphNode
->nVirtualBlockSize
= DPH_POOL_SIZE
;
1516 RtlpDphPlaceOnPoolList(DphRoot
, DphNode
);
1518 /* For the memory we allocated as a whole */
1519 DphNode
= RtlpDphAllocateNode(DphRoot
);
1520 ASSERT(DphNode
!= NULL
);
1521 DphNode
->pVirtualBlock
= Base
;
1522 DphNode
->nVirtualBlockSize
= MemSize
;
1523 RtlpDphPlaceOnVirtualList(DphRoot
, DphNode
);
1525 /* For the remaining part */
1526 DphNode
= RtlpDphAllocateNode(DphRoot
);
1527 ASSERT(DphNode
!= NULL
);
1528 DphNode
->pVirtualBlock
= (PUCHAR
)Base
+ 2*PAGE_SIZE
+ DPH_POOL_SIZE
;
1529 DphNode
->nVirtualBlockSize
= MemSize
- (2*PAGE_SIZE
+ DPH_POOL_SIZE
);
1530 RtlpDphCoalesceNodeIntoAvailable(DphRoot
, DphNode
);
1532 //DphRoot->CreateStackTrace = RtlpDphLogStackTrace(1);
1534 /* Initialize AVL-based busy nodes table */
1535 RtlInitializeGenericTableAvl(&DphRoot
->BusyNodesTable
,
1536 RtlpDphCompareNodeForTable
,
1537 RtlpDphAllocateNodeForTable
,
1538 RtlpDphFreeNodeForTable
,
1541 /* Initialize per-process startup info */
1542 if (!RtlpDphPageHeapListInitialized
) RtlpDphProcessStartupInitialization();
1544 /* Acquire the heap list lock */
1545 RtlEnterHeapLock(RtlpDphPageHeapListLock
, TRUE
);
1547 /* Insert this heap to the tail of the global list */
1548 InsertTailList(&RtlpDphPageHeapList
, &DphRoot
->NextHeap
);
1550 /* Note we increased the size of the list */
1551 RtlpDphPageHeapListLength
++;
1553 /* Release the heap list lock */
1554 RtlLeaveHeapLock(RtlpDphPageHeapListLock
);
1556 if (RtlpDphDebugOptions
& DPH_DEBUG_VERBOSE
)
1558 DPRINT1("Page heap: process 0x%p created heap @ %p (%p, flags 0x%X)\n",
1559 NtCurrentTeb()->ClientId
.UniqueProcess
, (PUCHAR
)DphRoot
- PAGE_SIZE
,
1560 DphRoot
->NormalHeap
, DphRoot
->ExtraFlags
);
1563 /* Perform internal validation if required */
1564 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
)
1565 RtlpDphInternalValidatePageHeap(DphRoot
, NULL
, 0);
1567 return (PUCHAR
)DphRoot
- PAGE_SIZE
;
1571 RtlpPageHeapDestroy(HANDLE HeapPtr
)
1573 PDPH_HEAP_ROOT DphRoot
;
1574 PDPH_HEAP_BLOCK Node
, Next
;
1578 /* Check if it's not a process heap */
1579 if (HeapPtr
== RtlGetProcessHeap())
1585 /* Get pointer to the heap root */
1586 DphRoot
= RtlpDphPointerFromHandle(HeapPtr
);
1587 if (!DphRoot
) return NULL
;
1589 RtlpDphPreProcessing(DphRoot
, DphRoot
->HeapFlags
);
1591 /* Get the pointer to the normal heap */
1592 NormalHeap
= DphRoot
->NormalHeap
;
1594 /* Free the delayed-free blocks */
1595 RtlpDphFreeDelayedBlocksFromHeap(DphRoot
, NormalHeap
);
1597 /* Go through the busy blocks */
1598 Node
= RtlEnumerateGenericTableAvl(&DphRoot
->BusyNodesTable
, TRUE
);
1602 if (!(DphRoot
->ExtraFlags
& DPH_EXTRA_CHECK_UNDERRUN
))
1604 if (!RtlpDphIsPageHeapBlock(DphRoot
, Node
->pUserAllocation
, &Value
, TRUE
))
1606 RtlpDphReportCorruptedBlock(DphRoot
, 3, Node
->pUserAllocation
, Value
);
1610 /* FIXME: Call AV notification */
1611 //AVrfInternalHeapFreeNotification();
1613 /* Go to the next node */
1614 Node
= RtlEnumerateGenericTableAvl(&DphRoot
->BusyNodesTable
, FALSE
);
1617 /* Acquire the global heap list lock */
1618 RtlEnterHeapLock(RtlpDphPageHeapListLock
, TRUE
);
1620 /* Remove the entry and decrement the global counter */
1621 RemoveEntryList(&DphRoot
->NextHeap
);
1622 RtlpDphPageHeapListLength
--;
1624 /* Release the global heap list lock */
1625 RtlLeaveHeapLock(RtlpDphPageHeapListLock
);
1627 /* Leave and delete this heap's critical section */
1628 RtlLeaveHeapLock(DphRoot
->HeapCritSect
);
1629 RtlDeleteHeapLock(DphRoot
->HeapCritSect
);
1631 /* Now go through all virtual list nodes and release the VM */
1632 Node
= DphRoot
->pVirtualStorageListHead
;
1635 Next
= Node
->pNextAlloc
;
1636 /* Release the memory without checking result */
1637 RtlpDphFreeVm(Node
->pVirtualBlock
, 0, MEM_RELEASE
);
1641 /* Destroy the normal heap */
1642 RtlDestroyHeap(NormalHeap
);
1644 /* Report success */
1645 if (RtlpDphDebugOptions
& DPH_DEBUG_VERBOSE
)
1646 DPRINT1("Page heap: process 0x%p destroyed heap @ %p (%p)\n",
1647 NtCurrentTeb()->ClientId
.UniqueProcess
, HeapPtr
, NormalHeap
);
1653 RtlpPageHeapAllocate(IN PVOID HeapPtr
,
1657 PDPH_HEAP_ROOT DphRoot
;
1658 PDPH_HEAP_BLOCK AvailableNode
, BusyNode
;
1659 BOOLEAN Biased
= FALSE
;
1660 ULONG AllocateSize
, AccessSize
;
1662 SIZE_T UserActualSize
;
1665 /* Check requested size */
1666 if (Size
> 0x7FF00000)
1668 DPRINT1("extreme size request\n");
1670 /* Generate an exception if needed */
1671 if (Flags
& HEAP_GENERATE_EXCEPTIONS
) RtlpDphRaiseException(STATUS_NO_MEMORY
);
1676 /* Unbias the pointer if necessary */
1677 if (IS_BIASED_POINTER(HeapPtr
))
1679 HeapPtr
= (PVOID
)POINTER_REMOVE_BIAS(HeapPtr
);
1683 /* Get a pointer to the heap root */
1684 DphRoot
= RtlpDphPointerFromHandle(HeapPtr
);
1685 if (!DphRoot
) return NULL
;
1687 /* Acquire the heap lock */
1688 RtlpDphPreProcessing(DphRoot
, Flags
);
1690 /* Perform internal validation if specified by flags */
1691 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
&& !Biased
)
1693 RtlpDphInternalValidatePageHeap(DphRoot
, NULL
, 0);
1696 /* Add heap flags */
1697 Flags
|= DphRoot
->HeapFlags
;
1699 if (!Biased
&& !RtlpDphShouldAllocateInPageHeap(DphRoot
, Size
))
1701 /* Perform allocation from a normal heap */
1705 /* Perform heap integrity check if specified by flags */
1706 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
)
1708 RtlpDphVerifyIntegrity(DphRoot
);
1711 /* Calculate sizes */
1712 AccessSize
= ROUND_UP(Size
+ sizeof(DPH_BLOCK_INFORMATION
), PAGE_SIZE
);
1713 AllocateSize
= AccessSize
+ PAGE_SIZE
;
1715 // FIXME: Move RtlpDphAllocateNode(DphRoot) to this place
1716 AvailableNode
= RtlpDphFindAvailableMemory(DphRoot
, AllocateSize
, TRUE
);
1719 DPRINT1("Page heap: Unable to allocate virtual memory\n");
1722 /* Release the lock */
1723 RtlpDphPostProcessing(DphRoot
);
1727 ASSERT(AvailableNode
->nVirtualBlockSize
>= AllocateSize
);
1729 /* Set protection */
1730 Status
= RtlpDphSetProtectionBeforeUse(DphRoot
,
1731 AvailableNode
->pVirtualBlock
,
1733 if (!NT_SUCCESS(Status
))
1738 /* Save available node pointer */
1739 Ptr
= AvailableNode
->pVirtualBlock
;
1741 /* Check node's size */
1742 if (AvailableNode
->nVirtualBlockSize
> AllocateSize
)
1744 /* The block contains too much free space, reduce it */
1745 AvailableNode
->pVirtualBlock
+= AllocateSize
;
1746 AvailableNode
->nVirtualBlockSize
-= AllocateSize
;
1747 DphRoot
->nAvailableAllocationBytesCommitted
-= AllocateSize
;
1749 /* Allocate a new node which will be our busy node */
1750 BusyNode
= RtlpDphAllocateNode(DphRoot
);
1751 ASSERT(BusyNode
!= NULL
);
1752 BusyNode
->pVirtualBlock
= Ptr
;
1753 BusyNode
->nVirtualBlockSize
= AllocateSize
;
1757 /* The block's size fits exactly */
1758 RtlpDphRemoveFromAvailableList(DphRoot
, AvailableNode
);
1759 BusyNode
= AvailableNode
;
1762 /* Calculate actual user size */
1763 if (DphRoot
->HeapFlags
& HEAP_NO_ALIGNMENT
)
1764 UserActualSize
= Size
;
1766 UserActualSize
= ROUND_UP(Size
, 8);
1768 /* Set up the block */
1769 BusyNode
->nVirtualAccessSize
= AccessSize
;
1770 BusyNode
->nUserActualSize
= UserActualSize
;
1771 BusyNode
->nUserRequestedSize
= Size
;
1773 if (DphRoot
->ExtraFlags
& DPH_EXTRA_CHECK_UNDERRUN
)
1774 BusyNode
->pUserAllocation
= BusyNode
->pVirtualBlock
+ PAGE_SIZE
;
1776 BusyNode
->pUserAllocation
= BusyNode
->pVirtualBlock
+ BusyNode
->nVirtualAccessSize
- UserActualSize
;
1778 BusyNode
->UserValue
= NULL
;
1779 BusyNode
->UserFlags
= Flags
& HEAP_SETTABLE_USER_FLAGS
;
1781 // FIXME: Don't forget about stack traces if such flag was set
1782 BusyNode
->StackTrace
= NULL
;
1784 /* Place it on busy list */
1785 RtlpDphPlaceOnBusyList(DphRoot
, BusyNode
);
1787 /* Zero or patter-fill memory depending on flags */
1788 if (Flags
& HEAP_ZERO_MEMORY
)
1789 RtlZeroMemory(BusyNode
->pUserAllocation
, Size
);
1791 RtlFillMemory(BusyNode
->pUserAllocation
, Size
, DPH_FILL_INFIX
);
1793 /* Write DPH info */
1794 if (!(DphRoot
->ExtraFlags
& DPH_EXTRA_CHECK_UNDERRUN
))
1796 RtlpDphWritePageHeapBlockInformation(DphRoot
,
1797 BusyNode
->pUserAllocation
,
1802 /* Finally allocation is done, perform validation again if required */
1803 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
&& !Biased
)
1805 RtlpDphInternalValidatePageHeap(DphRoot
, NULL
, 0);
1808 /* Release the lock */
1809 RtlpDphPostProcessing(DphRoot
);
1811 DPRINT("Allocated user block pointer: %p\n", BusyNode
->pUserAllocation
);
1813 /* Return pointer to user allocation */
1814 return BusyNode
->pUserAllocation
;
1818 RtlpPageHeapFree(HANDLE HeapPtr
,
1822 PDPH_HEAP_ROOT DphRoot
;
1823 PDPH_HEAP_BLOCK Node
;
1824 ULONG ValidationInfo
;
1825 PDPH_BLOCK_INFORMATION Info
;
1827 /* Check for a NULL pointer freeing */
1830 if (RtlpDphBreakOptions
& DPH_BREAK_ON_NULL_FREE
)
1832 DPRINT1("Page heap: freeing a null pointer \n");
1838 /* Get a pointer to the heap root */
1839 DphRoot
= RtlpDphPointerFromHandle(HeapPtr
);
1840 if (!DphRoot
) return FALSE
;
1842 /* Acquire the heap lock */
1843 RtlpDphPreProcessing(DphRoot
, Flags
);
1845 /* Perform internal validation if specified by flags */
1846 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
)
1847 RtlpDphInternalValidatePageHeap(DphRoot
, NULL
, 0);
1849 /* Add heap flags */
1850 Flags
|= DphRoot
->HeapFlags
;
1852 /* Find busy memory */
1853 Node
= RtlpDphFindBusyMemory(DphRoot
, Ptr
);
1857 /* This block was not found in page heap, try a normal heap instead */
1858 //RtlpDphNormalHeapFree();
1862 if (!(DphRoot
->ExtraFlags
& DPH_EXTRA_CHECK_UNDERRUN
))
1864 /* Check and report corrupted block */
1865 if (!RtlpDphIsPageHeapBlock(DphRoot
, Ptr
, &ValidationInfo
, TRUE
))
1867 RtlpDphReportCorruptedBlock(DphRoot
, 1, Ptr
, ValidationInfo
);
1870 // FIXME: Should go inside RtlpDphSetProtectionAfterUse
1871 if (Node
->nVirtualAccessSize
!= 0)
1874 Info
= (PDPH_BLOCK_INFORMATION
)Node
->pUserAllocation
- 1;
1875 Info
->StartStamp
= DPH_FILL_START_STAMP_2
;
1876 Info
->EndStamp
= DPH_FILL_END_STAMP_2
;
1878 RtlpDphProtectVm(Node
->pVirtualBlock
, Node
->nVirtualAccessSize
, PAGE_NOACCESS
);
1883 // FIXME: Should go inside RtlpDphSetProtectionAfterUse
1884 if (Node
->nVirtualAccessSize
!= 0)
1885 RtlpDphProtectVm(Node
->pVirtualBlock
+ PAGE_SIZE
, Node
->nVirtualAccessSize
, PAGE_NOACCESS
);
1888 /* Set new protection */
1889 //RtlpDphSetProtectionAfterUse(DphRoot, Node);
1891 /* Remove it from the list of busy nodes */
1892 RtlpDphRemoveFromBusyList(DphRoot
, Node
);
1894 /* And put it into the list of free nodes */
1895 RtlpDphPlaceOnFreeList(DphRoot
, Node
);
1897 //if (DphRoot->ExtraFlags & DPH_EXTRA_LOG_STACK_TRACES)
1898 // Node->StackTrace = RtlpDphLogStackTrace(3);
1900 Node
->StackTrace
= NULL
;
1902 /* Leave the heap lock */
1903 RtlpDphPostProcessing(DphRoot
);
1905 /* Return success */
1910 RtlpPageHeapReAllocate(HANDLE HeapPtr
,
1915 PDPH_HEAP_ROOT DphRoot
;
1916 PDPH_HEAP_BLOCK Node
= NULL
, AllocatedNode
;
1917 BOOLEAN Biased
= FALSE
, UseNormalHeap
= FALSE
, OldBlockPageHeap
= TRUE
;
1918 ULONG ValidationInfo
;
1920 PVOID NewAlloc
= NULL
;
1922 /* Check requested size */
1923 if (Size
> 0x7FF00000)
1925 DPRINT1("extreme size request\n");
1927 /* Generate an exception if needed */
1928 if (Flags
& HEAP_GENERATE_EXCEPTIONS
) RtlpDphRaiseException(STATUS_NO_MEMORY
);
1933 /* Unbias the pointer if necessary */
1934 if (IS_BIASED_POINTER(HeapPtr
))
1936 HeapPtr
= (PVOID
)POINTER_REMOVE_BIAS(HeapPtr
);
1940 /* Get a pointer to the heap root */
1941 DphRoot
= RtlpDphPointerFromHandle(HeapPtr
);
1942 if (!DphRoot
) return NULL
;
1944 /* Acquire the heap lock */
1945 RtlpDphPreProcessing(DphRoot
, Flags
);
1947 /* Perform internal validation if specified by flags */
1948 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
)
1950 RtlpDphInternalValidatePageHeap(DphRoot
, NULL
, 0);
1953 /* Add heap flags */
1954 Flags
|= DphRoot
->HeapFlags
;
1956 /* Exit with NULL right away if inplace is specified */
1957 if (Flags
& HEAP_REALLOC_IN_PLACE_ONLY
)
1959 /* Release the lock */
1960 RtlpDphPostProcessing(DphRoot
);
1962 /* Generate an exception if needed */
1963 if (Flags
& HEAP_GENERATE_EXCEPTIONS
) RtlpDphRaiseException(STATUS_NO_MEMORY
);
1968 /* Try to get node of the allocated block */
1969 AllocatedNode
= RtlpDphFindBusyMemory(DphRoot
, Ptr
);
1973 /* This block was not found in page heap, try a normal heap instead */
1974 //RtlpDphNormalHeapFree();
1976 OldBlockPageHeap
= FALSE
;
1979 /* Check the block */
1980 if (!(DphRoot
->ExtraFlags
& DPH_EXTRA_CHECK_UNDERRUN
))
1982 if (!RtlpDphIsPageHeapBlock(DphRoot
, AllocatedNode
->pUserAllocation
, &ValidationInfo
, TRUE
))
1984 RtlpDphReportCorruptedBlock(DphRoot
, 3, AllocatedNode
->pUserAllocation
, ValidationInfo
);
1988 /* Remove old one from the busy list */
1989 RtlpDphRemoveFromBusyList(DphRoot
, AllocatedNode
);
1991 if (!Biased
&& !RtlpDphShouldAllocateInPageHeap(DphRoot
, Size
))
1993 // FIXME: Use normal heap
1995 UseNormalHeap
= TRUE
;
1999 /* Now do a trick: bias the pointer and call our allocate routine */
2000 NewAlloc
= RtlpPageHeapAllocate((PVOID
)POINTER_ADD_BIAS(HeapPtr
), Flags
, Size
);
2005 /* New allocation failed, put the block back (if it was found in page heap) */
2006 RtlpDphPlaceOnBusyList(DphRoot
, AllocatedNode
);
2008 /* Release the lock */
2009 RtlpDphPostProcessing(DphRoot
);
2011 /* Perform validation again if required */
2012 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
)
2014 RtlpDphInternalValidatePageHeap(DphRoot
, NULL
, 0);
2017 /* Generate an exception if needed */
2018 if (Flags
& HEAP_GENERATE_EXCEPTIONS
) RtlpDphRaiseException(STATUS_NO_MEMORY
);
2023 /* Copy contents of the old block */
2024 if (AllocatedNode
->nUserRequestedSize
> Size
)
2027 DataSize
= AllocatedNode
->nUserRequestedSize
;
2029 if (DataSize
!= 0) RtlCopyMemory(NewAlloc
, Ptr
, DataSize
);
2031 /* Copy user flags and values */
2034 /* Get the node of the new block */
2035 Node
= RtlpDphFindBusyMemory(DphRoot
, NewAlloc
);
2036 ASSERT(Node
!= NULL
);
2038 /* Set its values/flags */
2039 Node
->UserValue
= AllocatedNode
->UserValue
;
2040 if (Flags
& HEAP_SETTABLE_USER_FLAGS
)
2041 Node
->UserFlags
= Flags
& HEAP_SETTABLE_USER_FLAGS
;
2043 Node
->UserFlags
= AllocatedNode
->UserFlags
;
2046 if (!OldBlockPageHeap
)
2048 /* Weird scenario, investigate */
2052 /* Mark the old block as no access */
2053 if (AllocatedNode
->nVirtualAccessSize
!= 0)
2055 RtlpDphProtectVm(AllocatedNode
->pVirtualBlock
, AllocatedNode
->nVirtualAccessSize
, PAGE_NOACCESS
);
2058 /* And place it on the free list */
2059 RtlpDphPlaceOnFreeList(DphRoot
, AllocatedNode
);
2061 // FIXME: Capture stack traces if needed
2062 AllocatedNode
->StackTrace
= NULL
;
2064 /* Finally allocation is done, perform validation again if required */
2065 if (RtlpDphDebugOptions
& DPH_DEBUG_INTERNAL_VALIDATE
&& !Biased
)
2067 RtlpDphInternalValidatePageHeap(DphRoot
, NULL
, 0);
2070 /* Release the lock */
2071 RtlpDphPostProcessing(DphRoot
);
2073 DPRINT("Allocated new user block pointer: %p\n", NewAlloc
);
2075 /* Return pointer to user allocation */
2080 RtlpPageHeapGetUserInfo(PVOID HeapHandle
,
2086 PDPH_HEAP_ROOT DphRoot
;
2087 PDPH_HEAP_BLOCK Node
;
2089 /* Get a pointer to the heap root */
2090 DphRoot
= RtlpDphPointerFromHandle(HeapHandle
);
2091 if (!DphRoot
) return FALSE
;
2093 /* Add heap flags */
2094 Flags
|= DphRoot
->HeapFlags
;
2096 /* Acquire the heap lock */
2097 RtlpDphPreProcessing(DphRoot
, Flags
);
2099 /* Find busy memory */
2100 Node
= RtlpDphFindBusyMemory(DphRoot
, BaseAddress
);
2104 /* This block was not found in page heap, try a normal heap instead */
2105 //RtlpDphNormalHeapGetUserInfo();
2110 /* Get user values and flags and store them in user provided pointers */
2111 if (UserValue
) *UserValue
= Node
->UserValue
;
2112 if (UserFlags
) *UserFlags
= Node
->UserFlags
;
2114 /* Leave the heap lock */
2115 RtlpDphPostProcessing(DphRoot
);
2117 /* Return success */
2122 RtlpPageHeapSetUserValue(PVOID HeapHandle
,
2127 PDPH_HEAP_ROOT DphRoot
;
2128 PDPH_HEAP_BLOCK Node
;
2130 /* Get a pointer to the heap root */
2131 DphRoot
= RtlpDphPointerFromHandle(HeapHandle
);
2132 if (!DphRoot
) return FALSE
;
2134 /* Add heap flags */
2135 Flags
|= DphRoot
->HeapFlags
;
2137 /* Acquire the heap lock */
2138 RtlpDphPreProcessing(DphRoot
, Flags
);
2140 /* Find busy memory */
2141 Node
= RtlpDphFindBusyMemory(DphRoot
, BaseAddress
);
2145 /* This block was not found in page heap, try a normal heap instead */
2146 //RtlpDphNormalHeapSetUserValue();
2151 /* Get user values and flags and store them in user provided pointers */
2152 Node
->UserValue
= UserValue
;
2154 /* Leave the heap lock */
2155 RtlpDphPostProcessing(DphRoot
);
2157 /* Return success */
2163 RtlpPageHeapSetUserFlags(PVOID HeapHandle
,
2166 ULONG UserFlagsReset
,
2169 PDPH_HEAP_ROOT DphRoot
;
2170 PDPH_HEAP_BLOCK Node
;
2172 /* Get a pointer to the heap root */
2173 DphRoot
= RtlpDphPointerFromHandle(HeapHandle
);
2174 if (!DphRoot
) return FALSE
;
2176 /* Add heap flags */
2177 Flags
|= DphRoot
->HeapFlags
;
2179 /* Acquire the heap lock */
2180 RtlpDphPreProcessing(DphRoot
, Flags
);
2182 /* Find busy memory */
2183 Node
= RtlpDphFindBusyMemory(DphRoot
, BaseAddress
);
2187 /* This block was not found in page heap, try a normal heap instead */
2188 //RtlpDphNormalHeapSetUserFlags();
2193 /* Get user values and flags and store them in user provided pointers */
2194 Node
->UserFlags
&= ~(UserFlagsReset
);
2195 Node
->UserFlags
|= UserFlagsSet
;
2197 /* Leave the heap lock */
2198 RtlpDphPostProcessing(DphRoot
);
2200 /* Return success */
2205 RtlpPageHeapSize(HANDLE HeapHandle
,
2209 PDPH_HEAP_ROOT DphRoot
;
2210 PDPH_HEAP_BLOCK Node
;
2213 /* Get a pointer to the heap root */
2214 DphRoot
= RtlpDphPointerFromHandle(HeapHandle
);
2215 if (!DphRoot
) return -1;
2217 /* Add heap flags */
2218 Flags
|= DphRoot
->HeapFlags
;
2220 /* Acquire the heap lock */
2221 RtlpDphPreProcessing(DphRoot
, Flags
);
2223 /* Find busy memory */
2224 Node
= RtlpDphFindBusyMemory(DphRoot
, BaseAddress
);
2228 /* This block was not found in page heap, try a normal heap instead */
2229 //RtlpDphNormalHeapSize();
2234 /* Get heap block size */
2235 Size
= Node
->nUserRequestedSize
;
2237 /* Leave the heap lock */
2238 RtlpDphPostProcessing(DphRoot
);
2240 /* Return user requested size */
2246 RtlpDebugPageHeapValidate(PVOID HeapHandle
,
2250 PDPH_HEAP_ROOT DphRoot
;
2251 PDPH_HEAP_BLOCK Node
= NULL
;
2252 BOOLEAN Valid
= FALSE
;
2254 /* Get a pointer to the heap root */
2255 DphRoot
= RtlpDphPointerFromHandle(HeapHandle
);
2256 if (!DphRoot
) return -1;
2258 /* Add heap flags */
2259 Flags
|= DphRoot
->HeapFlags
;
2261 /* Acquire the heap lock */
2262 RtlpDphPreProcessing(DphRoot
, Flags
);
2264 /* Find busy memory */
2266 Node
= RtlpDphFindBusyMemory(DphRoot
, BaseAddress
);
2270 /* This block was not found in page heap, or the request is to validate all normal heap */
2271 Valid
= RtlpDphNormalHeapValidate(DphRoot
, Flags
, BaseAddress
);
2274 /* Leave the heap lock */
2275 RtlpDphPostProcessing(DphRoot
);
2277 /* Return result of a normal heap validation */
2278 if (BaseAddress
&& !Node
)
2281 /* Otherwise return our own result */
2282 if (!BaseAddress
|| Node
) Valid
= TRUE
;
2289 RtlpDphNormalHeapValidate(PDPH_HEAP_ROOT DphRoot
,
2293 PDPH_BLOCK_INFORMATION BlockInfo
= (PDPH_BLOCK_INFORMATION
)BaseAddress
- 1;
2296 /* Validate all normal heap */
2297 return RtlValidateHeap(DphRoot
->NormalHeap
, Flags
, NULL
);
2300 // FIXME: Check is this a normal heap block
2301 /*if (!RtlpDphIsNormalHeapBlock(DphRoot, BaseAddress, &ValidationInfo))
2305 return RtlValidateHeap(DphRoot
->NormalHeap
, Flags
, BlockInfo
);