35a8e1b2c440ab11efc828e65873a7775e49c4b6
[reactos.git] / reactos / lib / rtl / heappage.c
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
6 */
7
8 /* Useful references:
9 http://msdn.microsoft.com/en-us/library/ms220938(VS.80).aspx
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <rtl.h>
15 #include <heap.h>
16
17 #define NDEBUG
18 #include <debug.h>
19
20 /* TYPES **********************************************************************/
21
22 typedef struct _DPH_BLOCK_INFORMATION
23 {
24 ULONG StartStamp;
25 PVOID Heap;
26 ULONG RequestedSize;
27 ULONG ActualSize;
28 union
29 {
30 LIST_ENTRY FreeQueue;
31 SINGLE_LIST_ENTRY FreePushList;
32 WORD TraceIndex;
33 };
34 PVOID StackTrace;
35 ULONG EndStamp;
36 } DPH_BLOCK_INFORMATION, *PDPH_BLOCK_INFORMATION;
37
38 typedef struct _DPH_HEAP_BLOCK
39 {
40 union
41 {
42 struct _DPH_HEAP_BLOCK *pNextAlloc;
43 LIST_ENTRY AvailableEntry;
44 RTL_BALANCED_LINKS TableLinks;
45 };
46 PUCHAR pUserAllocation;
47 PUCHAR pVirtualBlock;
48 ULONG nVirtualBlockSize;
49 ULONG nVirtualAccessSize;
50 ULONG nUserRequestedSize;
51 ULONG nUserActualSize;
52 PVOID UserValue;
53 ULONG UserFlags;
54 PRTL_TRACE_BLOCK StackTrace;
55 LIST_ENTRY AdjacencyEntry;
56 PUCHAR pVirtualRegion;
57 } DPH_HEAP_BLOCK, *PDPH_HEAP_BLOCK;
58
59 typedef struct _DPH_HEAP_ROOT
60 {
61 ULONG Signature;
62 ULONG HeapFlags;
63 PRTL_CRITICAL_SECTION HeapCritSect;
64 ULONG nRemoteLockAcquired;
65
66 PDPH_HEAP_BLOCK pVirtualStorageListHead;
67 PDPH_HEAP_BLOCK pVirtualStorageListTail;
68 ULONG nVirtualStorageRanges;
69 ULONG nVirtualStorageBytes;
70
71 RTL_AVL_TABLE BusyNodesTable;
72 PDPH_HEAP_BLOCK NodeToAllocate;
73 ULONG nBusyAllocations;
74 ULONG nBusyAllocationBytesCommitted;
75
76 PDPH_HEAP_BLOCK pFreeAllocationListHead;
77 PDPH_HEAP_BLOCK pFreeAllocationListTail;
78 ULONG nFreeAllocations;
79 ULONG nFreeAllocationBytesCommitted;
80
81 LIST_ENTRY AvailableAllocationHead;
82 ULONG nAvailableAllocations;
83 ULONG nAvailableAllocationBytesCommitted;
84
85 PDPH_HEAP_BLOCK pUnusedNodeListHead;
86 PDPH_HEAP_BLOCK pUnusedNodeListTail;
87 ULONG nUnusedNodes;
88 ULONG nBusyAllocationBytesAccessible;
89 PDPH_HEAP_BLOCK pNodePoolListHead;
90 PDPH_HEAP_BLOCK pNodePoolListTail;
91 ULONG nNodePools;
92 ULONG nNodePoolBytes;
93
94 LIST_ENTRY NextHeap;
95 ULONG ExtraFlags;
96 ULONG Seed;
97 PVOID NormalHeap;
98 PRTL_TRACE_BLOCK CreateStackTrace;
99 PVOID FirstThread;
100 } DPH_HEAP_ROOT, *PDPH_HEAP_ROOT;
101
102 /* GLOBALS ********************************************************************/
103
104 BOOLEAN RtlpPageHeapEnabled = FALSE;
105 ULONG RtlpDphGlobalFlags;
106 ULONG RtlpPageHeapSizeRangeStart, RtlpPageHeapSizeRangeEnd;
107 ULONG RtlpPageHeapDllRangeStart, RtlpPageHeapDllRangeEnd;
108 WCHAR RtlpDphTargetDlls[512];
109
110 ULONG RtlpDphBreakOptions;
111 ULONG RtlpDphDebugOptions;
112
113 LIST_ENTRY RtlpDphPageHeapList;
114 BOOLEAN RtlpDphPageHeapListInitialized;
115 RTL_CRITICAL_SECTION RtlpDphPageHeapListLock;
116 ULONG RtlpDphPageHeapListLength;
117 UNICODE_STRING RtlpDphTargetDllsUnicode;
118
119 /* Counters */
120 LONG RtlpDphCounter;
121 LONG RtlpDphAllocFails;
122 LONG RtlpDphReleaseFails;
123 LONG RtlpDphFreeFails;
124 LONG RtlpDphProtectFails;
125
126 #define DPH_RESERVE_SIZE 0x100000
127 #define DPH_POOL_SIZE 0x4000
128
129 /* RtlpDphBreakOptions */
130 #define DPH_BREAK_ON_RESERVE_FAIL 0x01
131 #define DPH_BREAK_ON_COMMIT_FAIL 0x02
132 #define DPH_BREAK_ON_RELEASE_FAIL 0x04
133 #define DPH_BREAK_ON_FREE_FAIL 0x08
134 #define DPH_BREAK_ON_PROTECT_FAIL 0x10
135
136 /* RtlpDphDebugOptions */
137 #define DPH_DEBUG_INTERNAL_VALIDATE 0x01
138 #define DPH_DEBUG_VERBOSE 0x04
139
140 /* Fillers */
141 #define DPH_FILL 0xEEEEEEEE
142
143 /* Signatures */
144 #define DPH_SIGNATURE 0xFFEEDDCC
145
146 /* FUNCTIONS ******************************************************************/
147
148 NTSTATUS NTAPI
149 RtlpSecMemFreeVirtualMemory(HANDLE Process, PVOID *Base, PSIZE_T Size, ULONG Type)
150 {
151 NTSTATUS Status;
152 //PVOID *SavedBase = Base;
153 //PSIZE_T SavedSize = Size;
154
155 /* Free the memory */
156 Status = ZwFreeVirtualMemory(Process, Base, Size, Type);
157
158 /* Flush secure memory cache if needed and retry freeing */
159 #if 0
160 if (Status == STATUS_INVALID_PAGE_PROTECTION &&
161 Process == NtCurrentProcess() &&
162 RtlFlushSecureMemoryCache(*SavedBase, *SavedSize))
163 {
164 Status = ZwFreeVirtualMemory(NtCurrentProcess(), SavedBase, SavedSize, Type);
165 }
166 #endif
167
168 return Status;
169 }
170
171 NTSTATUS NTAPI
172 RtlpDphAllocateVm(PVOID *Base, SIZE_T Size, ULONG Type, ULONG Protection)
173 {
174 NTSTATUS Status;
175 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
176 Base,
177 0,
178 &Size,
179 Type,
180 Protection);
181
182 /* Check for failures */
183 if (!NT_SUCCESS(Status))
184 {
185 if (Type == MEM_RESERVE)
186 {
187 _InterlockedIncrement(&RtlpDphCounter);
188 if (RtlpDphBreakOptions & DPH_BREAK_ON_RESERVE_FAIL)
189 {
190 DPRINT1("Page heap: AllocVm (%p, %p, %x) failed with %x \n", Base, Size, Type, Status);
191 DbgBreakPoint();
192 return Status;
193 }
194 }
195 else
196 {
197 _InterlockedIncrement(&RtlpDphAllocFails);
198 if (RtlpDphBreakOptions & DPH_BREAK_ON_COMMIT_FAIL)
199 {
200 DPRINT1("Page heap: AllocVm (%p, %p, %x) failed with %x \n", Base, Size, Type, Status);
201 DbgBreakPoint();
202 return Status;
203 }
204 }
205 }
206
207 return Status;
208 }
209
210 NTSTATUS NTAPI
211 RtlpDphFreeVm(PVOID Base, SIZE_T Size, ULONG Type, ULONG Protection)
212 {
213 NTSTATUS Status;
214
215 /* Free the memory */
216 Status = RtlpSecMemFreeVirtualMemory(NtCurrentProcess(), &Base, &Size, Type);
217
218 /* Log/report failures */
219 if (!NT_SUCCESS(Status))
220 {
221 if (Type == MEM_RELEASE)
222 {
223 _InterlockedIncrement(&RtlpDphReleaseFails);
224 if (RtlpDphBreakOptions & DPH_BREAK_ON_RELEASE_FAIL)
225 {
226 DPRINT1("Page heap: FreeVm (%p, %p, %x) failed with %x \n", Base, Size, Type, Status);
227 DbgBreakPoint();
228 return Status;
229 }
230 }
231 else
232 {
233 _InterlockedIncrement(&RtlpDphFreeFails);
234 if (RtlpDphBreakOptions & DPH_BREAK_ON_FREE_FAIL)
235 {
236 DPRINT1("Page heap: FreeVm (%p, %p, %x) failed with %x \n", Base, Size, Type, Status);
237 DbgBreakPoint();
238 return Status;
239 }
240 }
241 }
242
243 return Status;
244 }
245
246 NTSTATUS NTAPI
247 RtlpDphProtectVm(PVOID Base, SIZE_T Size, ULONG Protection)
248 {
249 NTSTATUS Status;
250 ULONG OldProtection;
251
252 /* Change protection */
253 Status = ZwProtectVirtualMemory(NtCurrentProcess(), &Base, &Size, Protection, &OldProtection);
254
255 /* Log/report failures */
256 if (!NT_SUCCESS(Status))
257 {
258 _InterlockedIncrement(&RtlpDphProtectFails);
259 if (RtlpDphBreakOptions & DPH_BREAK_ON_PROTECT_FAIL)
260 {
261 DPRINT1("Page heap: ProtectVm (%p, %p, %x) failed with %x \n", Base, Size, Protection, Status);
262 DbgBreakPoint();
263 return Status;
264 }
265 }
266
267 return Status;
268 }
269
270 VOID NTAPI
271 RtlpDphAddNewPool(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK NodeBlock, PVOID Virtual, SIZE_T Size, BOOLEAN Add)
272 {
273 PDPH_HEAP_BLOCK DphNode, DphStartNode;
274 ULONG NodeCount;
275
276 NodeCount = (Size >> 6) - 1;
277 DphStartNode = Virtual;
278
279 /* Set pNextAlloc for all blocks */
280 for (DphNode = Virtual; NodeCount > 0; DphNode++, NodeCount--)
281 DphNode->pNextAlloc = DphNode + 1;
282
283 /* and the last one */
284 DphNode->pNextAlloc = NULL;
285
286 /* Add it to the tail of unused node list */
287 if (DphRoot->pUnusedNodeListTail)
288 DphRoot->pUnusedNodeListTail->pNextAlloc = DphStartNode;
289 else
290 DphRoot->pUnusedNodeListHead = DphStartNode;
291
292 DphRoot->pUnusedNodeListTail = DphNode;
293
294 /* Increase counters */
295 DphRoot->nUnusedNodes += NodeCount;
296
297 if (Add)
298 {
299 UNIMPLEMENTED;
300 }
301 }
302
303 PDPH_HEAP_BLOCK NTAPI
304 RtlpDphFindAvailableMemory(PDPH_HEAP_ROOT DphRoot,
305 SIZE_T Size,
306 PDPH_HEAP_BLOCK *Prev)
307 {
308 UNIMPLEMENTED;
309 return NULL;
310 }
311
312
313 PDPH_HEAP_BLOCK NTAPI
314 RtlpDphTakeNodeFromUnusedList(PDPH_HEAP_ROOT DphRoot)
315 {
316 UNIMPLEMENTED;
317 return NULL;
318 }
319
320 VOID NTAPI
321 RtlpDphReturnNodeToUnusedList(PDPH_HEAP_ROOT DphRoot,
322 PDPH_HEAP_BLOCK Node)
323 {
324 }
325
326 VOID NTAPI
327 RtlpDphRemoveFromAvailableList(PDPH_HEAP_ROOT DphRoot,
328 PDPH_HEAP_BLOCK Node)
329 {
330 UNIMPLEMENTED;
331 }
332
333 VOID NTAPI
334 RtlpDphCoalesceNodeIntoAvailable(PDPH_HEAP_ROOT DphRoot,
335 PDPH_HEAP_BLOCK Node)
336 {
337 UNIMPLEMENTED;
338 }
339
340 PDPH_HEAP_BLOCK NTAPI
341 RtlpDphAllocateNode(PDPH_HEAP_ROOT DphRoot)
342 {
343 PDPH_HEAP_BLOCK Node;
344 NTSTATUS Status;
345 ULONG Size = DPH_POOL_SIZE;
346 PVOID Ptr;
347
348 /* Check for the easy case */
349 if (DphRoot->pUnusedNodeListHead)
350 {
351 /* Just take a node from this list */
352 Node = RtlpDphTakeNodeFromUnusedList(DphRoot);
353 ASSERT(Node);
354 return Node;
355 }
356
357 /* There is a need to make free space */
358 Node = RtlpDphFindAvailableMemory(DphRoot, DPH_POOL_SIZE, NULL);
359
360 if (!DphRoot->pUnusedNodeListHead && !Node)
361 {
362 /* Retry with a smaller request */
363 Size = PAGE_SIZE;
364 Node = RtlpDphFindAvailableMemory(DphRoot, PAGE_SIZE, NULL);
365 }
366
367 if (!DphRoot->pUnusedNodeListHead)
368 {
369 if (Node)
370 {
371 RtlpDphRemoveFromAvailableList(DphRoot, Node);
372 Ptr = Node->pVirtualBlock;
373 }
374 else
375 {
376 /* No free space, need to alloc a new VM block */
377 Size = DPH_POOL_SIZE;
378 Status = RtlpDphAllocateVm(&Ptr, DPH_RESERVE_SIZE, MEM_COMMIT, PAGE_NOACCESS);
379
380 if (!NT_SUCCESS(Status))
381 {
382 /* Retry with a smaller size */
383 Status = RtlpDphAllocateVm(&Ptr, 0x10000, MEM_COMMIT, PAGE_NOACCESS);
384 if (!NT_SUCCESS(Status)) return NULL;
385 }
386 }
387
388 /* VM is allocated at this point, set protection */
389 Status = RtlpDphProtectVm(Ptr, Size, PAGE_READWRITE);
390 if (!NT_SUCCESS(Status))
391 {
392 ASSERT(FALSE);
393 return NULL;
394 }
395
396 /* Zero the memory */
397 if (Node) RtlZeroMemory(Ptr, Size);
398
399 /* Add a new pool based on this VM */
400 RtlpDphAddNewPool(DphRoot, Node, Ptr, Size, TRUE);
401
402 if (!Node)
403 {
404 ASSERT(FALSE);
405 }
406 else
407 {
408 if (Node->nVirtualBlockSize > Size)
409 {
410 Node->pVirtualBlock += Size;
411 Node->nVirtualBlockSize -= Size;
412
413 RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node);
414 }
415 else
416 {
417 RtlpDphReturnNodeToUnusedList(DphRoot, Node);
418 }
419 }
420 }
421
422 return RtlpDphTakeNodeFromUnusedList(DphRoot);
423 }
424
425 VOID NTAPI
426 RtlpDphPlaceOnPoolList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK DphNode)
427 {
428 UNIMPLEMENTED;
429 }
430
431 VOID NTAPI
432 RtlpDphPlaceOnVirtualList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK DphNode)
433 {
434 UNIMPLEMENTED;
435 }
436
437 RTL_GENERIC_COMPARE_RESULTS
438 NTAPI
439 RtlpDphCompareNodeForTable(IN PRTL_AVL_TABLE Table,
440 IN PVOID FirstStruct,
441 IN PVOID SecondStruct)
442 {
443 /* FIXME: TODO */
444 ASSERT(FALSE);
445 return 0;
446 }
447
448 PVOID
449 NTAPI
450 RtlpDphAllocateNodeForTable(IN PRTL_AVL_TABLE Table,
451 IN CLONG ByteSize)
452 {
453 /* FIXME: TODO */
454 ASSERT(FALSE);
455 return NULL;
456 }
457
458 VOID
459 NTAPI
460 RtlpDphFreeNodeForTable(IN PRTL_AVL_TABLE Table,
461 IN PVOID Buffer)
462 {
463 /* FIXME: TODO */
464 ASSERT(FALSE);
465 }
466
467 NTSTATUS NTAPI
468 RtlpDphInitializeDelayedFreeQueue()
469 {
470 UNIMPLEMENTED;
471 return STATUS_SUCCESS;
472 }
473
474 NTSTATUS NTAPI
475 RtlpDphTargetDllsLogicInitialize()
476 {
477 UNIMPLEMENTED;
478 return STATUS_SUCCESS;
479 }
480
481 VOID NTAPI
482 RtlpDphInternalValidatePageHeap(PDPH_HEAP_ROOT DphRoot, PVOID Address, ULONG Value)
483 {
484 UNIMPLEMENTED;
485 }
486
487 NTSTATUS NTAPI
488 RtlpDphProcessStartupInitialization()
489 {
490 NTSTATUS Status;
491 PTEB Teb = NtCurrentTeb();
492
493 /* Initialize the DPH heap list and its critical section */
494 InitializeListHead(&RtlpDphPageHeapList);
495 Status = RtlInitializeCriticalSection(&RtlpDphPageHeapListLock);
496 if (!NT_SUCCESS(Status))
497 {
498 ASSERT(FALSE);
499 return Status;
500 }
501
502 /* Initialize delayed-free queue */
503 Status = RtlpDphInitializeDelayedFreeQueue();
504 if (!NT_SUCCESS(Status)) return Status;
505
506 /* Initialize the target dlls string */
507 RtlInitUnicodeString(&RtlpDphTargetDllsUnicode, RtlpDphTargetDlls);
508 Status = RtlpDphTargetDllsLogicInitialize();
509
510 /* Per-process DPH init is done */
511 RtlpDphPageHeapListInitialized = TRUE;
512
513 DPRINT1("Page heap: pid 0x%X: page heap enabled with flags 0x%X.\n", Teb->ClientId.UniqueProcess, RtlpDphGlobalFlags);
514
515 return Status;
516 }
517
518 HANDLE NTAPI
519 RtlpPageHeapCreate(ULONG Flags,
520 PVOID Addr,
521 SIZE_T TotalSize,
522 SIZE_T CommitSize,
523 PVOID Lock,
524 PRTL_HEAP_PARAMETERS Parameters)
525 {
526 PVOID Base;
527 PHEAP HeapPtr;
528 PDPH_HEAP_ROOT DphRoot;
529 PDPH_HEAP_BLOCK DphNode;
530 ULONG MemSize;
531 NTSTATUS Status;
532 LARGE_INTEGER PerfCounter;
533
534 /* Check for a DPH bypass flag */
535 if ((ULONG_PTR)Parameters == -1) return NULL;
536
537 /* Make sure no user-allocated stuff was provided */
538 if (Addr || Lock) return NULL;
539
540 /* Allocate minimum amount of virtual memory */
541 MemSize = DPH_RESERVE_SIZE;
542 Status = RtlpDphAllocateVm(&Base, MemSize, MEM_COMMIT, PAGE_NOACCESS);
543 if (!NT_SUCCESS(Status))
544 {
545 ASSERT(FALSE);
546 return NULL;
547 }
548
549 /* Set protection */
550 Status = RtlpDphProtectVm(Base, 2*PAGE_SIZE + DPH_POOL_SIZE, PAGE_READWRITE);
551 if (!NT_SUCCESS(Status))
552 {
553 //RtlpDphFreeVm(Base, 0, 0, 0);
554 ASSERT(FALSE);
555 return NULL;
556 }
557
558 /* Start preparing the 1st page. Fill it with the default filler */
559 RtlFillMemory(Base, PAGE_SIZE, DPH_FILL);
560
561 /* Set flags in the "HEAP" structure */
562 HeapPtr = (PHEAP)Base;
563 HeapPtr->Flags = Flags | HEAP_FLAG_PAGE_ALLOCS;
564 HeapPtr->ForceFlags = Flags | HEAP_FLAG_PAGE_ALLOCS;
565
566 /* Set 1st page to read only now */
567 Status = RtlpDphProtectVm(Base, PAGE_SIZE, PAGE_READONLY);
568 if (!NT_SUCCESS(Status))
569 {
570 ASSERT(FALSE);
571 return NULL;
572 }
573
574 /* 2nd page is the real DPH root block */
575 DphRoot = (PDPH_HEAP_ROOT)((PCHAR)Base + PAGE_SIZE);
576
577 /* Initialize the DPH root */
578 DphRoot->Signature = DPH_SIGNATURE;
579 DphRoot->HeapFlags = Flags;
580 DphRoot->HeapCritSect = (PRTL_CRITICAL_SECTION)((PCHAR)DphRoot + DPH_POOL_SIZE);
581 DphRoot->ExtraFlags = RtlpDphGlobalFlags;
582
583 ZwQueryPerformanceCounter(&PerfCounter, NULL);
584 DphRoot->Seed = PerfCounter.LowPart;
585
586 RtlInitializeCriticalSection(DphRoot->HeapCritSect);
587
588 /* Create a normal heap for this paged heap */
589 DphRoot->NormalHeap = RtlCreateHeap(Flags, NULL, TotalSize, CommitSize, NULL, (PRTL_HEAP_PARAMETERS)-1);
590 if (!DphRoot->NormalHeap)
591 {
592 ASSERT(FALSE);
593 return NULL;
594 }
595
596 /* 3rd page: a pool for DPH allocations */
597 RtlpDphAddNewPool(DphRoot, NULL, DphRoot + 1, DPH_POOL_SIZE - sizeof(DPH_HEAP_ROOT), FALSE);
598
599 /* Allocate internal heap blocks. For the root */
600 DphNode = RtlpDphAllocateNode(DphRoot);
601 ASSERT(DphNode != NULL);
602 DphNode->pVirtualBlock = (PUCHAR)DphRoot;
603 DphNode->nVirtualBlockSize = DPH_POOL_SIZE;
604 RtlpDphPlaceOnPoolList(DphRoot, DphNode);
605
606 /* For the memory we allocated as a whole */
607 DphNode = RtlpDphAllocateNode(DphRoot);
608 ASSERT(DphNode != NULL);
609 DphNode->pVirtualBlock = Base;
610 DphNode->nVirtualBlockSize = MemSize;
611 RtlpDphPlaceOnVirtualList(DphRoot, DphNode);
612
613 /* For the remaining part */
614 DphNode = RtlpDphAllocateNode(DphRoot);
615 ASSERT(DphNode != NULL);
616 DphNode->pVirtualBlock = (PUCHAR)Base + 2*PAGE_SIZE + DPH_POOL_SIZE;
617 DphNode->nVirtualBlockSize = MemSize - (2*PAGE_SIZE + DPH_POOL_SIZE);
618 RtlpDphCoalesceNodeIntoAvailable(DphRoot, DphNode);
619
620 //DphRoot->CreateStackTrace = RtlpDphLogStackTrace(1);
621
622 /* Initialize AVL-based busy nodes table */
623 RtlInitializeGenericTableAvl(&DphRoot->BusyNodesTable,
624 RtlpDphCompareNodeForTable,
625 RtlpDphAllocateNodeForTable,
626 RtlpDphFreeNodeForTable,
627 NULL);
628
629 /* Initialize per-process startup info */
630 if (!RtlpDphPageHeapListInitialized) RtlpDphProcessStartupInitialization();
631
632 /* Acquire the heap list lock */
633 RtlEnterCriticalSection(&RtlpDphPageHeapListLock);
634
635 /* Insert this heap to the tail of the global list */
636 InsertTailList(&RtlpDphPageHeapList, &DphRoot->NextHeap);
637
638 /* Note we increased the size of the list */
639 RtlpDphPageHeapListLength++;
640
641 /* Release the heap list lock */
642 RtlLeaveCriticalSection(&RtlpDphPageHeapListLock);
643
644 if (RtlpDphDebugOptions & DPH_DEBUG_VERBOSE)
645 {
646 DPRINT1("Page heap: process 0x%X created heap @ %p (%p, flags 0x%X)\n",
647 NtCurrentTeb()->ClientId.UniqueProcess, (PUCHAR)DphRoot - PAGE_SIZE, DphRoot->NormalHeap, DphRoot->ExtraFlags);
648 }
649
650 /* Perform internal validation if required */
651 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE)
652 RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0);
653
654 return (PUCHAR)DphRoot - PAGE_SIZE;
655 }
656
657 PVOID NTAPI
658 RtlpPageHeapDestroy(HANDLE HeapPtr)
659 {
660 return FALSE;
661 }
662
663 PVOID NTAPI
664 RtlpPageHeapAllocate(IN PVOID HeapPtr,
665 IN ULONG Flags,
666 IN SIZE_T Size)
667 {
668 return NULL;
669 }
670
671 BOOLEAN NTAPI
672 RtlpPageHeapFree(HANDLE HeapPtr,
673 ULONG Flags,
674 PVOID Ptr)
675 {
676 return FALSE;
677 }
678
679 PVOID NTAPI
680 RtlpPageHeapReAllocate(HANDLE HeapPtr,
681 ULONG Flags,
682 PVOID Ptr,
683 SIZE_T Size)
684 {
685 return NULL;
686 }
687
688 BOOLEAN NTAPI
689 RtlpPageHeapGetUserInfo(PVOID HeapHandle,
690 ULONG Flags,
691 PVOID BaseAddress,
692 PVOID *UserValue,
693 PULONG UserFlags)
694 {
695 return FALSE;
696 }
697
698 BOOLEAN NTAPI
699 RtlpPageHeapSetUserValue(PVOID HeapHandle,
700 ULONG Flags,
701 PVOID BaseAddress,
702 PVOID UserValue)
703 {
704 return FALSE;
705 }
706
707 BOOLEAN
708 NTAPI
709 RtlpPageHeapSetUserFlags(PVOID HeapHandle,
710 ULONG Flags,
711 PVOID BaseAddress,
712 ULONG UserFlagsReset,
713 ULONG UserFlagsSet)
714 {
715 return FALSE;
716 }
717
718 SIZE_T NTAPI
719 RtlpPageHeapSize(HANDLE HeapPtr,
720 ULONG Flags,
721 PVOID Ptr)
722 {
723 return 0;
724 }
725
726 /* EOF */