1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * FILE: lib/rtl/heappage.c 5 * PURPOSE: RTL Page Heap implementation 6 * PROGRAMMERS: Copyright 2011 Aleksey Bragin 7 */ 8 9 /* Useful references: 10 http://msdn.microsoft.com/en-us/library/ms220938(VS.80).aspx 11 http://blogs.msdn.com/b/jiangyue/archive/2010/03/16/windows-heap-overrun-monitoring.aspx 12 */ 13 14 /* INCLUDES *****************************************************************/ 15 16 #include <rtl.h> 17 #include <heap.h> 18 #include <reactos/verifier.h> 19 20 #define NDEBUG 21 #include <debug.h> 22 23 /* TYPES **********************************************************************/ 24 25 typedef struct _DPH_BLOCK_INFORMATION 26 { 27 ULONG StartStamp; 28 PVOID Heap; 29 SIZE_T RequestedSize; 30 SIZE_T ActualSize; 31 union 32 { 33 LIST_ENTRY FreeQueue; 34 SINGLE_LIST_ENTRY FreePushList; 35 WORD TraceIndex; 36 }; 37 PVOID StackTrace; 38 ULONG EndStamp; 39 } DPH_BLOCK_INFORMATION, *PDPH_BLOCK_INFORMATION; 40 41 typedef struct _DPH_HEAP_BLOCK 42 { 43 union 44 { 45 struct _DPH_HEAP_BLOCK *pNextAlloc; 46 LIST_ENTRY AvailableEntry; 47 RTL_BALANCED_LINKS TableLinks; 48 }; 49 PUCHAR pUserAllocation; 50 PUCHAR pVirtualBlock; 51 SIZE_T nVirtualBlockSize; 52 SIZE_T nVirtualAccessSize; 53 SIZE_T nUserRequestedSize; 54 SIZE_T nUserActualSize; 55 PVOID UserValue; 56 ULONG UserFlags; 57 PRTL_TRACE_BLOCK StackTrace; 58 LIST_ENTRY AdjacencyEntry; 59 PUCHAR pVirtualRegion; 60 } DPH_HEAP_BLOCK, *PDPH_HEAP_BLOCK; 61 62 typedef struct _DPH_HEAP_ROOT 63 { 64 ULONG Signature; 65 ULONG HeapFlags; 66 PHEAP_LOCK HeapCritSect; 67 ULONG nRemoteLockAcquired; 68 69 PDPH_HEAP_BLOCK pVirtualStorageListHead; 70 PDPH_HEAP_BLOCK pVirtualStorageListTail; 71 ULONG nVirtualStorageRanges; 72 SIZE_T nVirtualStorageBytes; 73 74 RTL_AVL_TABLE BusyNodesTable; 75 PDPH_HEAP_BLOCK NodeToAllocate; 76 ULONG nBusyAllocations; 77 SIZE_T nBusyAllocationBytesCommitted; 78 79 PDPH_HEAP_BLOCK pFreeAllocationListHead; 80 PDPH_HEAP_BLOCK pFreeAllocationListTail; 81 ULONG nFreeAllocations; 82 SIZE_T nFreeAllocationBytesCommitted; 83 84 LIST_ENTRY AvailableAllocationHead; 85 ULONG nAvailableAllocations; 86 SIZE_T nAvailableAllocationBytesCommitted; 87 88 PDPH_HEAP_BLOCK pUnusedNodeListHead; 89 PDPH_HEAP_BLOCK pUnusedNodeListTail; 90 ULONG nUnusedNodes; 91 SIZE_T nBusyAllocationBytesAccessible; 92 PDPH_HEAP_BLOCK pNodePoolListHead; 93 PDPH_HEAP_BLOCK pNodePoolListTail; 94 ULONG nNodePools; 95 SIZE_T nNodePoolBytes; 96 97 LIST_ENTRY NextHeap; 98 ULONG ExtraFlags; 99 ULONG Seed; 100 PVOID NormalHeap; 101 PRTL_TRACE_BLOCK CreateStackTrace; 102 PVOID FirstThread; 103 } DPH_HEAP_ROOT, *PDPH_HEAP_ROOT; 104 105 /* GLOBALS ********************************************************************/ 106 107 BOOLEAN RtlpPageHeapEnabled = FALSE; 108 ULONG RtlpDphGlobalFlags; 109 ULONG RtlpPageHeapSizeRangeStart, RtlpPageHeapSizeRangeEnd; 110 ULONG RtlpPageHeapDllRangeStart, RtlpPageHeapDllRangeEnd; 111 WCHAR RtlpDphTargetDlls[512]; 112 113 LIST_ENTRY RtlpDphPageHeapList; 114 BOOLEAN RtlpDphPageHeapListInitialized; 115 HEAP_LOCK _RtlpDphPageHeapListLock; 116 PHEAP_LOCK RtlpDphPageHeapListLock = &_RtlpDphPageHeapListLock; 117 ULONG RtlpDphPageHeapListLength; 118 UNICODE_STRING RtlpDphTargetDllsUnicode; 119 120 HEAP_LOCK _RtlpDphDelayedFreeQueueLock; 121 PHEAP_LOCK RtlpDphDelayedFreeQueueLock = &_RtlpDphDelayedFreeQueueLock; 122 LIST_ENTRY RtlpDphDelayedFreeQueue; 123 SLIST_HEADER RtlpDphDelayedTemporaryPushList; 124 SIZE_T RtlpDphMemoryUsedByDelayedFreeBlocks; 125 ULONG RtlpDphNumberOfDelayedFreeBlocks; 126 127 /* Counters */ 128 LONG RtlpDphCounter; 129 LONG RtlpDphAllocFails; 130 LONG RtlpDphReleaseFails; 131 LONG RtlpDphFreeFails; 132 LONG RtlpDphProtectFails; 133 134 #define DPH_RESERVE_SIZE 0x100000 135 #define DPH_POOL_SIZE 0x4000 136 #define DPH_FREE_LIST_MINIMUM 8 137 138 /* RtlpDphBreakOptions */ 139 #define DPH_BREAK_ON_RESERVE_FAIL 0x01 140 #define DPH_BREAK_ON_COMMIT_FAIL 0x02 141 #define DPH_BREAK_ON_RELEASE_FAIL 0x04 142 #define DPH_BREAK_ON_FREE_FAIL 0x08 143 #define DPH_BREAK_ON_PROTECT_FAIL 0x10 144 #define DPH_BREAK_ON_NULL_FREE 0x80 145 146 /* RtlpDphDebugOptions */ 147 #define DPH_DEBUG_INTERNAL_VALIDATE 0x01 148 #define DPH_DEBUG_VERBOSE 0x04 149 150 /* DPH ExtraFlags */ 151 #define DPH_EXTRA_LOG_STACK_TRACES 0x02 152 #define DPH_EXTRA_CHECK_UNDERRUN 0x10 153 154 /* Fillers */ 155 #define DPH_FILL 0xEEEEEEEE 156 #define DPH_FILL_START_STAMP_1 0xABCDBBBB 157 #define DPH_FILL_START_STAMP_2 0xABCDBBBA 158 #define DPH_FILL_END_STAMP_1 0xDCBABBBB 159 #define DPH_FILL_END_STAMP_2 0xDCBABBBA 160 #define DPH_FILL_SUFFIX 0xD0 161 #define DPH_FILL_INFIX 0xC0 162 163 /* Validation info flags */ 164 #define DPH_VALINFO_BAD_START_STAMP 0x01 165 #define DPH_VALINFO_BAD_END_STAMP 0x02 166 #define DPH_VALINFO_BAD_POINTER 0x04 167 #define DPH_VALINFO_BAD_PREFIX_PATTERN 0x08 168 #define DPH_VALINFO_BAD_SUFFIX_PATTERN 0x10 169 #define DPH_VALINFO_EXCEPTION 0x20 170 #define DPH_VALINFO_1 0x40 171 #define DPH_VALINFO_BAD_INFIX_PATTERN 0x80 172 #define DPH_VALINFO_ALREADY_FREED 0x100 173 #define DPH_VALINFO_CORRUPTED_AFTER_FREE 0x200 174 175 /* Signatures */ 176 #define DPH_SIGNATURE 0xFFEEDDCC 177 178 /* Biased pointer macros */ 179 #define IS_BIASED_POINTER(ptr) ((ULONG_PTR)(ptr) & 1) 180 #define POINTER_REMOVE_BIAS(ptr) ((ULONG_PTR)(ptr) & ~(ULONG_PTR)1) 181 #define POINTER_ADD_BIAS(ptr) ((ULONG_PTR)(ptr) | 1) 182 183 184 ULONG RtlpDphBreakOptions = 0;//0xFFFFFFFF; 185 ULONG RtlpDphDebugOptions; 186 187 /* FUNCTIONS ******************************************************************/ 188 189 BOOLEAN NTAPI 190 RtlpDphGrowVirtual(PDPH_HEAP_ROOT DphRoot, SIZE_T Size); 191 192 BOOLEAN NTAPI 193 RtlpDphIsNormalFreeHeapBlock(PVOID Block, PULONG ValidationInformation, BOOLEAN CheckFillers); 194 195 VOID NTAPI 196 RtlpDphReportCorruptedBlock( 197 _In_ PDPH_HEAP_ROOT DphRoot, 198 _In_ ULONG Reserved, 199 _In_ PVOID Block, 200 _In_ ULONG ValidationInfo); 201 202 BOOLEAN NTAPI 203 RtlpDphNormalHeapValidate(PDPH_HEAP_ROOT DphRoot, ULONG Flags, PVOID BaseAddress); 204 205 206 VOID NTAPI 207 RtlpDphRaiseException(NTSTATUS Status) 208 { 209 EXCEPTION_RECORD Exception; 210 211 /* Initialize exception record */ 212 Exception.ExceptionCode = Status; 213 Exception.ExceptionAddress = RtlpDphRaiseException; 214 Exception.ExceptionFlags = 0; 215 Exception.ExceptionRecord = NULL; 216 Exception.NumberParameters = 0; 217 218 /* Raise the exception */ 219 RtlRaiseException(&Exception); 220 } 221 222 PVOID NTAPI 223 RtlpDphPointerFromHandle(PVOID Handle) 224 { 225 PHEAP NormalHeap = (PHEAP)Handle; 226 PDPH_HEAP_ROOT DphHeap = (PDPH_HEAP_ROOT)((PUCHAR)Handle + PAGE_SIZE); 227 228 if (NormalHeap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS) 229 { 230 if (DphHeap->Signature == DPH_SIGNATURE) 231 return DphHeap; 232 } 233 234 DPRINT1("heap handle with incorrect signature\n"); 235 DbgBreakPoint(); 236 return NULL; 237 } 238 239 PVOID NTAPI 240 RtlpDphHeapFromPointer(PDPH_HEAP_ROOT DphHeap) 241 { 242 return ((PUCHAR)DphHeap) - PAGE_SIZE; 243 } 244 245 ULONG NTAPI 246 RtlpDphGetBlockSizeFromCorruptedBlock(PVOID Block) 247 { 248 PDPH_BLOCK_INFORMATION BlockInfo; 249 BlockInfo = (PDPH_BLOCK_INFORMATION)Block - 1; 250 251 /* Check stamps */ 252 if (BlockInfo->StartStamp != DPH_FILL_START_STAMP_1 && BlockInfo->StartStamp != DPH_FILL_START_STAMP_2) 253 { 254 return 0; 255 } 256 257 return BlockInfo->RequestedSize; 258 } 259 260 VOID NTAPI 261 RtlpDphEnterCriticalSection(PDPH_HEAP_ROOT DphRoot, ULONG Flags) 262 { 263 if (Flags & HEAP_NO_SERIALIZE) 264 { 265 /* More complex scenario */ 266 if (!RtlTryEnterHeapLock(DphRoot->HeapCritSect, TRUE)) 267 { 268 if (!DphRoot->nRemoteLockAcquired) 269 { 270 DPRINT1("multithreaded access in HEAP_NO_SERIALIZE heap\n"); 271 DbgBreakPoint(); 272 273 /* Clear out the no serialize flag */ 274 DphRoot->HeapFlags &= ~HEAP_NO_SERIALIZE; 275 } 276 277 /* Enter the heap's critical section */ 278 RtlEnterHeapLock(DphRoot->HeapCritSect, TRUE); 279 } 280 } 281 else 282 { 283 /* Just enter the heap's critical section */ 284 RtlEnterHeapLock(DphRoot->HeapCritSect, TRUE); 285 } 286 } 287 288 VOID NTAPI 289 RtlpDphLeaveCriticalSection(PDPH_HEAP_ROOT DphRoot) 290 { 291 /* Just leave the heap's critical section */ 292 RtlLeaveHeapLock(DphRoot->HeapCritSect); 293 } 294 295 296 VOID NTAPI 297 RtlpDphPreProcessing(PDPH_HEAP_ROOT DphRoot, ULONG Flags) 298 { 299 RtlpDphEnterCriticalSection(DphRoot, Flags); 300 301 /* FIXME: Validate integrity, internal lists if necessary */ 302 } 303 304 VOID NTAPI 305 RtlpDphPostProcessing(PDPH_HEAP_ROOT DphRoot) 306 { 307 if (!DphRoot) return; 308 309 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE) 310 { 311 /* FIXME: Validate integrity, internal lists if necessary */ 312 } 313 314 /* Release the lock */ 315 RtlpDphLeaveCriticalSection(DphRoot); 316 } 317 318 NTSTATUS NTAPI 319 RtlpSecMemFreeVirtualMemory(HANDLE Process, PVOID *Base, PSIZE_T Size, ULONG Type) 320 { 321 NTSTATUS Status; 322 //PVOID *SavedBase = Base; 323 //PSIZE_T SavedSize = Size; 324 325 /* Free the memory */ 326 Status = ZwFreeVirtualMemory(Process, Base, Size, Type); 327 328 /* Flush secure memory cache if needed and retry freeing */ 329 #if 0 330 if (Status == STATUS_INVALID_PAGE_PROTECTION && 331 Process == NtCurrentProcess() && 332 RtlFlushSecureMemoryCache(*SavedBase, *SavedSize)) 333 { 334 Status = ZwFreeVirtualMemory(NtCurrentProcess(), SavedBase, SavedSize, Type); 335 } 336 #endif 337 338 return Status; 339 } 340 341 NTSTATUS NTAPI 342 RtlpDphAllocateVm(PVOID *Base, SIZE_T Size, ULONG Type, ULONG Protection) 343 { 344 NTSTATUS Status; 345 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 346 Base, 347 0, 348 &Size, 349 Type, 350 Protection); 351 DPRINT("Page heap: AllocVm (%p, %Ix, %lx) status %lx\n", Base, Size, Type, Status); 352 /* Check for failures */ 353 if (!NT_SUCCESS(Status)) 354 { 355 if (Type == MEM_RESERVE) 356 { 357 _InterlockedIncrement(&RtlpDphCounter); 358 if (RtlpDphBreakOptions & DPH_BREAK_ON_RESERVE_FAIL) 359 { 360 DPRINT1("Page heap: AllocVm (%p, %Ix, %lx) failed with %lx\n", Base, Size, Type, Status); 361 DbgBreakPoint(); 362 return Status; 363 } 364 } 365 else 366 { 367 _InterlockedIncrement(&RtlpDphAllocFails); 368 if (RtlpDphBreakOptions & DPH_BREAK_ON_COMMIT_FAIL) 369 { 370 DPRINT1("Page heap: AllocVm (%p, %Ix, %lx) failed with %lx\n", Base, Size, Type, Status); 371 DbgBreakPoint(); 372 return Status; 373 } 374 } 375 } 376 377 return Status; 378 } 379 380 NTSTATUS NTAPI 381 RtlpDphFreeVm(PVOID Base, SIZE_T Size, ULONG Type) 382 { 383 NTSTATUS Status; 384 385 /* Free the memory */ 386 Status = RtlpSecMemFreeVirtualMemory(NtCurrentProcess(), &Base, &Size, Type); 387 DPRINT("Page heap: FreeVm (%p, %Ix, %lx) status %lx\n", Base, Size, Type, Status); 388 /* Log/report failures */ 389 if (!NT_SUCCESS(Status)) 390 { 391 if (Type == MEM_RELEASE) 392 { 393 _InterlockedIncrement(&RtlpDphReleaseFails); 394 if (RtlpDphBreakOptions & DPH_BREAK_ON_RELEASE_FAIL) 395 { 396 DPRINT1("Page heap: FreeVm (%p, %Ix, %lx) failed with %lx\n", Base, Size, Type, Status); 397 DbgBreakPoint(); 398 return Status; 399 } 400 } 401 else 402 { 403 _InterlockedIncrement(&RtlpDphFreeFails); 404 if (RtlpDphBreakOptions & DPH_BREAK_ON_FREE_FAIL) 405 { 406 DPRINT1("Page heap: FreeVm (%p, %Ix, %lx) failed with %lx\n", Base, Size, Type, Status); 407 DbgBreakPoint(); 408 return Status; 409 } 410 } 411 } 412 413 return Status; 414 } 415 416 NTSTATUS NTAPI 417 RtlpDphProtectVm(PVOID Base, SIZE_T Size, ULONG Protection) 418 { 419 NTSTATUS Status; 420 ULONG OldProtection; 421 422 /* Change protection */ 423 Status = ZwProtectVirtualMemory(NtCurrentProcess(), &Base, &Size, Protection, &OldProtection); 424 425 /* Log/report failures */ 426 if (!NT_SUCCESS(Status)) 427 { 428 _InterlockedIncrement(&RtlpDphProtectFails); 429 if (RtlpDphBreakOptions & DPH_BREAK_ON_PROTECT_FAIL) 430 { 431 DPRINT1("Page heap: ProtectVm (%p, %Ix, %lx) failed with %lx\n", Base, Size, Protection, Status); 432 DbgBreakPoint(); 433 return Status; 434 } 435 } 436 437 return Status; 438 } 439 440 BOOLEAN NTAPI 441 RtlpDphWritePageHeapBlockInformation(PDPH_HEAP_ROOT DphRoot, PVOID UserAllocation, SIZE_T Size, SIZE_T UserSize) 442 { 443 PDPH_BLOCK_INFORMATION BlockInfo; 444 PUCHAR FillPtr; 445 446 /* Get pointer to the block info structure */ 447 BlockInfo = (PDPH_BLOCK_INFORMATION)UserAllocation - 1; 448 449 /* Set up basic fields */ 450 BlockInfo->Heap = DphRoot; 451 BlockInfo->ActualSize = UserSize; 452 BlockInfo->RequestedSize = Size; 453 BlockInfo->StartStamp = DPH_FILL_START_STAMP_1; 454 BlockInfo->EndStamp = DPH_FILL_END_STAMP_1; 455 456 /* Fill with a pattern */ 457 FillPtr = (PUCHAR)UserAllocation + Size; 458 RtlFillMemory(FillPtr, ROUND_UP(FillPtr, PAGE_SIZE) - (ULONG_PTR)FillPtr, DPH_FILL_SUFFIX); 459 460 /* FIXME: Check if logging stack traces is turned on */ 461 //if (DphRoot->ExtraFlags & 462 463 return TRUE; 464 } 465 466 VOID NTAPI 467 RtlpDphPlaceOnBusyList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK DphNode) 468 { 469 BOOLEAN NewElement; 470 PVOID AddressUserData; 471 472 DPRINT("RtlpDphPlaceOnBusyList(%p %p)\n", DphRoot, DphNode); 473 474 /* Add it to the AVL busy nodes table */ 475 DphRoot->NodeToAllocate = DphNode; 476 AddressUserData = RtlInsertElementGenericTableAvl(&DphRoot->BusyNodesTable, 477 &DphNode->pUserAllocation, 478 sizeof(ULONG_PTR), 479 &NewElement); 480 481 ASSERT(AddressUserData == &DphNode->pUserAllocation); 482 ASSERT(NewElement == TRUE); 483 484 /* Update heap counters */ 485 DphRoot->nBusyAllocations++; 486 DphRoot->nBusyAllocationBytesAccessible += DphNode->nVirtualAccessSize; 487 DphRoot->nBusyAllocationBytesCommitted += DphNode->nVirtualBlockSize; 488 } 489 490 VOID NTAPI 491 RtlpDphPlaceOnFreeList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK Node) 492 { 493 DPRINT("RtlpDphPlaceOnFreeList(%p %p)\n", DphRoot, Node); 494 495 /* Node is being added to the tail of the list */ 496 Node->pNextAlloc = NULL; 497 498 /* Add it to the tail of the linked list */ 499 if (DphRoot->pFreeAllocationListTail) 500 DphRoot->pFreeAllocationListTail->pNextAlloc = Node; 501 else 502 DphRoot->pFreeAllocationListHead = Node; 503 DphRoot->pFreeAllocationListTail = Node; 504 505 /* Update byte counts taking in account this new node */ 506 DphRoot->nFreeAllocations++; 507 DphRoot->nFreeAllocationBytesCommitted += Node->nVirtualBlockSize; 508 } 509 510 VOID NTAPI 511 RtlpDphPlaceOnPoolList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK Node) 512 { 513 DPRINT("RtlpDphPlaceOnPoolList(%p %p)\n", DphRoot, Node); 514 515 /* Node is being added to the tail of the list */ 516 Node->pNextAlloc = NULL; 517 518 /* Add it to the tail of the linked list */ 519 if (DphRoot->pNodePoolListTail) 520 DphRoot->pNodePoolListTail->pNextAlloc = Node; 521 else 522 DphRoot->pNodePoolListHead = Node; 523 DphRoot->pNodePoolListTail = Node; 524 525 /* Update byte counts taking in account this new node */ 526 DphRoot->nNodePools++; 527 DphRoot->nNodePoolBytes += Node->nVirtualBlockSize; 528 } 529 530 VOID NTAPI 531 RtlpDphPlaceOnVirtualList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK Node) 532 { 533 DPRINT("RtlpDphPlaceOnVirtualList(%p %p)\n", DphRoot, Node); 534 535 /* Add it to the head of the virtual list */ 536 Node->pNextAlloc = DphRoot->pVirtualStorageListHead; 537 if (!DphRoot->pVirtualStorageListHead) 538 DphRoot->pVirtualStorageListTail = Node; 539 DphRoot->pVirtualStorageListHead = Node; 540 541 /* Update byte counts taking in account this new node */ 542 DphRoot->nVirtualStorageRanges++; 543 DphRoot->nVirtualStorageBytes += Node->nVirtualBlockSize; 544 } 545 546 PDPH_HEAP_BLOCK NTAPI 547 RtlpDphTakeNodeFromUnusedList(PDPH_HEAP_ROOT DphRoot) 548 { 549 PDPH_HEAP_BLOCK Node = DphRoot->pUnusedNodeListHead; 550 PDPH_HEAP_BLOCK Next; 551 552 DPRINT("RtlpDphTakeNodeFromUnusedList(%p), ret %p\n", DphRoot, Node); 553 554 /* Take the first entry */ 555 if (!Node) return NULL; 556 557 /* Remove that entry (Node) from the list */ 558 Next = Node->pNextAlloc; 559 if (DphRoot->pUnusedNodeListHead == Node) DphRoot->pUnusedNodeListHead = Next; 560 if (DphRoot->pUnusedNodeListTail == Node) DphRoot->pUnusedNodeListTail = NULL; 561 562 /* Decrease amount of unused nodes */ 563 DphRoot->nUnusedNodes--; 564 565 return Node; 566 } 567 568 VOID NTAPI 569 RtlpDphReturnNodeToUnusedList(PDPH_HEAP_ROOT DphRoot, 570 PDPH_HEAP_BLOCK Node) 571 { 572 DPRINT("RtlpDphReturnNodeToUnusedList(%p, %p)\n", DphRoot, Node); 573 574 /* Add it back to the head of the unused list */ 575 Node->pNextAlloc = DphRoot->pUnusedNodeListHead; 576 if (!DphRoot->pUnusedNodeListHead) 577 DphRoot->pUnusedNodeListTail = Node; 578 DphRoot->pUnusedNodeListHead = Node; 579 580 /* Increase amount of unused nodes */ 581 DphRoot->nUnusedNodes++; 582 } 583 584 VOID NTAPI 585 RtlpDphRemoveFromAvailableList(PDPH_HEAP_ROOT DphRoot, 586 PDPH_HEAP_BLOCK Node) 587 { 588 /* Make sure Adjacency list pointers are biased */ 589 //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Flink)); 590 //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Blink)); 591 592 DPRINT("RtlpDphRemoveFromAvailableList(%p %p)\n", DphRoot, Node); 593 594 /* Check if it is in the list */ 595 #if 0 596 { 597 PLIST_ENTRY CurEntry; 598 PDPH_HEAP_BLOCK NodeEntry; 599 BOOLEAN Found = FALSE; 600 601 /* Find where to put this node according to its virtual address */ 602 CurEntry = DphRoot->AvailableAllocationHead.Flink; 603 604 while (CurEntry != &DphRoot->AvailableAllocationHead) 605 { 606 NodeEntry = CONTAINING_RECORD(CurEntry, DPH_HEAP_BLOCK, AvailableEntry); 607 608 if (NodeEntry == Node) 609 { 610 Found = TRUE; 611 break; 612 } 613 614 CurEntry = CurEntry->Flink; 615 } 616 617 if (!Found) 618 { 619 DPRINT1("Trying to remove non-existing in availlist node!\n"); 620 DbgBreakPoint(); 621 } 622 } 623 #endif 624 625 /* Remove it from the list */ 626 RemoveEntryList(&Node->AvailableEntry); 627 628 /* Decrease heap counters */ 629 DphRoot->nAvailableAllocations--; 630 DphRoot->nAvailableAllocationBytesCommitted -= Node->nVirtualBlockSize; 631 632 /* Remove bias from the AdjacencyEntry pointer */ 633 Node->AdjacencyEntry.Flink = (PLIST_ENTRY)POINTER_REMOVE_BIAS(Node->AdjacencyEntry.Flink); 634 Node->AdjacencyEntry.Blink = (PLIST_ENTRY)POINTER_REMOVE_BIAS(Node->AdjacencyEntry.Blink); 635 } 636 637 VOID NTAPI 638 RtlpDphRemoveFromBusyList(PDPH_HEAP_ROOT DphRoot, 639 PDPH_HEAP_BLOCK Node) 640 { 641 BOOLEAN ElementPresent; 642 643 DPRINT("RtlpDphRemoveFromBusyList(%p %p)\n", DphRoot, Node); 644 645 /* Delete it from busy nodes table */ 646 ElementPresent = RtlDeleteElementGenericTableAvl(&DphRoot->BusyNodesTable, &Node->pUserAllocation); 647 ASSERT(ElementPresent == TRUE); 648 649 /* Update counters */ 650 DphRoot->nBusyAllocations--; 651 DphRoot->nBusyAllocationBytesCommitted -= Node->nVirtualBlockSize; 652 DphRoot->nBusyAllocationBytesAccessible -= Node->nVirtualAccessSize; 653 } 654 655 VOID NTAPI 656 RtlpDphRemoveFromFreeList(PDPH_HEAP_ROOT DphRoot, 657 PDPH_HEAP_BLOCK Node, 658 PDPH_HEAP_BLOCK Prev) 659 { 660 PDPH_HEAP_BLOCK Next; 661 662 DPRINT("RtlpDphRemoveFromFreeList(%p %p %p)\n", DphRoot, Node, Prev); 663 664 /* Detach it from the list */ 665 Next = Node->pNextAlloc; 666 if (DphRoot->pFreeAllocationListHead == Node) 667 DphRoot->pFreeAllocationListHead = Next; 668 if (DphRoot->pFreeAllocationListTail == Node) 669 DphRoot->pFreeAllocationListTail = Prev; 670 if (Prev) Prev->pNextAlloc = Next; 671 672 /* Decrease heap counters */ 673 DphRoot->nFreeAllocations--; 674 DphRoot->nFreeAllocationBytesCommitted -= Node->nVirtualBlockSize; 675 676 Node->StackTrace = NULL; 677 } 678 679 VOID NTAPI 680 RtlpDphCoalesceNodeIntoAvailable(PDPH_HEAP_ROOT DphRoot, 681 PDPH_HEAP_BLOCK Node) 682 { 683 PDPH_HEAP_BLOCK NodeEntry, PrevNode = NULL, NextNode; 684 PLIST_ENTRY AvailListHead; 685 PLIST_ENTRY CurEntry; 686 687 DPRINT("RtlpDphCoalesceNodeIntoAvailable(%p %p)\n", DphRoot, Node); 688 689 /* Update heap counters */ 690 DphRoot->nAvailableAllocationBytesCommitted += Node->nVirtualBlockSize; 691 DphRoot->nAvailableAllocations++; 692 693 /* Find where to put this node according to its virtual address */ 694 AvailListHead = &DphRoot->AvailableAllocationHead; 695 696 /* Find a point where to insert an available node */ 697 CurEntry = AvailListHead->Flink; 698 699 while (CurEntry != AvailListHead) 700 { 701 NodeEntry = CONTAINING_RECORD(CurEntry, DPH_HEAP_BLOCK, AvailableEntry); 702 if (NodeEntry->pVirtualBlock >= Node->pVirtualBlock) 703 { 704 PrevNode = NodeEntry; 705 break; 706 } 707 CurEntry = CurEntry->Flink; 708 } 709 710 if (!PrevNode) 711 { 712 /* That means either this list is empty, or we should add to the head of it */ 713 InsertHeadList(AvailListHead, &Node->AvailableEntry); 714 } 715 else 716 { 717 /* Check the previous node and merge if possible */ 718 if (PrevNode->pVirtualBlock + PrevNode->nVirtualBlockSize == Node->pVirtualBlock) 719 { 720 /* Check they actually belong to the same virtual memory block */ 721 NTSTATUS Status; 722 MEMORY_BASIC_INFORMATION MemoryBasicInfo; 723 724 Status = ZwQueryVirtualMemory( 725 ZwCurrentProcess(), 726 Node->pVirtualBlock, 727 MemoryBasicInformation, 728 &MemoryBasicInfo, 729 sizeof(MemoryBasicInfo), 730 NULL); 731 732 /* There is no way this can fail, we committed this memory! */ 733 ASSERT(NT_SUCCESS(Status)); 734 735 if ((PUCHAR)MemoryBasicInfo.AllocationBase <= PrevNode->pVirtualBlock) 736 { 737 /* They are adjacent, and from the same VM region. - merge! */ 738 PrevNode->nVirtualBlockSize += Node->nVirtualBlockSize; 739 RtlpDphReturnNodeToUnusedList(DphRoot, Node); 740 DphRoot->nAvailableAllocations--; 741 742 Node = PrevNode; 743 } 744 else 745 { 746 /* Insert after PrevNode */ 747 InsertTailList(&PrevNode->AvailableEntry, &Node->AvailableEntry); 748 } 749 } 750 else 751 { 752 /* Insert after PrevNode */ 753 InsertTailList(&PrevNode->AvailableEntry, &Node->AvailableEntry); 754 } 755 756 /* Now check the next entry after our one */ 757 if (Node->AvailableEntry.Flink != AvailListHead) 758 { 759 NextNode = CONTAINING_RECORD(Node->AvailableEntry.Flink, DPH_HEAP_BLOCK, AvailableEntry); 760 /* Node is not at the tail of the list, check if it's adjacent */ 761 if (Node->pVirtualBlock + Node->nVirtualBlockSize == NextNode->pVirtualBlock) 762 { 763 /* Check they actually belong to the same virtual memory block */ 764 NTSTATUS Status; 765 MEMORY_BASIC_INFORMATION MemoryBasicInfo; 766 767 Status = ZwQueryVirtualMemory( 768 ZwCurrentProcess(), 769 NextNode->pVirtualBlock, 770 MemoryBasicInformation, 771 &MemoryBasicInfo, 772 sizeof(MemoryBasicInfo), 773 NULL); 774 775 /* There is no way this can fail, we committed this memory! */ 776 ASSERT(NT_SUCCESS(Status)); 777 778 if ((PUCHAR)MemoryBasicInfo.AllocationBase <= Node->pVirtualBlock) 779 { 780 /* They are adjacent - merge! */ 781 Node->nVirtualBlockSize += NextNode->nVirtualBlockSize; 782 783 /* Remove next entry from the list and put it into unused entries list */ 784 RemoveEntryList(&NextNode->AvailableEntry); 785 RtlpDphReturnNodeToUnusedList(DphRoot, NextNode); 786 DphRoot->nAvailableAllocations--; 787 } 788 } 789 } 790 } 791 } 792 793 VOID NTAPI 794 RtlpDphCoalesceFreeIntoAvailable(PDPH_HEAP_ROOT DphRoot, 795 ULONG LeaveOnFreeList) 796 { 797 PDPH_HEAP_BLOCK Node = DphRoot->pFreeAllocationListHead, Next; 798 SIZE_T FreeAllocations = DphRoot->nFreeAllocations; 799 800 /* Make sure requested size is not too big */ 801 ASSERT(FreeAllocations >= LeaveOnFreeList); 802 803 DPRINT("RtlpDphCoalesceFreeIntoAvailable(%p %lu)\n", DphRoot, LeaveOnFreeList); 804 805 while (Node) 806 { 807 FreeAllocations--; 808 if (FreeAllocations < LeaveOnFreeList) break; 809 810 /* Get the next pointer, because it may be changed after following two calls */ 811 Next = Node->pNextAlloc; 812 813 /* Remove it from the free list */ 814 RtlpDphRemoveFromFreeList(DphRoot, Node, NULL); 815 816 /* And put into the available */ 817 RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node); 818 819 /* Go to the next node */ 820 Node = Next; 821 } 822 } 823 824 VOID NTAPI 825 RtlpDphAddNewPool(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK NodeBlock, PVOID Virtual, SIZE_T Size, BOOLEAN PlaceOnPool) 826 { 827 PDPH_HEAP_BLOCK DphNode, DphStartNode; 828 ULONG NodeCount, i; 829 830 //NodeCount = (Size >> 6) - 1; 831 NodeCount = (ULONG)(Size / sizeof(DPH_HEAP_BLOCK)); 832 DphStartNode = Virtual; 833 834 /* Set pNextAlloc for all blocks */ 835 for (DphNode = Virtual, i=NodeCount-1; i > 0; i--) 836 { 837 DphNode->pNextAlloc = DphNode + 1; 838 DphNode = DphNode->pNextAlloc; 839 } 840 841 /* and the last one */ 842 DphNode->pNextAlloc = NULL; 843 844 /* Add it to the tail of unused node list */ 845 if (DphRoot->pUnusedNodeListTail) 846 DphRoot->pUnusedNodeListTail->pNextAlloc = DphStartNode; 847 else 848 DphRoot->pUnusedNodeListHead = DphStartNode; 849 850 DphRoot->pUnusedNodeListTail = DphNode; 851 852 /* Increase counters */ 853 DphRoot->nUnusedNodes += NodeCount; 854 855 /* Check if we need to place it on the pool list */ 856 if (PlaceOnPool) 857 { 858 /* Get a node from the unused list */ 859 DphNode = RtlpDphTakeNodeFromUnusedList(DphRoot); 860 ASSERT(DphNode); 861 862 /* Set its virtual block values */ 863 DphNode->pVirtualBlock = Virtual; 864 DphNode->nVirtualBlockSize = Size; 865 866 /* Place it on the pool list */ 867 RtlpDphPlaceOnPoolList(DphRoot, DphNode); 868 } 869 } 870 871 PDPH_HEAP_BLOCK NTAPI 872 RtlpDphSearchAvailableMemoryListForBestFit(PDPH_HEAP_ROOT DphRoot, 873 SIZE_T Size) 874 { 875 PLIST_ENTRY CurEntry; 876 PDPH_HEAP_BLOCK Node, NodeFound = NULL; 877 878 CurEntry = DphRoot->AvailableAllocationHead.Flink; 879 880 while (CurEntry != &DphRoot->AvailableAllocationHead) 881 { 882 /* Get the current available node */ 883 Node = CONTAINING_RECORD(CurEntry, DPH_HEAP_BLOCK, AvailableEntry); 884 885 /* Check its size */ 886 if (Node->nVirtualBlockSize >= Size) 887 { 888 NodeFound = Node; 889 break; 890 } 891 892 /* Move to the next available entry */ 893 CurEntry = CurEntry->Flink; 894 } 895 896 /* Make sure Adjacency list pointers are biased */ 897 //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Flink)); 898 //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Blink)); 899 900 return NodeFound; 901 } 902 903 PDPH_HEAP_BLOCK NTAPI 904 RtlpDphFindAvailableMemory(PDPH_HEAP_ROOT DphRoot, 905 SIZE_T Size, 906 BOOLEAN Grow) 907 { 908 PDPH_HEAP_BLOCK Node; 909 ULONG NewSize; 910 911 /* Find an available best fitting node */ 912 Node = RtlpDphSearchAvailableMemoryListForBestFit(DphRoot, Size); 913 914 /* If that didn't work, try to search a smaller one in the loop */ 915 while (!Node) 916 { 917 /* Break if the free list becomes too small */ 918 if (DphRoot->nFreeAllocations <= DPH_FREE_LIST_MINIMUM) break; 919 920 /* Calculate a new free list size */ 921 NewSize = DphRoot->nFreeAllocations >> 2; 922 if (NewSize < DPH_FREE_LIST_MINIMUM) NewSize = DPH_FREE_LIST_MINIMUM; 923 924 /* Coalesce free into available */ 925 RtlpDphCoalesceFreeIntoAvailable(DphRoot, NewSize); 926 927 /* Try to find an available best fitting node again */ 928 Node = RtlpDphSearchAvailableMemoryListForBestFit(DphRoot, Size); 929 } 930 931 /* If Node is NULL, then we could fix the situation only by 932 growing the available VM size */ 933 if (!Node && Grow) 934 { 935 /* Grow VM size, if it fails - return failure directly */ 936 if (!RtlpDphGrowVirtual(DphRoot, Size)) return NULL; 937 938 /* Try to find an available best fitting node again */ 939 Node = RtlpDphSearchAvailableMemoryListForBestFit(DphRoot, Size); 940 941 if (!Node) 942 { 943 /* Do the last attempt: coalesce all free into available (if Size fits there) */ 944 if (DphRoot->nFreeAllocationBytesCommitted + DphRoot->nAvailableAllocationBytesCommitted >= Size) 945 { 946 /* Coalesce free into available */ 947 RtlpDphCoalesceFreeIntoAvailable(DphRoot, 0); 948 949 /* Try to find an available best fitting node again */ 950 Node = RtlpDphSearchAvailableMemoryListForBestFit(DphRoot, Size); 951 } 952 } 953 } 954 955 /* Return node we found */ 956 return Node; 957 } 958 959 PDPH_HEAP_BLOCK NTAPI 960 RtlpDphFindBusyMemory(PDPH_HEAP_ROOT DphRoot, 961 PVOID pUserMem) 962 { 963 PDPH_HEAP_BLOCK Node; 964 PVOID Ptr; 965 966 /* Lookup busy block in AVL */ 967 Ptr = RtlLookupElementGenericTableAvl(&DphRoot->BusyNodesTable, &pUserMem); 968 if (!Ptr) return NULL; 969 970 /* Restore pointer to the heap block */ 971 Node = CONTAINING_RECORD(Ptr, DPH_HEAP_BLOCK, pUserAllocation); 972 ASSERT(Node->pUserAllocation == pUserMem); 973 return Node; 974 } 975 976 NTSTATUS NTAPI 977 RtlpDphSetProtectionBeforeUse(PDPH_HEAP_ROOT DphRoot, PUCHAR VirtualBlock, ULONG UserSize) 978 { 979 ULONG Protection; 980 PVOID Base; 981 982 if (DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN) 983 { 984 Base = VirtualBlock + PAGE_SIZE; 985 } 986 else 987 { 988 Base = VirtualBlock; 989 } 990 991 // FIXME: It should be different, but for now it's fine 992 Protection = PAGE_READWRITE; 993 994 return RtlpDphProtectVm(Base, UserSize, Protection); 995 } 996 997 NTSTATUS NTAPI 998 RtlpDphSetProtectionAfterUse(PDPH_HEAP_ROOT DphRoot, /*PUCHAR VirtualBlock*/PDPH_HEAP_BLOCK Node) 999 { 1000 ASSERT((Node->nVirtualAccessSize + PAGE_SIZE) <= Node->nVirtualBlockSize); 1001 1002 // FIXME: Bring stuff here 1003 if (DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN) 1004 { 1005 } 1006 else 1007 { 1008 } 1009 1010 return STATUS_SUCCESS; 1011 } 1012 1013 PDPH_HEAP_BLOCK NTAPI 1014 RtlpDphAllocateNode(PDPH_HEAP_ROOT DphRoot) 1015 { 1016 PDPH_HEAP_BLOCK Node; 1017 NTSTATUS Status; 1018 SIZE_T Size = DPH_POOL_SIZE, SizeVirtual; 1019 PVOID Ptr = NULL; 1020 1021 /* Check for the easy case */ 1022 if (DphRoot->pUnusedNodeListHead) 1023 { 1024 /* Just take a node from this list */ 1025 Node = RtlpDphTakeNodeFromUnusedList(DphRoot); 1026 ASSERT(Node); 1027 return Node; 1028 } 1029 1030 /* There is a need to make free space */ 1031 Node = RtlpDphFindAvailableMemory(DphRoot, DPH_POOL_SIZE, FALSE); 1032 1033 if (!DphRoot->pUnusedNodeListHead && !Node) 1034 { 1035 /* Retry with a smaller request */ 1036 Size = PAGE_SIZE; 1037 Node = RtlpDphFindAvailableMemory(DphRoot, PAGE_SIZE, FALSE); 1038 } 1039 1040 if (!DphRoot->pUnusedNodeListHead) 1041 { 1042 if (Node) 1043 { 1044 RtlpDphRemoveFromAvailableList(DphRoot, Node); 1045 Ptr = Node->pVirtualBlock; 1046 SizeVirtual = Node->nVirtualBlockSize; 1047 } 1048 else 1049 { 1050 /* No free space, need to alloc a new VM block */ 1051 Size = DPH_POOL_SIZE; 1052 SizeVirtual = DPH_RESERVE_SIZE; 1053 Status = RtlpDphAllocateVm(&Ptr, SizeVirtual, MEM_COMMIT, PAGE_NOACCESS); 1054 1055 if (!NT_SUCCESS(Status)) 1056 { 1057 /* Retry with a smaller size */ 1058 SizeVirtual = 0x10000; 1059 Status = RtlpDphAllocateVm(&Ptr, SizeVirtual, MEM_COMMIT, PAGE_NOACCESS); 1060 if (!NT_SUCCESS(Status)) return NULL; 1061 } 1062 } 1063 1064 /* VM is allocated at this point, set protection */ 1065 Status = RtlpDphProtectVm(Ptr, Size, PAGE_READWRITE); 1066 if (!NT_SUCCESS(Status)) 1067 { 1068 if (Node) 1069 { 1070 RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node); 1071 } 1072 else 1073 { 1074 //RtlpDphFreeVm(); 1075 ASSERT(FALSE); 1076 } 1077 1078 return NULL; 1079 } 1080 1081 /* Zero the memory */ 1082 if (Node) RtlZeroMemory(Ptr, Size); 1083 1084 /* Add a new pool based on this VM */ 1085 RtlpDphAddNewPool(DphRoot, Node, Ptr, Size, TRUE); 1086 1087 if (Node) 1088 { 1089 if (Node->nVirtualBlockSize > Size) 1090 { 1091 Node->pVirtualBlock += Size; 1092 Node->nVirtualBlockSize -= Size; 1093 1094 RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node); 1095 } 1096 else 1097 { 1098 RtlpDphReturnNodeToUnusedList(DphRoot, Node); 1099 } 1100 } 1101 else 1102 { 1103 /* The new VM block was just allocated a few code lines ago, 1104 so initialize it */ 1105 Node = RtlpDphTakeNodeFromUnusedList(DphRoot); 1106 Node->pVirtualBlock = Ptr; 1107 Node->nVirtualBlockSize = SizeVirtual; 1108 RtlpDphPlaceOnVirtualList(DphRoot, Node); 1109 1110 Node = RtlpDphTakeNodeFromUnusedList(DphRoot); 1111 Node->pVirtualBlock = (PUCHAR)Ptr + Size; 1112 Node->nVirtualBlockSize = SizeVirtual - Size; 1113 RtlpDphPlaceOnVirtualList(DphRoot, Node); 1114 1115 /* Coalesce them into available list */ 1116 RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node); 1117 } 1118 } 1119 1120 return RtlpDphTakeNodeFromUnusedList(DphRoot); 1121 } 1122 1123 BOOLEAN NTAPI 1124 RtlpDphGrowVirtual(PDPH_HEAP_ROOT DphRoot, 1125 SIZE_T Size) 1126 { 1127 PDPH_HEAP_BLOCK Node, AvailableNode; 1128 PVOID Base = NULL; 1129 SIZE_T VirtualSize; 1130 NTSTATUS Status; 1131 1132 /* Start with allocating a couple of nodes */ 1133 Node = RtlpDphAllocateNode(DphRoot); 1134 if (!Node) return FALSE; 1135 1136 AvailableNode = RtlpDphAllocateNode(DphRoot); 1137 if (!AvailableNode) 1138 { 1139 /* Free the allocated node and return failure */ 1140 RtlpDphReturnNodeToUnusedList(DphRoot, Node); 1141 return FALSE; 1142 } 1143 1144 /* Calculate size of VM to allocate by rounding it up */ 1145 Size = ROUND_UP(Size, 0xFFFF); 1146 VirtualSize = Size; 1147 if (Size < DPH_RESERVE_SIZE) 1148 VirtualSize = DPH_RESERVE_SIZE; 1149 1150 /* Allocate the virtual memory */ 1151 // FIXME: Shouldn't it be MEM_RESERVE with later committing? 1152 Status = RtlpDphAllocateVm(&Base, VirtualSize, MEM_COMMIT, PAGE_NOACCESS); 1153 if (!NT_SUCCESS(Status)) 1154 { 1155 /* Retry again with a smaller size */ 1156 VirtualSize = Size; 1157 Status = RtlpDphAllocateVm(&Base, VirtualSize, MEM_COMMIT, PAGE_NOACCESS); 1158 if (!NT_SUCCESS(Status)) 1159 { 1160 /* Free the allocated node and return failure */ 1161 RtlpDphReturnNodeToUnusedList(DphRoot, Node); 1162 RtlpDphReturnNodeToUnusedList(DphRoot, AvailableNode); 1163 return FALSE; 1164 } 1165 } 1166 1167 /* Set up our two nodes describing this VM */ 1168 Node->pVirtualBlock = Base; 1169 Node->nVirtualBlockSize = VirtualSize; 1170 AvailableNode->pVirtualBlock = Base; 1171 AvailableNode->nVirtualBlockSize = VirtualSize; 1172 1173 /* Add them to virtual and available lists respectively */ 1174 RtlpDphPlaceOnVirtualList(DphRoot, Node); 1175 RtlpDphCoalesceNodeIntoAvailable(DphRoot, AvailableNode); 1176 1177 /* Return success */ 1178 return TRUE; 1179 } 1180 1181 RTL_GENERIC_COMPARE_RESULTS 1182 NTAPI 1183 RtlpDphCompareNodeForTable(IN PRTL_AVL_TABLE Table, 1184 IN PVOID FirstStruct, 1185 IN PVOID SecondStruct) 1186 { 1187 ULONG_PTR FirstBlock, SecondBlock; 1188 1189 FirstBlock = *((ULONG_PTR *)FirstStruct); 1190 SecondBlock = *((ULONG_PTR *)SecondStruct); 1191 1192 if (FirstBlock < SecondBlock) 1193 return GenericLessThan; 1194 else if (FirstBlock > SecondBlock) 1195 return GenericGreaterThan; 1196 1197 return GenericEqual; 1198 } 1199 1200 PVOID 1201 NTAPI 1202 RtlpDphAllocateNodeForTable(IN PRTL_AVL_TABLE Table, 1203 IN CLONG ByteSize) 1204 { 1205 PDPH_HEAP_BLOCK pBlock; 1206 PDPH_HEAP_ROOT DphRoot; 1207 1208 /* This mega-assert comes from a text search over Windows 2003 checked binary of ntdll.dll */ 1209 ASSERT((ULONG_PTR)(((PRTL_BALANCED_LINKS)0)+1) + sizeof(PUCHAR) == ByteSize); 1210 1211 /* Get pointer to the containing heap root record */ 1212 DphRoot = CONTAINING_RECORD(Table, DPH_HEAP_ROOT, BusyNodesTable); 1213 pBlock = DphRoot->NodeToAllocate; 1214 1215 DphRoot->NodeToAllocate = NULL; 1216 ASSERT(pBlock); 1217 1218 return &(pBlock->TableLinks); 1219 } 1220 1221 VOID 1222 NTAPI 1223 RtlpDphFreeNodeForTable(IN PRTL_AVL_TABLE Table, 1224 IN PVOID Buffer) 1225 { 1226 /* Nothing */ 1227 } 1228 1229 NTSTATUS NTAPI 1230 RtlpDphInitializeDelayedFreeQueue(VOID) 1231 { 1232 NTSTATUS Status; 1233 1234 Status = RtlInitializeHeapLock(&RtlpDphDelayedFreeQueueLock); 1235 if (!NT_SUCCESS(Status)) 1236 { 1237 // TODO: Log this error! 1238 DPRINT1("Failure initializing delayed free queue critical section\n"); 1239 return Status; 1240 } 1241 1242 /* Initialize lists */ 1243 InitializeListHead(&RtlpDphDelayedFreeQueue); 1244 RtlInitializeSListHead(&RtlpDphDelayedTemporaryPushList); 1245 1246 /* Reset counters */ 1247 RtlpDphMemoryUsedByDelayedFreeBlocks = 0; 1248 RtlpDphNumberOfDelayedFreeBlocks = 0; 1249 1250 return Status; 1251 } 1252 1253 VOID NTAPI 1254 RtlpDphFreeDelayedBlocksFromHeap(PDPH_HEAP_ROOT DphRoot, 1255 PHEAP NormalHeap) 1256 { 1257 PLIST_ENTRY Current, Next; 1258 PDPH_BLOCK_INFORMATION BlockInfo; 1259 ULONG ValidationInfo; 1260 1261 /* The original routine seems to use a temporary SList to put blocks to be freed, 1262 then it releases the lock and frees the blocks. But let's make it simple for now */ 1263 1264 /* Acquire the delayed free queue lock */ 1265 RtlEnterHeapLock(RtlpDphDelayedFreeQueueLock, TRUE); 1266 1267 /* Traverse the list */ 1268 Current = RtlpDphDelayedFreeQueue.Flink; 1269 while (Current != &RtlpDphDelayedFreeQueue) 1270 { 1271 /* Get the next entry pointer */ 1272 Next = Current->Flink; 1273 1274 BlockInfo = CONTAINING_RECORD(Current, DPH_BLOCK_INFORMATION, FreeQueue); 1275 1276 /* Check if it belongs to the same heap */ 1277 if (BlockInfo->Heap == DphRoot) 1278 { 1279 /* Remove it from the list */ 1280 RemoveEntryList(Current); 1281 1282 /* Reset its heap to NULL */ 1283 BlockInfo->Heap = NULL; 1284 1285 if (!RtlpDphIsNormalFreeHeapBlock(BlockInfo + 1, &ValidationInfo, TRUE)) 1286 { 1287 RtlpDphReportCorruptedBlock(DphRoot, 10, BlockInfo + 1, ValidationInfo); 1288 } 1289 1290 /* Decrement counters */ 1291 RtlpDphMemoryUsedByDelayedFreeBlocks -= BlockInfo->ActualSize; 1292 RtlpDphNumberOfDelayedFreeBlocks--; 1293 1294 /* Free the normal heap */ 1295 RtlFreeHeap(NormalHeap, 0, BlockInfo); 1296 } 1297 1298 /* Move to the next one */ 1299 Current = Next; 1300 } 1301 1302 /* Release the delayed free queue lock */ 1303 RtlLeaveHeapLock(RtlpDphDelayedFreeQueueLock); 1304 } 1305 1306 NTSTATUS NTAPI 1307 RtlpDphTargetDllsLogicInitialize(VOID) 1308 { 1309 UNIMPLEMENTED; 1310 return STATUS_SUCCESS; 1311 } 1312 1313 VOID NTAPI 1314 RtlpDphInternalValidatePageHeap(PDPH_HEAP_ROOT DphRoot, PVOID Address, ULONG Value) 1315 { 1316 UNIMPLEMENTED; 1317 } 1318 1319 VOID NTAPI 1320 RtlpDphVerifyIntegrity(PDPH_HEAP_ROOT DphRoot) 1321 { 1322 UNIMPLEMENTED; 1323 } 1324 1325 VOID NTAPI 1326 RtlpDphReportCorruptedBlock( 1327 _In_ PDPH_HEAP_ROOT DphRoot, 1328 _In_ ULONG Reserved, 1329 _In_ PVOID Block, 1330 _In_ ULONG ValidationInfo) 1331 { 1332 PVOID Size = (PVOID)(ULONG_PTR)RtlpDphGetBlockSizeFromCorruptedBlock(Block); 1333 DPH_BLOCK_INFORMATION SafeInfo = {0}; 1334 1335 DPRINT1("Corrupted heap block %p\n", Block); 1336 1337 _SEH2_TRY 1338 { 1339 PDPH_BLOCK_INFORMATION BlockInfo = (PDPH_BLOCK_INFORMATION)Block - 1; 1340 RtlCopyMemory(&SafeInfo, BlockInfo, sizeof(SafeInfo)); 1341 } 1342 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1343 { 1344 DPRINT1("ERROR: Could not read DPH_BLOCK_INFORMATION\n"); 1345 RtlZeroMemory(&SafeInfo, sizeof(SafeInfo)); 1346 } 1347 _SEH2_END; 1348 1349 if (ValidationInfo & DPH_VALINFO_CORRUPTED_AFTER_FREE) 1350 { 1351 RtlApplicationVerifierStop( 1352 APPLICATION_VERIFIER_CORRUPTED_HEAP_BLOCK_AFTER_FREE, "block corrupted after having been freed", 1353 RtlpDphHeapFromPointer(DphRoot), "Heap handle", Block, "Heap block", (PVOID)Size, "Block size", 0, ""); 1354 } 1355 1356 if (ValidationInfo & DPH_VALINFO_ALREADY_FREED) 1357 { 1358 RtlApplicationVerifierStop( 1359 APPLICATION_VERIFIER_DOUBLE_FREE, "block already freed", RtlpDphHeapFromPointer(DphRoot), "Heap handle", 1360 Block, "Heap block", Size, "Block size", 0, ""); 1361 } 1362 1363 if (ValidationInfo & DPH_VALINFO_BAD_INFIX_PATTERN) 1364 { 1365 RtlApplicationVerifierStop( 1366 APPLICATION_VERIFIER_CORRUPTED_INFIX_PATTERN, "corrupted infix pattern for freed block", 1367 RtlpDphHeapFromPointer(DphRoot), "Heap handle", Block, "Heap block", Size, "Block size", 0, ""); 1368 } 1369 1370 if (ValidationInfo & DPH_VALINFO_BAD_POINTER) 1371 { 1372 RtlApplicationVerifierStop( 1373 APPLICATION_VERIFIER_CORRUPT_HEAP_POINTER, "corrupted heap pointer or using wrong heap", 1374 RtlpDphHeapFromPointer(DphRoot), "Heap handle used", Block, "Heap block", Size, "Block size", 1375 SafeInfo.Heap, "Actual heap handle"); 1376 } 1377 1378 if (ValidationInfo & DPH_VALINFO_BAD_SUFFIX_PATTERN) 1379 { 1380 RtlApplicationVerifierStop( 1381 APPLICATION_VERIFIER_CORRUPTED_SUFFIX_PATTERN, "corrupted suffix pattern", RtlpDphHeapFromPointer(DphRoot), 1382 "Heap handle used", Block, "Heap block", Size, "Block size", 0, ""); 1383 } 1384 1385 if (ValidationInfo & DPH_VALINFO_BAD_PREFIX_PATTERN) 1386 { 1387 RtlApplicationVerifierStop( 1388 APPLICATION_VERIFIER_CORRUPTED_PREFIX_PATTERN, "corrupted prefix pattern", RtlpDphHeapFromPointer(DphRoot), 1389 "Heap handle used", Block, "Heap block", Size, "Block size", 0, ""); 1390 } 1391 1392 if (ValidationInfo & DPH_VALINFO_BAD_START_STAMP) 1393 { 1394 RtlApplicationVerifierStop( 1395 APPLICATION_VERIFIER_CORRUPTED_START_STAMP, "corrupted start stamp", RtlpDphHeapFromPointer(DphRoot), 1396 "Heap handle used", Block, "Heap block", Size, "Block size", (PVOID)(ULONG_PTR)SafeInfo.StartStamp, 1397 "Corrupted start stamp"); 1398 } 1399 1400 if (ValidationInfo & DPH_VALINFO_BAD_END_STAMP) 1401 { 1402 RtlApplicationVerifierStop( 1403 APPLICATION_VERIFIER_CORRUPTED_END_STAMP, "corrupted end stamp", RtlpDphHeapFromPointer(DphRoot), 1404 "Heap handle used", Block, "Heap block", Size, "Block size", (PVOID)(ULONG_PTR)SafeInfo.EndStamp, 1405 "Corrupted end stamp"); 1406 } 1407 1408 if (ValidationInfo & DPH_VALINFO_EXCEPTION) 1409 { 1410 RtlApplicationVerifierStop( 1411 APPLICATION_VERIFIER_EXCEPTION_WHILE_VERIFYING_BLOCK_HEADER, "exception raised while verifying block", 1412 RtlpDphHeapFromPointer(DphRoot), "Heap handle used", Block, "Heap block", Size, "Block size", 0, ""); 1413 } 1414 } 1415 1416 BOOLEAN NTAPI 1417 RtlpDphIsPageHeapBlock(PDPH_HEAP_ROOT DphRoot, 1418 PVOID Block, 1419 PULONG ValidationInformation, 1420 BOOLEAN CheckFillers) 1421 { 1422 PDPH_BLOCK_INFORMATION BlockInfo; 1423 BOOLEAN SomethingWrong = FALSE; 1424 PUCHAR Byte, Start, End; 1425 1426 ASSERT(ValidationInformation != NULL); 1427 *ValidationInformation = 0; 1428 1429 // _SEH2_TRY { 1430 BlockInfo = (PDPH_BLOCK_INFORMATION)Block - 1; 1431 1432 /* Check stamps */ 1433 if (BlockInfo->StartStamp != DPH_FILL_START_STAMP_1) 1434 { 1435 *ValidationInformation |= DPH_VALINFO_BAD_START_STAMP; 1436 SomethingWrong = TRUE; 1437 1438 /* Check if it has an alloc/free mismatch */ 1439 if (BlockInfo->StartStamp == DPH_FILL_START_STAMP_2) 1440 { 1441 /* Notify respectively */ 1442 *ValidationInformation = 0x101; 1443 } 1444 } 1445 1446 if (BlockInfo->EndStamp != DPH_FILL_END_STAMP_1) 1447 { 1448 *ValidationInformation |= DPH_VALINFO_BAD_END_STAMP; 1449 SomethingWrong = TRUE; 1450 } 1451 1452 /* Check root heap pointer */ 1453 if (BlockInfo->Heap != DphRoot) 1454 { 1455 *ValidationInformation |= DPH_VALINFO_BAD_POINTER; 1456 SomethingWrong = TRUE; 1457 } 1458 1459 /* Check other fillers if requested */ 1460 if (CheckFillers) 1461 { 1462 /* Check space after the block */ 1463 Start = (PUCHAR)Block + BlockInfo->RequestedSize; 1464 End = (PUCHAR)ROUND_UP(Start, PAGE_SIZE); 1465 for (Byte = Start; Byte < End; Byte++) 1466 { 1467 if (*Byte != DPH_FILL_SUFFIX) 1468 { 1469 *ValidationInformation |= DPH_VALINFO_BAD_SUFFIX_PATTERN; 1470 SomethingWrong = TRUE; 1471 break; 1472 } 1473 } 1474 } 1475 1476 return (SomethingWrong == FALSE); 1477 } 1478 1479 BOOLEAN NTAPI 1480 RtlpDphIsNormalFreeHeapBlock(PVOID Block, 1481 PULONG ValidationInformation, 1482 BOOLEAN CheckFillers) 1483 { 1484 ASSERT(ValidationInformation != NULL); 1485 1486 UNIMPLEMENTED; 1487 *ValidationInformation = 0; 1488 return TRUE; 1489 } 1490 1491 NTSTATUS NTAPI 1492 RtlpDphProcessStartupInitialization(VOID) 1493 { 1494 NTSTATUS Status; 1495 PTEB Teb = NtCurrentTeb(); 1496 1497 /* Initialize the DPH heap list and its critical section */ 1498 InitializeListHead(&RtlpDphPageHeapList); 1499 Status = RtlInitializeHeapLock(&RtlpDphPageHeapListLock); 1500 if (!NT_SUCCESS(Status)) 1501 { 1502 ASSERT(FALSE); 1503 return Status; 1504 } 1505 1506 /* Initialize delayed-free queue */ 1507 Status = RtlpDphInitializeDelayedFreeQueue(); 1508 if (!NT_SUCCESS(Status)) return Status; 1509 1510 /* Initialize the target dlls string */ 1511 RtlInitUnicodeString(&RtlpDphTargetDllsUnicode, RtlpDphTargetDlls); 1512 Status = RtlpDphTargetDllsLogicInitialize(); 1513 1514 /* Per-process DPH init is done */ 1515 RtlpDphPageHeapListInitialized = TRUE; 1516 1517 DPRINT1("Page heap: pid 0x%p: page heap enabled with flags 0x%X.\n", 1518 Teb->ClientId.UniqueProcess, RtlpDphGlobalFlags); 1519 1520 return Status; 1521 } 1522 1523 BOOLEAN NTAPI 1524 RtlpDphShouldAllocateInPageHeap(PDPH_HEAP_ROOT DphRoot, 1525 SIZE_T Size) 1526 { 1527 //UNIMPLEMENTED; 1528 /* Always use page heap for now */ 1529 return TRUE; 1530 } 1531 1532 HANDLE NTAPI 1533 RtlpPageHeapCreate(ULONG Flags, 1534 PVOID Addr, 1535 SIZE_T TotalSize, 1536 SIZE_T CommitSize, 1537 PVOID Lock, 1538 PRTL_HEAP_PARAMETERS Parameters) 1539 { 1540 PVOID Base = NULL; 1541 PHEAP HeapPtr; 1542 PDPH_HEAP_ROOT DphRoot; 1543 PDPH_HEAP_BLOCK DphNode; 1544 ULONG MemSize; 1545 NTSTATUS Status; 1546 LARGE_INTEGER PerfCounter; 1547 1548 /* Check for a DPH bypass flag */ 1549 if ((ULONG_PTR)Parameters == -1) return NULL; 1550 1551 /* Make sure no user-allocated stuff was provided */ 1552 if (Addr || Lock) return NULL; 1553 1554 /* Allocate minimum amount of virtual memory */ 1555 MemSize = DPH_RESERVE_SIZE; 1556 Status = RtlpDphAllocateVm(&Base, MemSize, MEM_COMMIT, PAGE_NOACCESS); 1557 if (!NT_SUCCESS(Status)) 1558 { 1559 ASSERT(FALSE); 1560 return NULL; 1561 } 1562 1563 /* Set protection */ 1564 Status = RtlpDphProtectVm(Base, 2*PAGE_SIZE + DPH_POOL_SIZE, PAGE_READWRITE); 1565 if (!NT_SUCCESS(Status)) 1566 { 1567 //RtlpDphFreeVm(Base, 0, 0, 0); 1568 ASSERT(FALSE); 1569 return NULL; 1570 } 1571 1572 /* Start preparing the 1st page. Fill it with the default filler */ 1573 RtlFillMemoryUlong(Base, PAGE_SIZE, DPH_FILL); 1574 1575 /* Set flags in the "HEAP" structure */ 1576 HeapPtr = (PHEAP)Base; 1577 HeapPtr->Flags = Flags | HEAP_FLAG_PAGE_ALLOCS; 1578 HeapPtr->ForceFlags = Flags | HEAP_FLAG_PAGE_ALLOCS; 1579 1580 /* Set 1st page to read only now */ 1581 Status = RtlpDphProtectVm(Base, PAGE_SIZE, PAGE_READONLY); 1582 if (!NT_SUCCESS(Status)) 1583 { 1584 ASSERT(FALSE); 1585 return NULL; 1586 } 1587 1588 /* 2nd page is the real DPH root block */ 1589 DphRoot = (PDPH_HEAP_ROOT)((PCHAR)Base + PAGE_SIZE); 1590 1591 /* Initialize the DPH root */ 1592 DphRoot->Signature = DPH_SIGNATURE; 1593 DphRoot->HeapFlags = Flags; 1594 DphRoot->HeapCritSect = (PHEAP_LOCK)((PCHAR)DphRoot + DPH_POOL_SIZE); 1595 DphRoot->ExtraFlags = RtlpDphGlobalFlags; 1596 1597 ZwQueryPerformanceCounter(&PerfCounter, NULL); 1598 DphRoot->Seed = PerfCounter.LowPart; 1599 1600 RtlInitializeHeapLock(&DphRoot->HeapCritSect); 1601 InitializeListHead(&DphRoot->AvailableAllocationHead); 1602 1603 /* Create a normal heap for this paged heap */ 1604 DphRoot->NormalHeap = RtlCreateHeap(Flags, NULL, TotalSize, CommitSize, NULL, (PRTL_HEAP_PARAMETERS)-1); 1605 if (!DphRoot->NormalHeap) 1606 { 1607 ASSERT(FALSE); 1608 return NULL; 1609 } 1610 1611 /* 3rd page: a pool for DPH allocations */ 1612 RtlpDphAddNewPool(DphRoot, NULL, DphRoot + 1, DPH_POOL_SIZE - sizeof(DPH_HEAP_ROOT), FALSE); 1613 1614 /* Allocate internal heap blocks. For the root */ 1615 DphNode = RtlpDphAllocateNode(DphRoot); 1616 ASSERT(DphNode != NULL); 1617 DphNode->pVirtualBlock = (PUCHAR)DphRoot; 1618 DphNode->nVirtualBlockSize = DPH_POOL_SIZE; 1619 RtlpDphPlaceOnPoolList(DphRoot, DphNode); 1620 1621 /* For the memory we allocated as a whole */ 1622 DphNode = RtlpDphAllocateNode(DphRoot); 1623 ASSERT(DphNode != NULL); 1624 DphNode->pVirtualBlock = Base; 1625 DphNode->nVirtualBlockSize = MemSize; 1626 RtlpDphPlaceOnVirtualList(DphRoot, DphNode); 1627 1628 /* For the remaining part */ 1629 DphNode = RtlpDphAllocateNode(DphRoot); 1630 ASSERT(DphNode != NULL); 1631 DphNode->pVirtualBlock = (PUCHAR)Base + 2*PAGE_SIZE + DPH_POOL_SIZE; 1632 DphNode->nVirtualBlockSize = MemSize - (2*PAGE_SIZE + DPH_POOL_SIZE); 1633 RtlpDphCoalesceNodeIntoAvailable(DphRoot, DphNode); 1634 1635 //DphRoot->CreateStackTrace = RtlpDphLogStackTrace(1); 1636 1637 /* Initialize AVL-based busy nodes table */ 1638 RtlInitializeGenericTableAvl(&DphRoot->BusyNodesTable, 1639 RtlpDphCompareNodeForTable, 1640 RtlpDphAllocateNodeForTable, 1641 RtlpDphFreeNodeForTable, 1642 NULL); 1643 1644 /* Initialize per-process startup info */ 1645 if (!RtlpDphPageHeapListInitialized) RtlpDphProcessStartupInitialization(); 1646 1647 /* Acquire the heap list lock */ 1648 RtlEnterHeapLock(RtlpDphPageHeapListLock, TRUE); 1649 1650 /* Insert this heap to the tail of the global list */ 1651 InsertTailList(&RtlpDphPageHeapList, &DphRoot->NextHeap); 1652 1653 /* Note we increased the size of the list */ 1654 RtlpDphPageHeapListLength++; 1655 1656 /* Release the heap list lock */ 1657 RtlLeaveHeapLock(RtlpDphPageHeapListLock); 1658 1659 if (RtlpDphDebugOptions & DPH_DEBUG_VERBOSE) 1660 { 1661 DPRINT1("Page heap: process 0x%p created heap @ %p (%p, flags 0x%X)\n", 1662 NtCurrentTeb()->ClientId.UniqueProcess, (PUCHAR)DphRoot - PAGE_SIZE, 1663 DphRoot->NormalHeap, DphRoot->ExtraFlags); 1664 } 1665 1666 /* Perform internal validation if required */ 1667 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE) 1668 RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0); 1669 1670 return (PUCHAR)DphRoot - PAGE_SIZE; 1671 } 1672 1673 PVOID NTAPI 1674 RtlpPageHeapDestroy(HANDLE HeapPtr) 1675 { 1676 PDPH_HEAP_ROOT DphRoot; 1677 PVOID Ptr; 1678 PDPH_HEAP_BLOCK Node, Next; 1679 PHEAP NormalHeap; 1680 ULONG Value; 1681 1682 /* Check if it's not a process heap */ 1683 if (HeapPtr == RtlGetProcessHeap()) 1684 { 1685 DbgBreakPoint(); 1686 return NULL; 1687 } 1688 1689 /* Get pointer to the heap root */ 1690 DphRoot = RtlpDphPointerFromHandle(HeapPtr); 1691 if (!DphRoot) return NULL; 1692 1693 RtlpDphPreProcessing(DphRoot, DphRoot->HeapFlags); 1694 1695 /* Get the pointer to the normal heap */ 1696 NormalHeap = DphRoot->NormalHeap; 1697 1698 /* Free the delayed-free blocks */ 1699 RtlpDphFreeDelayedBlocksFromHeap(DphRoot, NormalHeap); 1700 1701 /* Go through the busy blocks */ 1702 Ptr = RtlEnumerateGenericTableAvl(&DphRoot->BusyNodesTable, TRUE); 1703 1704 while (Ptr) 1705 { 1706 Node = CONTAINING_RECORD(Ptr, DPH_HEAP_BLOCK, pUserAllocation); 1707 if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN)) 1708 { 1709 if (!RtlpDphIsPageHeapBlock(DphRoot, Node->pUserAllocation, &Value, TRUE)) 1710 { 1711 RtlpDphReportCorruptedBlock(DphRoot, 3, Node->pUserAllocation, Value); 1712 } 1713 } 1714 1715 /* FIXME: Call AV notification */ 1716 //AVrfInternalHeapFreeNotification(); 1717 1718 /* Go to the next node */ 1719 Ptr = RtlEnumerateGenericTableAvl(&DphRoot->BusyNodesTable, FALSE); 1720 } 1721 1722 /* Acquire the global heap list lock */ 1723 RtlEnterHeapLock(RtlpDphPageHeapListLock, TRUE); 1724 1725 /* Remove the entry and decrement the global counter */ 1726 RemoveEntryList(&DphRoot->NextHeap); 1727 RtlpDphPageHeapListLength--; 1728 1729 /* Release the global heap list lock */ 1730 RtlLeaveHeapLock(RtlpDphPageHeapListLock); 1731 1732 /* Leave and delete this heap's critical section */ 1733 RtlLeaveHeapLock(DphRoot->HeapCritSect); 1734 RtlDeleteHeapLock(DphRoot->HeapCritSect); 1735 1736 /* Now go through all virtual list nodes and release the VM */ 1737 Node = DphRoot->pVirtualStorageListHead; 1738 while (Node) 1739 { 1740 Next = Node->pNextAlloc; 1741 /* Release the memory without checking result */ 1742 RtlpDphFreeVm(Node->pVirtualBlock, 0, MEM_RELEASE); 1743 Node = Next; 1744 } 1745 1746 /* Destroy the normal heap */ 1747 RtlDestroyHeap(NormalHeap); 1748 1749 /* Report success */ 1750 if (RtlpDphDebugOptions & DPH_DEBUG_VERBOSE) 1751 DPRINT1("Page heap: process 0x%p destroyed heap @ %p (%p)\n", 1752 NtCurrentTeb()->ClientId.UniqueProcess, HeapPtr, NormalHeap); 1753 1754 return NULL; 1755 } 1756 1757 PVOID NTAPI 1758 RtlpPageHeapAllocate(IN PVOID HeapPtr, 1759 IN ULONG Flags, 1760 IN SIZE_T Size) 1761 { 1762 PDPH_HEAP_ROOT DphRoot; 1763 PDPH_HEAP_BLOCK AvailableNode, BusyNode; 1764 BOOLEAN Biased = FALSE; 1765 ULONG AllocateSize, AccessSize; 1766 NTSTATUS Status; 1767 SIZE_T UserActualSize; 1768 PVOID Ptr; 1769 1770 /* Check requested size */ 1771 if (Size > 0x7FF00000) 1772 { 1773 DPRINT1("extreme size request\n"); 1774 1775 /* Generate an exception if needed */ 1776 if (Flags & HEAP_GENERATE_EXCEPTIONS) RtlpDphRaiseException(STATUS_NO_MEMORY); 1777 1778 return NULL; 1779 } 1780 1781 /* Unbias the pointer if necessary */ 1782 if (IS_BIASED_POINTER(HeapPtr)) 1783 { 1784 HeapPtr = (PVOID)POINTER_REMOVE_BIAS(HeapPtr); 1785 Biased = TRUE; 1786 } 1787 1788 /* Get a pointer to the heap root */ 1789 DphRoot = RtlpDphPointerFromHandle(HeapPtr); 1790 if (!DphRoot) return NULL; 1791 1792 /* Acquire the heap lock */ 1793 RtlpDphPreProcessing(DphRoot, Flags); 1794 1795 /* Perform internal validation if specified by flags */ 1796 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE && !Biased) 1797 { 1798 RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0); 1799 } 1800 1801 /* Add heap flags */ 1802 Flags |= DphRoot->HeapFlags; 1803 1804 if (!Biased && !RtlpDphShouldAllocateInPageHeap(DphRoot, Size)) 1805 { 1806 /* Perform allocation from a normal heap */ 1807 ASSERT(FALSE); 1808 } 1809 1810 /* Perform heap integrity check if specified by flags */ 1811 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE) 1812 { 1813 RtlpDphVerifyIntegrity(DphRoot); 1814 } 1815 1816 /* Calculate sizes */ 1817 AccessSize = ROUND_UP(Size + sizeof(DPH_BLOCK_INFORMATION), PAGE_SIZE); 1818 AllocateSize = AccessSize + PAGE_SIZE; 1819 1820 // FIXME: Move RtlpDphAllocateNode(DphRoot) to this place 1821 AvailableNode = RtlpDphFindAvailableMemory(DphRoot, AllocateSize, TRUE); 1822 if (!AvailableNode) 1823 { 1824 DPRINT1("Page heap: Unable to allocate virtual memory\n"); 1825 DbgBreakPoint(); 1826 1827 /* Release the lock */ 1828 RtlpDphPostProcessing(DphRoot); 1829 1830 return NULL; 1831 } 1832 ASSERT(AvailableNode->nVirtualBlockSize >= AllocateSize); 1833 1834 /* Set protection */ 1835 Status = RtlpDphSetProtectionBeforeUse(DphRoot, 1836 AvailableNode->pVirtualBlock, 1837 AccessSize); 1838 if (!NT_SUCCESS(Status)) 1839 { 1840 ASSERT(FALSE); 1841 } 1842 1843 /* Save available node pointer */ 1844 Ptr = AvailableNode->pVirtualBlock; 1845 1846 /* Check node's size */ 1847 if (AvailableNode->nVirtualBlockSize > AllocateSize) 1848 { 1849 /* The block contains too much free space, reduce it */ 1850 AvailableNode->pVirtualBlock += AllocateSize; 1851 AvailableNode->nVirtualBlockSize -= AllocateSize; 1852 DphRoot->nAvailableAllocationBytesCommitted -= AllocateSize; 1853 1854 /* Allocate a new node which will be our busy node */ 1855 BusyNode = RtlpDphAllocateNode(DphRoot); 1856 ASSERT(BusyNode != NULL); 1857 BusyNode->pVirtualBlock = Ptr; 1858 BusyNode->nVirtualBlockSize = AllocateSize; 1859 } 1860 else 1861 { 1862 /* The block's size fits exactly */ 1863 RtlpDphRemoveFromAvailableList(DphRoot, AvailableNode); 1864 BusyNode = AvailableNode; 1865 } 1866 1867 /* Calculate actual user size */ 1868 if (DphRoot->HeapFlags & HEAP_NO_ALIGNMENT) 1869 UserActualSize = Size; 1870 else 1871 UserActualSize = ROUND_UP(Size, 8); 1872 1873 /* Set up the block */ 1874 BusyNode->nVirtualAccessSize = AccessSize; 1875 BusyNode->nUserActualSize = UserActualSize; 1876 BusyNode->nUserRequestedSize = Size; 1877 1878 if (DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN) 1879 BusyNode->pUserAllocation = BusyNode->pVirtualBlock + PAGE_SIZE; 1880 else 1881 BusyNode->pUserAllocation = BusyNode->pVirtualBlock + BusyNode->nVirtualAccessSize - UserActualSize; 1882 1883 BusyNode->UserValue = NULL; 1884 BusyNode->UserFlags = Flags & HEAP_SETTABLE_USER_FLAGS; 1885 1886 // FIXME: Don't forget about stack traces if such flag was set 1887 BusyNode->StackTrace = NULL; 1888 1889 /* Place it on busy list */ 1890 RtlpDphPlaceOnBusyList(DphRoot, BusyNode); 1891 1892 /* Zero or patter-fill memory depending on flags */ 1893 if (Flags & HEAP_ZERO_MEMORY) 1894 RtlZeroMemory(BusyNode->pUserAllocation, Size); 1895 else 1896 RtlFillMemory(BusyNode->pUserAllocation, Size, DPH_FILL_INFIX); 1897 1898 /* Write DPH info */ 1899 if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN)) 1900 { 1901 RtlpDphWritePageHeapBlockInformation(DphRoot, 1902 BusyNode->pUserAllocation, 1903 Size, 1904 AccessSize); 1905 } 1906 1907 /* Finally allocation is done, perform validation again if required */ 1908 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE && !Biased) 1909 { 1910 RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0); 1911 } 1912 1913 /* Release the lock */ 1914 RtlpDphPostProcessing(DphRoot); 1915 1916 DPRINT("Allocated user block pointer: %p\n", BusyNode->pUserAllocation); 1917 1918 /* Return pointer to user allocation */ 1919 return BusyNode->pUserAllocation; 1920 } 1921 1922 BOOLEAN NTAPI 1923 RtlpPageHeapFree(HANDLE HeapPtr, 1924 ULONG Flags, 1925 PVOID Ptr) 1926 { 1927 PDPH_HEAP_ROOT DphRoot; 1928 PDPH_HEAP_BLOCK Node; 1929 ULONG ValidationInfo; 1930 PDPH_BLOCK_INFORMATION Info; 1931 1932 /* Check for a NULL pointer freeing */ 1933 if (!Ptr) 1934 { 1935 if (RtlpDphBreakOptions & DPH_BREAK_ON_NULL_FREE) 1936 { 1937 DPRINT1("Page heap: freeing a null pointer\n"); 1938 DbgBreakPoint(); 1939 } 1940 return TRUE; 1941 } 1942 1943 /* Get a pointer to the heap root */ 1944 DphRoot = RtlpDphPointerFromHandle(HeapPtr); 1945 if (!DphRoot) return FALSE; 1946 1947 /* Acquire the heap lock */ 1948 RtlpDphPreProcessing(DphRoot, Flags); 1949 1950 /* Perform internal validation if specified by flags */ 1951 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE) 1952 RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0); 1953 1954 /* Add heap flags */ 1955 Flags |= DphRoot->HeapFlags; 1956 1957 /* Find busy memory */ 1958 Node = RtlpDphFindBusyMemory(DphRoot, Ptr); 1959 1960 if (!Node) 1961 { 1962 /* This block was not found in page heap, try a normal heap instead */ 1963 //RtlpDphNormalHeapFree(); 1964 ASSERT(FALSE); 1965 } 1966 1967 if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN)) 1968 { 1969 /* Check and report corrupted block */ 1970 if (!RtlpDphIsPageHeapBlock(DphRoot, Ptr, &ValidationInfo, TRUE)) 1971 { 1972 RtlpDphReportCorruptedBlock(DphRoot, 1, Ptr, ValidationInfo); 1973 } 1974 1975 // FIXME: Should go inside RtlpDphSetProtectionAfterUse 1976 if (Node->nVirtualAccessSize != 0) 1977 { 1978 /* Set stamps */ 1979 Info = (PDPH_BLOCK_INFORMATION)Node->pUserAllocation - 1; 1980 Info->StartStamp = DPH_FILL_START_STAMP_2; 1981 Info->EndStamp = DPH_FILL_END_STAMP_2; 1982 1983 RtlpDphProtectVm(Node->pVirtualBlock, Node->nVirtualAccessSize, PAGE_NOACCESS); 1984 } 1985 } 1986 else 1987 { 1988 // FIXME: Should go inside RtlpDphSetProtectionAfterUse 1989 if (Node->nVirtualAccessSize != 0) 1990 RtlpDphProtectVm(Node->pVirtualBlock + PAGE_SIZE, Node->nVirtualAccessSize, PAGE_NOACCESS); 1991 } 1992 1993 /* Set new protection */ 1994 //RtlpDphSetProtectionAfterUse(DphRoot, Node); 1995 1996 /* Remove it from the list of busy nodes */ 1997 RtlpDphRemoveFromBusyList(DphRoot, Node); 1998 1999 /* And put it into the list of free nodes */ 2000 RtlpDphPlaceOnFreeList(DphRoot, Node); 2001 2002 //if (DphRoot->ExtraFlags & DPH_EXTRA_LOG_STACK_TRACES) 2003 // Node->StackTrace = RtlpDphLogStackTrace(3); 2004 //else 2005 Node->StackTrace = NULL; 2006 2007 /* Leave the heap lock */ 2008 RtlpDphPostProcessing(DphRoot); 2009 2010 /* Return success */ 2011 return TRUE; 2012 } 2013 2014 PVOID NTAPI 2015 RtlpPageHeapReAllocate(HANDLE HeapPtr, 2016 ULONG Flags, 2017 PVOID Ptr, 2018 SIZE_T Size) 2019 { 2020 PDPH_HEAP_ROOT DphRoot; 2021 PDPH_HEAP_BLOCK Node = NULL, AllocatedNode; 2022 BOOLEAN Biased = FALSE, UseNormalHeap = FALSE, OldBlockPageHeap = TRUE; 2023 ULONG ValidationInfo; 2024 SIZE_T DataSize; 2025 PVOID NewAlloc = NULL; 2026 2027 /* Check requested size */ 2028 if (Size > 0x7FF00000) 2029 { 2030 DPRINT1("extreme size request\n"); 2031 2032 /* Generate an exception if needed */ 2033 if (Flags & HEAP_GENERATE_EXCEPTIONS) RtlpDphRaiseException(STATUS_NO_MEMORY); 2034 2035 return NULL; 2036 } 2037 2038 /* Unbias the pointer if necessary */ 2039 if (IS_BIASED_POINTER(HeapPtr)) 2040 { 2041 HeapPtr = (PVOID)POINTER_REMOVE_BIAS(HeapPtr); 2042 Biased = TRUE; 2043 } 2044 2045 /* Get a pointer to the heap root */ 2046 DphRoot = RtlpDphPointerFromHandle(HeapPtr); 2047 if (!DphRoot) return NULL; 2048 2049 /* Acquire the heap lock */ 2050 RtlpDphPreProcessing(DphRoot, Flags); 2051 2052 /* Perform internal validation if specified by flags */ 2053 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE) 2054 { 2055 RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0); 2056 } 2057 2058 /* Add heap flags */ 2059 Flags |= DphRoot->HeapFlags; 2060 2061 /* Exit with NULL right away if inplace is specified */ 2062 if (Flags & HEAP_REALLOC_IN_PLACE_ONLY) 2063 { 2064 /* Release the lock */ 2065 RtlpDphPostProcessing(DphRoot); 2066 2067 /* Generate an exception if needed */ 2068 if (Flags & HEAP_GENERATE_EXCEPTIONS) RtlpDphRaiseException(STATUS_NO_MEMORY); 2069 2070 return NULL; 2071 } 2072 2073 /* Try to get node of the allocated block */ 2074 AllocatedNode = RtlpDphFindBusyMemory(DphRoot, Ptr); 2075 2076 if (!AllocatedNode) 2077 { 2078 /* This block was not found in page heap, try a normal heap instead */ 2079 //RtlpDphNormalHeapFree(); 2080 ASSERT(FALSE); 2081 OldBlockPageHeap = FALSE; 2082 } 2083 2084 /* Check the block */ 2085 if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN)) 2086 { 2087 if (!RtlpDphIsPageHeapBlock(DphRoot, AllocatedNode->pUserAllocation, &ValidationInfo, TRUE)) 2088 { 2089 RtlpDphReportCorruptedBlock(DphRoot, 3, AllocatedNode->pUserAllocation, ValidationInfo); 2090 } 2091 } 2092 2093 /* Remove old one from the busy list */ 2094 RtlpDphRemoveFromBusyList(DphRoot, AllocatedNode); 2095 2096 if (!Biased && !RtlpDphShouldAllocateInPageHeap(DphRoot, Size)) 2097 { 2098 // FIXME: Use normal heap 2099 ASSERT(FALSE); 2100 UseNormalHeap = TRUE; 2101 } 2102 else 2103 { 2104 /* Now do a trick: bias the pointer and call our allocate routine */ 2105 NewAlloc = RtlpPageHeapAllocate((PVOID)POINTER_ADD_BIAS(HeapPtr), Flags, Size); 2106 } 2107 2108 if (!NewAlloc) 2109 { 2110 /* New allocation failed, put the block back (if it was found in page heap) */ 2111 RtlpDphPlaceOnBusyList(DphRoot, AllocatedNode); 2112 2113 /* Release the lock */ 2114 RtlpDphPostProcessing(DphRoot); 2115 2116 /* Perform validation again if required */ 2117 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE) 2118 { 2119 RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0); 2120 } 2121 2122 /* Generate an exception if needed */ 2123 if (Flags & HEAP_GENERATE_EXCEPTIONS) RtlpDphRaiseException(STATUS_NO_MEMORY); 2124 2125 return NULL; 2126 } 2127 2128 /* Copy contents of the old block */ 2129 if (AllocatedNode->nUserRequestedSize > Size) 2130 DataSize = Size; 2131 else 2132 DataSize = AllocatedNode->nUserRequestedSize; 2133 2134 if (DataSize != 0) RtlCopyMemory(NewAlloc, Ptr, DataSize); 2135 2136 /* Copy user flags and values */ 2137 if (!UseNormalHeap) 2138 { 2139 /* Get the node of the new block */ 2140 Node = RtlpDphFindBusyMemory(DphRoot, NewAlloc); 2141 ASSERT(Node != NULL); 2142 2143 /* Set its values/flags */ 2144 Node->UserValue = AllocatedNode->UserValue; 2145 if (Flags & HEAP_SETTABLE_USER_FLAGS) 2146 Node->UserFlags = Flags & HEAP_SETTABLE_USER_FLAGS; 2147 else 2148 Node->UserFlags = AllocatedNode->UserFlags; 2149 } 2150 2151 if (!OldBlockPageHeap) 2152 { 2153 /* Weird scenario, investigate */ 2154 ASSERT(FALSE); 2155 } 2156 2157 /* Mark the old block as no access */ 2158 if (AllocatedNode->nVirtualAccessSize != 0) 2159 { 2160 RtlpDphProtectVm(AllocatedNode->pVirtualBlock, AllocatedNode->nVirtualAccessSize, PAGE_NOACCESS); 2161 } 2162 2163 /* And place it on the free list */ 2164 RtlpDphPlaceOnFreeList(DphRoot, AllocatedNode); 2165 2166 // FIXME: Capture stack traces if needed 2167 AllocatedNode->StackTrace = NULL; 2168 2169 /* Finally allocation is done, perform validation again if required */ 2170 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE && !Biased) 2171 { 2172 RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0); 2173 } 2174 2175 /* Release the lock */ 2176 RtlpDphPostProcessing(DphRoot); 2177 2178 DPRINT("Allocated new user block pointer: %p\n", NewAlloc); 2179 2180 /* Return pointer to user allocation */ 2181 return NewAlloc; 2182 } 2183 2184 BOOLEAN NTAPI 2185 RtlpPageHeapGetUserInfo(PVOID HeapHandle, 2186 ULONG Flags, 2187 PVOID BaseAddress, 2188 PVOID *UserValue, 2189 PULONG UserFlags) 2190 { 2191 PDPH_HEAP_ROOT DphRoot; 2192 PDPH_HEAP_BLOCK Node; 2193 2194 /* Get a pointer to the heap root */ 2195 DphRoot = RtlpDphPointerFromHandle(HeapHandle); 2196 if (!DphRoot) return FALSE; 2197 2198 /* Add heap flags */ 2199 Flags |= DphRoot->HeapFlags; 2200 2201 /* Acquire the heap lock */ 2202 RtlpDphPreProcessing(DphRoot, Flags); 2203 2204 /* Find busy memory */ 2205 Node = RtlpDphFindBusyMemory(DphRoot, BaseAddress); 2206 2207 if (!Node) 2208 { 2209 /* This block was not found in page heap, try a normal heap instead */ 2210 //RtlpDphNormalHeapGetUserInfo(); 2211 ASSERT(FALSE); 2212 return FALSE; 2213 } 2214 2215 /* Get user values and flags and store them in user provided pointers */ 2216 if (UserValue) *UserValue = Node->UserValue; 2217 if (UserFlags) *UserFlags = Node->UserFlags; 2218 2219 /* Leave the heap lock */ 2220 RtlpDphPostProcessing(DphRoot); 2221 2222 /* Return success */ 2223 return TRUE; 2224 } 2225 2226 BOOLEAN NTAPI 2227 RtlpPageHeapSetUserValue(PVOID HeapHandle, 2228 ULONG Flags, 2229 PVOID BaseAddress, 2230 PVOID UserValue) 2231 { 2232 PDPH_HEAP_ROOT DphRoot; 2233 PDPH_HEAP_BLOCK Node; 2234 2235 /* Get a pointer to the heap root */ 2236 DphRoot = RtlpDphPointerFromHandle(HeapHandle); 2237 if (!DphRoot) return FALSE; 2238 2239 /* Add heap flags */ 2240 Flags |= DphRoot->HeapFlags; 2241 2242 /* Acquire the heap lock */ 2243 RtlpDphPreProcessing(DphRoot, Flags); 2244 2245 /* Find busy memory */ 2246 Node = RtlpDphFindBusyMemory(DphRoot, BaseAddress); 2247 2248 if (!Node) 2249 { 2250 /* This block was not found in page heap, try a normal heap instead */ 2251 //RtlpDphNormalHeapSetUserValue(); 2252 ASSERT(FALSE); 2253 return FALSE; 2254 } 2255 2256 /* Get user values and flags and store them in user provided pointers */ 2257 Node->UserValue = UserValue; 2258 2259 /* Leave the heap lock */ 2260 RtlpDphPostProcessing(DphRoot); 2261 2262 /* Return success */ 2263 return TRUE; 2264 } 2265 2266 BOOLEAN 2267 NTAPI 2268 RtlpPageHeapSetUserFlags(PVOID HeapHandle, 2269 ULONG Flags, 2270 PVOID BaseAddress, 2271 ULONG UserFlagsReset, 2272 ULONG UserFlagsSet) 2273 { 2274 PDPH_HEAP_ROOT DphRoot; 2275 PDPH_HEAP_BLOCK Node; 2276 2277 /* Get a pointer to the heap root */ 2278 DphRoot = RtlpDphPointerFromHandle(HeapHandle); 2279 if (!DphRoot) return FALSE; 2280 2281 /* Add heap flags */ 2282 Flags |= DphRoot->HeapFlags; 2283 2284 /* Acquire the heap lock */ 2285 RtlpDphPreProcessing(DphRoot, Flags); 2286 2287 /* Find busy memory */ 2288 Node = RtlpDphFindBusyMemory(DphRoot, BaseAddress); 2289 2290 if (!Node) 2291 { 2292 /* This block was not found in page heap, try a normal heap instead */ 2293 //RtlpDphNormalHeapSetUserFlags(); 2294 ASSERT(FALSE); 2295 return FALSE; 2296 } 2297 2298 /* Get user values and flags and store them in user provided pointers */ 2299 Node->UserFlags &= ~(UserFlagsReset); 2300 Node->UserFlags |= UserFlagsSet; 2301 2302 /* Leave the heap lock */ 2303 RtlpDphPostProcessing(DphRoot); 2304 2305 /* Return success */ 2306 return TRUE; 2307 } 2308 2309 SIZE_T NTAPI 2310 RtlpPageHeapSize(HANDLE HeapHandle, 2311 ULONG Flags, 2312 PVOID BaseAddress) 2313 { 2314 PDPH_HEAP_ROOT DphRoot; 2315 PDPH_HEAP_BLOCK Node; 2316 SIZE_T Size; 2317 2318 /* Get a pointer to the heap root */ 2319 DphRoot = RtlpDphPointerFromHandle(HeapHandle); 2320 if (!DphRoot) return -1; 2321 2322 /* Add heap flags */ 2323 Flags |= DphRoot->HeapFlags; 2324 2325 /* Acquire the heap lock */ 2326 RtlpDphPreProcessing(DphRoot, Flags); 2327 2328 /* Find busy memory */ 2329 Node = RtlpDphFindBusyMemory(DphRoot, BaseAddress); 2330 2331 if (!Node) 2332 { 2333 /* This block was not found in page heap, try a normal heap instead */ 2334 //RtlpDphNormalHeapSize(); 2335 ASSERT(FALSE); 2336 return -1; 2337 } 2338 2339 /* Get heap block size */ 2340 Size = Node->nUserRequestedSize; 2341 2342 /* Leave the heap lock */ 2343 RtlpDphPostProcessing(DphRoot); 2344 2345 /* Return user requested size */ 2346 return Size; 2347 } 2348 2349 BOOLEAN 2350 NTAPI 2351 RtlpDebugPageHeapValidate(PVOID HeapHandle, 2352 ULONG Flags, 2353 PVOID BaseAddress) 2354 { 2355 PDPH_HEAP_ROOT DphRoot; 2356 PDPH_HEAP_BLOCK Node = NULL; 2357 BOOLEAN Valid = FALSE; 2358 2359 /* Get a pointer to the heap root */ 2360 DphRoot = RtlpDphPointerFromHandle(HeapHandle); 2361 if (!DphRoot) return -1; 2362 2363 /* Add heap flags */ 2364 Flags |= DphRoot->HeapFlags; 2365 2366 /* Acquire the heap lock */ 2367 RtlpDphPreProcessing(DphRoot, Flags); 2368 2369 /* Find busy memory */ 2370 if (BaseAddress) 2371 Node = RtlpDphFindBusyMemory(DphRoot, BaseAddress); 2372 2373 if (!Node) 2374 { 2375 /* This block was not found in page heap, or the request is to validate all normal heap */ 2376 Valid = RtlpDphNormalHeapValidate(DphRoot, Flags, BaseAddress); 2377 } 2378 2379 /* Leave the heap lock */ 2380 RtlpDphPostProcessing(DphRoot); 2381 2382 /* Return result of a normal heap validation */ 2383 if (BaseAddress && !Node) 2384 return Valid; 2385 2386 /* Otherwise return our own result */ 2387 if (!BaseAddress || Node) Valid = TRUE; 2388 2389 return Valid; 2390 } 2391 2392 BOOLEAN 2393 NTAPI 2394 RtlpDphNormalHeapValidate(PDPH_HEAP_ROOT DphRoot, 2395 ULONG Flags, 2396 PVOID BaseAddress) 2397 { 2398 PDPH_BLOCK_INFORMATION BlockInfo = (PDPH_BLOCK_INFORMATION)BaseAddress - 1; 2399 if (!BaseAddress) 2400 { 2401 /* Validate all normal heap */ 2402 return RtlValidateHeap(DphRoot->NormalHeap, Flags, NULL); 2403 } 2404 2405 // FIXME: Check is this a normal heap block 2406 /*if (!RtlpDphIsNormalHeapBlock(DphRoot, BaseAddress, &ValidationInfo)) 2407 { 2408 }*/ 2409 2410 return RtlValidateHeap(DphRoot->NormalHeap, Flags, BlockInfo); 2411 } 2412 2413 BOOLEAN 2414 NTAPI 2415 RtlpPageHeapLock(HANDLE HeapPtr) 2416 { 2417 PDPH_HEAP_ROOT DphRoot; 2418 2419 /* Get pointer to the heap root */ 2420 DphRoot = RtlpDphPointerFromHandle(HeapPtr); 2421 if (!DphRoot) return FALSE; 2422 2423 RtlpDphEnterCriticalSection(DphRoot, DphRoot->HeapFlags); 2424 return TRUE; 2425 } 2426 2427 BOOLEAN 2428 NTAPI 2429 RtlpPageHeapUnlock(HANDLE HeapPtr) 2430 { 2431 PDPH_HEAP_ROOT DphRoot; 2432 2433 /* Get pointer to the heap root */ 2434 DphRoot = RtlpDphPointerFromHandle(HeapPtr); 2435 if (!DphRoot) return FALSE; 2436 2437 RtlpDphLeaveCriticalSection(DphRoot); 2438 return TRUE; 2439 } 2440 2441 /* EOF */ 2442