ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

heappage.c
Go to the documentation of this file.
00001 /* COPYRIGHT:       See COPYING in the top level directory
00002  * PROJECT:         ReactOS system libraries
00003  * FILE:            lib/rtl/heappage.c
00004  * PURPOSE:         RTL Page Heap implementation
00005  * PROGRAMMERS:     Copyright 2011 Aleksey Bragin
00006  */
00007 
00008 /* Useful references:
00009     http://msdn.microsoft.com/en-us/library/ms220938(VS.80).aspx
00010     http://blogs.msdn.com/b/jiangyue/archive/2010/03/16/windows-heap-overrun-monitoring.aspx
00011 */
00012 
00013 /* INCLUDES *****************************************************************/
00014 
00015 #include <rtl.h>
00016 #include <heap.h>
00017 
00018 #define NDEBUG
00019 #include <debug.h>
00020 
00021 /* TYPES **********************************************************************/
00022 
00023 typedef struct _DPH_BLOCK_INFORMATION
00024 {
00025      ULONG StartStamp;
00026      PVOID Heap;
00027      SIZE_T RequestedSize;
00028      SIZE_T ActualSize;
00029      union
00030      {
00031           LIST_ENTRY FreeQueue;
00032           SINGLE_LIST_ENTRY FreePushList;
00033           WORD TraceIndex;
00034      };
00035      PVOID StackTrace;
00036      ULONG EndStamp;
00037 } DPH_BLOCK_INFORMATION, *PDPH_BLOCK_INFORMATION;
00038 
00039 typedef struct _DPH_HEAP_BLOCK
00040 {
00041      union
00042      {
00043           struct _DPH_HEAP_BLOCK *pNextAlloc;
00044           LIST_ENTRY AvailableEntry;
00045           RTL_BALANCED_LINKS TableLinks;
00046      };
00047      PUCHAR pUserAllocation;
00048      PUCHAR pVirtualBlock;
00049      SIZE_T nVirtualBlockSize;
00050      SIZE_T nVirtualAccessSize;
00051      SIZE_T nUserRequestedSize;
00052      SIZE_T nUserActualSize;
00053      PVOID UserValue;
00054      ULONG UserFlags;
00055      PRTL_TRACE_BLOCK StackTrace;
00056      LIST_ENTRY AdjacencyEntry;
00057      PUCHAR pVirtualRegion;
00058 } DPH_HEAP_BLOCK, *PDPH_HEAP_BLOCK;
00059 
00060 typedef struct _DPH_HEAP_ROOT
00061 {
00062      ULONG Signature;
00063      ULONG HeapFlags;
00064      PRTL_CRITICAL_SECTION HeapCritSect;
00065      ULONG nRemoteLockAcquired;
00066 
00067      PDPH_HEAP_BLOCK pVirtualStorageListHead;
00068      PDPH_HEAP_BLOCK pVirtualStorageListTail;
00069      ULONG nVirtualStorageRanges;
00070      SIZE_T nVirtualStorageBytes;
00071 
00072      RTL_AVL_TABLE BusyNodesTable;
00073      PDPH_HEAP_BLOCK NodeToAllocate;
00074      ULONG nBusyAllocations;
00075      SIZE_T nBusyAllocationBytesCommitted;
00076 
00077      PDPH_HEAP_BLOCK pFreeAllocationListHead;
00078      PDPH_HEAP_BLOCK pFreeAllocationListTail;
00079      ULONG nFreeAllocations;
00080      SIZE_T nFreeAllocationBytesCommitted;
00081 
00082      LIST_ENTRY AvailableAllocationHead;
00083      ULONG nAvailableAllocations;
00084      SIZE_T nAvailableAllocationBytesCommitted;
00085 
00086      PDPH_HEAP_BLOCK pUnusedNodeListHead;
00087      PDPH_HEAP_BLOCK pUnusedNodeListTail;
00088      ULONG nUnusedNodes;
00089      SIZE_T nBusyAllocationBytesAccessible;
00090      PDPH_HEAP_BLOCK pNodePoolListHead;
00091      PDPH_HEAP_BLOCK pNodePoolListTail;
00092      ULONG nNodePools;
00093      SIZE_T nNodePoolBytes;
00094 
00095      LIST_ENTRY NextHeap;
00096      ULONG ExtraFlags;
00097      ULONG Seed;
00098      PVOID NormalHeap;
00099      PRTL_TRACE_BLOCK CreateStackTrace;
00100      PVOID FirstThread;
00101 } DPH_HEAP_ROOT, *PDPH_HEAP_ROOT;
00102 
00103 /* GLOBALS ********************************************************************/
00104 
00105 BOOLEAN RtlpPageHeapEnabled = FALSE;
00106 ULONG RtlpDphGlobalFlags;
00107 ULONG RtlpPageHeapSizeRangeStart, RtlpPageHeapSizeRangeEnd;
00108 ULONG RtlpPageHeapDllRangeStart, RtlpPageHeapDllRangeEnd;
00109 WCHAR RtlpDphTargetDlls[512];
00110 
00111 LIST_ENTRY RtlpDphPageHeapList;
00112 BOOLEAN RtlpDphPageHeapListInitialized;
00113 RTL_CRITICAL_SECTION RtlpDphPageHeapListLock;
00114 ULONG RtlpDphPageHeapListLength;
00115 UNICODE_STRING RtlpDphTargetDllsUnicode;
00116 
00117 RTL_CRITICAL_SECTION RtlpDphDelayedFreeQueueLock;
00118 LIST_ENTRY RtlpDphDelayedFreeQueue;
00119 SLIST_HEADER RtlpDphDelayedTemporaryPushList;
00120 SIZE_T RtlpDphMemoryUsedByDelayedFreeBlocks;
00121 ULONG RtlpDphNumberOfDelayedFreeBlocks;
00122 
00123 /* Counters */
00124 LONG RtlpDphCounter;
00125 LONG RtlpDphAllocFails;
00126 LONG RtlpDphReleaseFails;
00127 LONG RtlpDphFreeFails;
00128 LONG RtlpDphProtectFails;
00129 
00130 #define DPH_RESERVE_SIZE 0x100000
00131 #define DPH_POOL_SIZE 0x4000
00132 #define DPH_FREE_LIST_MINIMUM 8
00133 
00134 /* RtlpDphBreakOptions */
00135 #define DPH_BREAK_ON_RESERVE_FAIL 0x01
00136 #define DPH_BREAK_ON_COMMIT_FAIL  0x02
00137 #define DPH_BREAK_ON_RELEASE_FAIL 0x04
00138 #define DPH_BREAK_ON_FREE_FAIL    0x08
00139 #define DPH_BREAK_ON_PROTECT_FAIL 0x10
00140 #define DPH_BREAK_ON_NULL_FREE    0x80
00141 
00142 /* RtlpDphDebugOptions */
00143 #define DPH_DEBUG_INTERNAL_VALIDATE 0x01
00144 #define DPH_DEBUG_VERBOSE           0x04
00145 
00146 /* DPH ExtraFlags */
00147 #define DPH_EXTRA_LOG_STACK_TRACES 0x02
00148 #define DPH_EXTRA_CHECK_UNDERRUN   0x10
00149 
00150 /* Fillers */
00151 #define DPH_FILL 0xEEEEEEEE
00152 #define DPH_FILL_START_STAMP_1 0xABCDBBBB
00153 #define DPH_FILL_START_STAMP_2 0xABCDBBBA
00154 #define DPH_FILL_END_STAMP_1   0xDCBABBBB
00155 #define DPH_FILL_END_STAMP_2   0xDCBABBBA
00156 #define DPH_FILL_SUFFIX        0xD0
00157 #define DPH_FILL_INFIX         0xC0
00158 
00159 /* Validation info flags */
00160 #define DPH_VALINFO_BAD_START_STAMP      0x01
00161 #define DPH_VALINFO_BAD_END_STAMP        0x02
00162 #define DPH_VALINFO_BAD_POINTER          0x04
00163 #define DPH_VALINFO_BAD_PREFIX_PATTERN   0x08
00164 #define DPH_VALINFO_BAD_SUFFIX_PATTERN   0x10
00165 #define DPH_VALINFO_EXCEPTION            0x20
00166 #define DPH_VALINFO_1                    0x40
00167 #define DPH_VALINFO_BAD_INFIX_PATTERN    0x80
00168 #define DPH_VALINFO_ALREADY_FREED        0x100
00169 #define DPH_VALINFO_CORRUPTED_AFTER_FREE 0x200
00170 
00171 /* Signatures */
00172 #define DPH_SIGNATURE 0xFFEEDDCC
00173 
00174 /* Biased pointer macros */
00175 #define IS_BIASED_POINTER(ptr) ((ULONG_PTR)(ptr) & 1)
00176 #define POINTER_REMOVE_BIAS(ptr) ((ULONG_PTR)(ptr) & ~(ULONG_PTR)1)
00177 #define POINTER_ADD_BIAS(ptr) ((ULONG_PTR)(ptr) | 1)
00178 
00179 
00180 ULONG RtlpDphBreakOptions = 0;//0xFFFFFFFF;
00181 ULONG RtlpDphDebugOptions;
00182 
00183 /* FUNCTIONS ******************************************************************/
00184 
00185 BOOLEAN NTAPI
00186 RtlpDphGrowVirtual(PDPH_HEAP_ROOT DphRoot, SIZE_T Size);
00187 
00188 BOOLEAN NTAPI
00189 RtlpDphIsNormalFreeHeapBlock(PVOID Block, PULONG ValidationInformation, BOOLEAN CheckFillers);
00190 
00191 VOID NTAPI
00192 RtlpDphReportCorruptedBlock(PDPH_HEAP_ROOT DphRoot, ULONG Reserved, PVOID Block, ULONG ValidationInfo);
00193 
00194 BOOLEAN NTAPI
00195 RtlpDphNormalHeapValidate(PDPH_HEAP_ROOT DphRoot, ULONG Flags, PVOID BaseAddress);
00196 
00197 
00198 VOID NTAPI
00199 RtlpDphRaiseException(NTSTATUS Status)
00200 {
00201     EXCEPTION_RECORD Exception;
00202 
00203     /* Initialize exception record */
00204     Exception.ExceptionCode = Status;
00205     Exception.ExceptionAddress = RtlpDphRaiseException;
00206     Exception.ExceptionFlags = 0;
00207     Exception.ExceptionRecord = NULL;
00208     Exception.NumberParameters = 0;
00209 
00210     /* Raise the exception */
00211     RtlRaiseException(&Exception);
00212 }
00213 
00214 PVOID NTAPI
00215 RtlpDphPointerFromHandle(PVOID Handle)
00216 {
00217     PHEAP NormalHeap = (PHEAP)Handle;
00218     PDPH_HEAP_ROOT DphHeap = (PDPH_HEAP_ROOT)((PUCHAR)Handle + PAGE_SIZE);
00219 
00220     if (NormalHeap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
00221     {
00222         if (DphHeap->Signature == DPH_SIGNATURE)
00223             return DphHeap;
00224     }
00225 
00226     DPRINT1("heap handle with incorrect signature\n");
00227     DbgBreakPoint();
00228     return NULL;
00229 }
00230 
00231 VOID NTAPI
00232 RtlpDphEnterCriticalSection(PDPH_HEAP_ROOT DphRoot, ULONG Flags)
00233 {
00234     if (Flags & HEAP_NO_SERIALIZE)
00235     {
00236         /* More complex scenario */
00237         if (!RtlTryEnterCriticalSection(DphRoot->HeapCritSect))
00238         {
00239             if (!DphRoot->nRemoteLockAcquired)
00240             {
00241                 DPRINT1("multithreaded access in HEAP_NO_SERIALIZE heap\n");
00242                 DbgBreakPoint();
00243 
00244                 /* Clear out the no serialize flag */
00245                 DphRoot->HeapFlags &= ~HEAP_NO_SERIALIZE;
00246             }
00247 
00248             /* Enter the heap's critical section */
00249             RtlEnterCriticalSection(DphRoot->HeapCritSect);
00250         }
00251     }
00252     else
00253     {
00254         /* Just enter the heap's critical section */
00255         RtlEnterCriticalSection(DphRoot->HeapCritSect);
00256     }
00257 }
00258 
00259 VOID NTAPI
00260 RtlpDphLeaveCriticalSection(PDPH_HEAP_ROOT DphRoot)
00261 {
00262     /* Just leave the heap's critical section */
00263     RtlLeaveCriticalSection(DphRoot->HeapCritSect);
00264 }
00265 
00266 
00267 VOID NTAPI
00268 RtlpDphPreProcessing(PDPH_HEAP_ROOT DphRoot, ULONG Flags)
00269 {
00270     RtlpDphEnterCriticalSection(DphRoot, Flags);
00271 
00272     /* FIXME: Validate integrity, internal lists if necessary */
00273 }
00274 
00275 VOID NTAPI
00276 RtlpDphPostProcessing(PDPH_HEAP_ROOT DphRoot)
00277 {
00278     if (!DphRoot) return;
00279 
00280     if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE)
00281     {
00282         /* FIXME: Validate integrity, internal lists if necessary */
00283     }
00284 
00285     /* Release the lock */
00286     RtlpDphLeaveCriticalSection(DphRoot);
00287 }
00288 
00289 NTSTATUS NTAPI
00290 RtlpSecMemFreeVirtualMemory(HANDLE Process, PVOID *Base, PSIZE_T Size, ULONG Type)
00291 {
00292     NTSTATUS Status;
00293     //PVOID *SavedBase = Base;
00294     //PSIZE_T SavedSize = Size;
00295 
00296     /* Free the memory */
00297     Status = ZwFreeVirtualMemory(Process, Base, Size, Type);
00298 
00299     /* Flush secure memory cache if needed and retry freeing */
00300 #if 0
00301     if (Status == STATUS_INVALID_PAGE_PROTECTION &&
00302         Process == NtCurrentProcess() &&
00303         RtlFlushSecureMemoryCache(*SavedBase, *SavedSize))
00304     {
00305         Status = ZwFreeVirtualMemory(NtCurrentProcess(), SavedBase, SavedSize, Type);
00306     }
00307 #endif
00308 
00309     return Status;
00310 }
00311 
00312 NTSTATUS NTAPI
00313 RtlpDphAllocateVm(PVOID *Base, SIZE_T Size, ULONG Type, ULONG Protection)
00314 {
00315     NTSTATUS Status;
00316     Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
00317                                      Base,
00318                                      0,
00319                                      &Size,
00320                                      Type,
00321                                      Protection);
00322     DPRINT("Page heap: AllocVm (%p, %p, %x) status %x \n", Base, Size, Type, Status);
00323     /* Check for failures */
00324     if (!NT_SUCCESS(Status))
00325     {
00326         if (Type == MEM_RESERVE)
00327         {
00328             _InterlockedIncrement(&RtlpDphCounter);
00329             if (RtlpDphBreakOptions & DPH_BREAK_ON_RESERVE_FAIL)
00330             {
00331                 DPRINT1("Page heap: AllocVm (%p, %p, %x) failed with %x \n", Base, Size, Type, Status);
00332                 DbgBreakPoint();
00333                 return Status;
00334             }
00335         }
00336         else
00337         {
00338             _InterlockedIncrement(&RtlpDphAllocFails);
00339             if (RtlpDphBreakOptions & DPH_BREAK_ON_COMMIT_FAIL)
00340             {
00341                 DPRINT1("Page heap: AllocVm (%p, %p, %x) failed with %x \n", Base, Size, Type, Status);
00342                 DbgBreakPoint();
00343                 return Status;
00344             }
00345         }
00346     }
00347 
00348     return Status;
00349 }
00350 
00351 NTSTATUS NTAPI
00352 RtlpDphFreeVm(PVOID Base, SIZE_T Size, ULONG Type)
00353 {
00354     NTSTATUS Status;
00355 
00356     /* Free the memory */
00357     Status = RtlpSecMemFreeVirtualMemory(NtCurrentProcess(), &Base, &Size, Type);
00358     DPRINT1("Page heap: FreeVm (%p, %p, %x) status %x \n", Base, Size, Type, Status);
00359     /* Log/report failures */
00360     if (!NT_SUCCESS(Status))
00361     {
00362         if (Type == MEM_RELEASE)
00363         {
00364             _InterlockedIncrement(&RtlpDphReleaseFails);
00365             if (RtlpDphBreakOptions & DPH_BREAK_ON_RELEASE_FAIL)
00366             {
00367                 DPRINT1("Page heap: FreeVm (%p, %p, %x) failed with %x \n", Base, Size, Type, Status);
00368                 DbgBreakPoint();
00369                 return Status;
00370             }
00371         }
00372         else
00373         {
00374             _InterlockedIncrement(&RtlpDphFreeFails);
00375             if (RtlpDphBreakOptions & DPH_BREAK_ON_FREE_FAIL)
00376             {
00377                 DPRINT1("Page heap: FreeVm (%p, %p, %x) failed with %x \n", Base, Size, Type, Status);
00378                 DbgBreakPoint();
00379                 return Status;
00380             }
00381         }
00382     }
00383 
00384     return Status;
00385 }
00386 
00387 NTSTATUS NTAPI
00388 RtlpDphProtectVm(PVOID Base, SIZE_T Size, ULONG Protection)
00389 {
00390     NTSTATUS Status;
00391     ULONG OldProtection;
00392 
00393     /* Change protection */
00394     Status = ZwProtectVirtualMemory(NtCurrentProcess(), &Base, &Size, Protection, &OldProtection);
00395 
00396     /* Log/report failures */
00397     if (!NT_SUCCESS(Status))
00398     {
00399         _InterlockedIncrement(&RtlpDphProtectFails);
00400         if (RtlpDphBreakOptions & DPH_BREAK_ON_PROTECT_FAIL)
00401         {
00402             DPRINT1("Page heap: ProtectVm (%p, %p, %x) failed with %x \n", Base, Size, Protection, Status);
00403             DbgBreakPoint();
00404             return Status;
00405         }
00406     }
00407 
00408     return Status;
00409 }
00410 
00411 BOOLEAN NTAPI
00412 RtlpDphWritePageHeapBlockInformation(PDPH_HEAP_ROOT DphRoot, PVOID UserAllocation, SIZE_T Size, SIZE_T UserSize)
00413 {
00414     PDPH_BLOCK_INFORMATION BlockInfo;
00415     PUCHAR FillPtr;
00416 
00417     /* Get pointer to the block info structure */
00418     BlockInfo = (PDPH_BLOCK_INFORMATION)UserAllocation - 1;
00419 
00420     /* Set up basic fields */
00421     BlockInfo->Heap = DphRoot;
00422     BlockInfo->ActualSize = UserSize;
00423     BlockInfo->RequestedSize = Size;
00424     BlockInfo->StartStamp = DPH_FILL_START_STAMP_1;
00425     BlockInfo->EndStamp = DPH_FILL_END_STAMP_1;
00426 
00427     /* Fill with a pattern */
00428     FillPtr = (PUCHAR)UserAllocation + Size;
00429     RtlFillMemory(FillPtr, ROUND_UP(FillPtr, PAGE_SIZE) - (ULONG_PTR)FillPtr, DPH_FILL_SUFFIX);
00430 
00431     /* FIXME: Check if logging stack traces is turned on */
00432     //if (DphRoot->ExtraFlags &
00433 
00434     return TRUE;
00435 }
00436 
00437 VOID NTAPI
00438 RtlpDphPlaceOnBusyList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK DphNode)
00439 {
00440     BOOLEAN NewElement;
00441     PVOID AddressUserData;
00442 
00443     DPRINT("RtlpDphPlaceOnBusyList(%p %p)\n", DphRoot, DphNode);
00444 
00445     /* Add it to the AVL busy nodes table */
00446     DphRoot->NodeToAllocate = DphNode;
00447     AddressUserData = RtlInsertElementGenericTableAvl(&DphRoot->BusyNodesTable,
00448                                                       &DphNode->pUserAllocation,
00449                                                       sizeof(ULONG_PTR),
00450                                                       &NewElement);
00451 
00452     ASSERT(AddressUserData == &DphNode->pUserAllocation);
00453     ASSERT(NewElement == TRUE);
00454 
00455     /* Update heap counters */
00456     DphRoot->nBusyAllocations++;
00457     DphRoot->nBusyAllocationBytesAccessible += DphNode->nVirtualAccessSize;
00458     DphRoot->nBusyAllocationBytesCommitted += DphNode->nVirtualBlockSize;
00459 }
00460 
00461 VOID NTAPI
00462 RtlpDphPlaceOnFreeList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK Node)
00463 {
00464     DPRINT("RtlpDphPlaceOnFreeList(%p %p)\n", DphRoot, Node);
00465 
00466     /* Node is being added to the tail of the list */
00467     Node->pNextAlloc = NULL;
00468 
00469     /* Add it to the tail of the linked list */
00470     if (DphRoot->pFreeAllocationListTail)
00471         DphRoot->pFreeAllocationListTail->pNextAlloc = Node;
00472     else
00473         DphRoot->pFreeAllocationListHead = Node;
00474     DphRoot->pFreeAllocationListTail = Node;
00475 
00476     /* Update byte counts taking in account this new node */
00477     DphRoot->nFreeAllocations++;
00478     DphRoot->nFreeAllocationBytesCommitted += Node->nVirtualBlockSize;
00479 }
00480 
00481 VOID NTAPI
00482 RtlpDphPlaceOnPoolList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK Node)
00483 {
00484     DPRINT("RtlpDphPlaceOnPoolList(%p %p)\n", DphRoot, Node);
00485 
00486     /* Node is being added to the tail of the list */
00487     Node->pNextAlloc = NULL;
00488 
00489     /* Add it to the tail of the linked list */
00490     if (DphRoot->pNodePoolListTail)
00491         DphRoot->pNodePoolListTail->pNextAlloc = Node;
00492     else
00493         DphRoot->pNodePoolListHead = Node;
00494     DphRoot->pNodePoolListTail = Node;
00495 
00496     /* Update byte counts taking in account this new node */
00497     DphRoot->nNodePools++;
00498     DphRoot->nNodePoolBytes += Node->nVirtualBlockSize;
00499 }
00500 
00501 VOID NTAPI
00502 RtlpDphPlaceOnVirtualList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK Node)
00503 {
00504     DPRINT("RtlpDphPlaceOnVirtualList(%p %p)\n", DphRoot, Node);
00505 
00506     /* Add it to the head of the virtual list */
00507     Node->pNextAlloc = DphRoot->pVirtualStorageListHead;
00508     if (!DphRoot->pVirtualStorageListHead)
00509         DphRoot->pVirtualStorageListTail = Node;
00510     DphRoot->pVirtualStorageListHead = Node;
00511 
00512     /* Update byte counts taking in account this new node */
00513     DphRoot->nVirtualStorageRanges++;
00514     DphRoot->nVirtualStorageBytes += Node->nVirtualBlockSize;
00515 }
00516 
00517 PDPH_HEAP_BLOCK NTAPI
00518 RtlpDphTakeNodeFromUnusedList(PDPH_HEAP_ROOT DphRoot)
00519 {
00520     PDPH_HEAP_BLOCK Node = DphRoot->pUnusedNodeListHead;
00521     PDPH_HEAP_BLOCK Next;
00522 
00523     DPRINT("RtlpDphTakeNodeFromUnusedList(%p), ret %p\n", DphRoot, Node);
00524 
00525     /* Take the first entry */
00526     if (!Node) return NULL;
00527 
00528     /* Remove that entry (Node) from the list */
00529     Next = Node->pNextAlloc;
00530     if (DphRoot->pUnusedNodeListHead == Node) DphRoot->pUnusedNodeListHead = Next;
00531     if (DphRoot->pUnusedNodeListTail == Node) DphRoot->pUnusedNodeListTail = NULL;
00532 
00533     /* Decrease amount of unused nodes */
00534     DphRoot->nUnusedNodes--;
00535 
00536     return Node;
00537 }
00538 
00539 VOID NTAPI
00540 RtlpDphReturnNodeToUnusedList(PDPH_HEAP_ROOT DphRoot,
00541                               PDPH_HEAP_BLOCK Node)
00542 {
00543     DPRINT("RtlpDphReturnNodeToUnusedList(%p, %p)\n", DphRoot, Node);
00544 
00545     /* Add it back to the head of the unused list */
00546     Node->pNextAlloc = DphRoot->pUnusedNodeListHead;
00547     if (!DphRoot->pUnusedNodeListHead)
00548         DphRoot->pUnusedNodeListTail = Node;
00549     DphRoot->pUnusedNodeListHead = Node;
00550 
00551     /* Increase amount of unused nodes */
00552     DphRoot->nUnusedNodes++;
00553 }
00554 
00555 VOID NTAPI
00556 RtlpDphRemoveFromAvailableList(PDPH_HEAP_ROOT DphRoot,
00557                                PDPH_HEAP_BLOCK Node)
00558 {
00559     /* Make sure Adjacency list pointers are biased */
00560     //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Flink));
00561     //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Blink));
00562 
00563     DPRINT("RtlpDphRemoveFromAvailableList(%p %p)\n", DphRoot, Node);
00564 
00565     /* Check if it is in the list */
00566 #if 0
00567     {
00568         PLIST_ENTRY CurEntry;
00569         PDPH_HEAP_BLOCK NodeEntry;
00570         BOOLEAN Found = FALSE;
00571 
00572         /* Find where to put this node according to its virtual address */
00573         CurEntry = DphRoot->AvailableAllocationHead.Flink;
00574 
00575         while (CurEntry != &DphRoot->AvailableAllocationHead)
00576         {
00577             NodeEntry = CONTAINING_RECORD(CurEntry, DPH_HEAP_BLOCK, AvailableEntry);
00578 
00579             if (NodeEntry == Node)
00580             {
00581                 Found = TRUE;
00582                 break;
00583             }
00584 
00585             CurEntry = CurEntry->Flink;
00586         }
00587 
00588         if (!Found)
00589         {
00590             DPRINT1("Trying to remove non-existing in availlist node!\n");
00591             DbgBreakPoint();
00592         }
00593     }
00594 #endif
00595 
00596     /* Remove it from the list */
00597     RemoveEntryList(&Node->AvailableEntry);
00598 
00599     /* Decrease heap counters */
00600     DphRoot->nAvailableAllocations--;
00601     DphRoot->nAvailableAllocationBytesCommitted -= Node->nVirtualBlockSize;
00602 
00603     /* Remove bias from the AdjacencyEntry pointer */
00604     Node->AdjacencyEntry.Flink = (PLIST_ENTRY)POINTER_REMOVE_BIAS(Node->AdjacencyEntry.Flink);
00605     Node->AdjacencyEntry.Blink = (PLIST_ENTRY)POINTER_REMOVE_BIAS(Node->AdjacencyEntry.Blink);
00606 }
00607 
00608 VOID NTAPI
00609 RtlpDphRemoveFromBusyList(PDPH_HEAP_ROOT DphRoot,
00610                           PDPH_HEAP_BLOCK Node)
00611 {
00612     BOOLEAN ElementPresent;
00613 
00614     DPRINT("RtlpDphRemoveFromBusyList(%p %p)\n", DphRoot, Node);
00615 
00616     /* Delete it from busy nodes table */
00617     ElementPresent = RtlDeleteElementGenericTableAvl(&DphRoot->BusyNodesTable, &Node->pUserAllocation);
00618     ASSERT(ElementPresent == TRUE);
00619 
00620     /* Update counters */
00621     DphRoot->nBusyAllocations--;
00622     DphRoot->nBusyAllocationBytesCommitted -= Node->nVirtualBlockSize;
00623     DphRoot->nBusyAllocationBytesAccessible -= Node->nVirtualAccessSize;
00624 }
00625 
00626 VOID NTAPI
00627 RtlpDphRemoveFromFreeList(PDPH_HEAP_ROOT DphRoot,
00628                           PDPH_HEAP_BLOCK Node,
00629                           PDPH_HEAP_BLOCK Prev)
00630 {
00631     PDPH_HEAP_BLOCK Next;
00632 
00633     DPRINT("RtlpDphRemoveFromFreeList(%p %p %p)\n", DphRoot, Node, Prev);
00634 
00635     /* Detach it from the list */
00636     Next = Node->pNextAlloc;
00637     if (DphRoot->pFreeAllocationListHead == Node)
00638         DphRoot->pFreeAllocationListHead = Next;
00639     if (DphRoot->pFreeAllocationListTail == Node)
00640         DphRoot->pFreeAllocationListTail = Prev;
00641     if (Prev) Prev->pNextAlloc = Next;
00642 
00643     /* Decrease heap counters */
00644     DphRoot->nFreeAllocations--;
00645     DphRoot->nFreeAllocationBytesCommitted -= Node->nVirtualBlockSize;
00646 
00647     Node->StackTrace = NULL;
00648 }
00649 
00650 VOID NTAPI
00651 RtlpDphCoalesceNodeIntoAvailable(PDPH_HEAP_ROOT DphRoot,
00652                                  PDPH_HEAP_BLOCK Node)
00653 {
00654     PDPH_HEAP_BLOCK NodeEntry, PrevNode = NULL, NextNode;
00655     PLIST_ENTRY AvailListHead;
00656     PLIST_ENTRY CurEntry;
00657 
00658     DPRINT("RtlpDphCoalesceNodeIntoAvailable(%p %p)\n", DphRoot, Node);
00659 
00660     /* Update heap counters */
00661     DphRoot->nAvailableAllocationBytesCommitted += Node->nVirtualBlockSize;
00662     DphRoot->nAvailableAllocations++;
00663 
00664     /* Find where to put this node according to its virtual address */
00665     AvailListHead = &DphRoot->AvailableAllocationHead;
00666 
00667     /* Find a point where to insert an available node */
00668     CurEntry = AvailListHead->Flink;
00669 
00670     while (CurEntry != AvailListHead)
00671     {
00672         NodeEntry = CONTAINING_RECORD(CurEntry, DPH_HEAP_BLOCK, AvailableEntry);
00673         if (NodeEntry->pVirtualBlock >= Node->pVirtualBlock)
00674         {
00675             PrevNode = NodeEntry;
00676             break;
00677         }
00678         CurEntry = CurEntry->Flink;
00679     }
00680 
00681     if (!PrevNode)
00682     {
00683         /* That means either this list is empty, or we should add to the head of it */
00684         InsertHeadList(AvailListHead, &Node->AvailableEntry);
00685     }
00686     else
00687     {
00688         /* Check the previous node and merge if possible */
00689         if (PrevNode->pVirtualBlock + PrevNode->nVirtualBlockSize == Node->pVirtualBlock)
00690         {
00691             /* They are adjacent - merge! */
00692             PrevNode->nVirtualBlockSize += Node->nVirtualBlockSize;
00693             RtlpDphReturnNodeToUnusedList(DphRoot, Node);
00694             DphRoot->nAvailableAllocations--;
00695 
00696             Node = PrevNode;
00697         }
00698         else
00699         {
00700             /* Insert after PrevNode */
00701             InsertTailList(&PrevNode->AvailableEntry, &Node->AvailableEntry);
00702         }
00703 
00704         /* Now check the next entry after our one */
00705         if (Node->AvailableEntry.Flink != AvailListHead)
00706         {
00707             NextNode = CONTAINING_RECORD(Node->AvailableEntry.Flink, DPH_HEAP_BLOCK, AvailableEntry);
00708             /* Node is not at the tail of the list, check if it's adjacent */
00709             if (Node->pVirtualBlock + Node->nVirtualBlockSize == NextNode->pVirtualBlock)
00710             {
00711                 /* They are adjacent - merge! */
00712                 Node->nVirtualBlockSize += NextNode->nVirtualBlockSize;
00713 
00714                 /* Remove next entry from the list and put it into unused entries list */
00715                 RemoveEntryList(&NextNode->AvailableEntry);
00716                 RtlpDphReturnNodeToUnusedList(DphRoot, NextNode);
00717                 DphRoot->nAvailableAllocations--;
00718             }
00719         }
00720     }
00721 }
00722 
00723 VOID NTAPI
00724 RtlpDphCoalesceFreeIntoAvailable(PDPH_HEAP_ROOT DphRoot,
00725                                  ULONG LeaveOnFreeList)
00726 {
00727     PDPH_HEAP_BLOCK Node = DphRoot->pFreeAllocationListHead, Next;
00728     SIZE_T FreeAllocations = DphRoot->nFreeAllocations;
00729 
00730     /* Make sure requested size is not too big */
00731     ASSERT(FreeAllocations >= LeaveOnFreeList);
00732 
00733     DPRINT("RtlpDphCoalesceFreeIntoAvailable(%p %d)\n", DphRoot, LeaveOnFreeList);
00734 
00735     while (Node)
00736     {
00737         FreeAllocations--;
00738         if (FreeAllocations < LeaveOnFreeList) break;
00739 
00740         /* Get the next pointer, because it may be changed after following two calls */
00741         Next = Node->pNextAlloc;
00742 
00743         /* Remove it from the free list */
00744         RtlpDphRemoveFromFreeList(DphRoot, Node, NULL);
00745 
00746         /* And put into the available */
00747         RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node);
00748 
00749         /* Go to the next node */
00750         Node = Next;
00751     }
00752 }
00753 
00754 VOID NTAPI
00755 RtlpDphAddNewPool(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK NodeBlock, PVOID Virtual, SIZE_T Size, BOOLEAN PlaceOnPool)
00756 {
00757     PDPH_HEAP_BLOCK DphNode, DphStartNode;
00758     ULONG NodeCount, i;
00759 
00760     //NodeCount = (Size >> 6) - 1;
00761     NodeCount = (ULONG)(Size / sizeof(DPH_HEAP_BLOCK));
00762     DphStartNode = Virtual;
00763 
00764     /* Set pNextAlloc for all blocks */
00765     for (DphNode = Virtual, i=NodeCount-1; i > 0; i--)
00766     {
00767         DphNode->pNextAlloc = DphNode + 1;
00768         DphNode = DphNode->pNextAlloc;
00769     }
00770 
00771     /* and the last one */
00772     DphNode->pNextAlloc = NULL;
00773 
00774     /* Add it to the tail of unused node list */
00775     if (DphRoot->pUnusedNodeListTail)
00776         DphRoot->pUnusedNodeListTail->pNextAlloc = DphStartNode;
00777     else
00778         DphRoot->pUnusedNodeListHead = DphStartNode;
00779 
00780     DphRoot->pUnusedNodeListTail = DphNode;
00781 
00782     /* Increase counters */
00783     DphRoot->nUnusedNodes += NodeCount;
00784 
00785     /* Check if we need to place it on the pool list */
00786     if (PlaceOnPool)
00787     {
00788         /* Get a node from the unused list */
00789         DphNode = RtlpDphTakeNodeFromUnusedList(DphRoot);
00790         ASSERT(DphNode);
00791 
00792         /* Set its virtual block values */
00793         DphNode->pVirtualBlock = Virtual;
00794         DphNode->nVirtualBlockSize = Size;
00795 
00796         /* Place it on the pool list */
00797         RtlpDphPlaceOnPoolList(DphRoot, DphNode);
00798     }
00799 }
00800 
00801 PDPH_HEAP_BLOCK NTAPI
00802 RtlpDphSearchAvailableMemoryListForBestFit(PDPH_HEAP_ROOT DphRoot,
00803                                            SIZE_T Size)
00804 {
00805     PLIST_ENTRY CurEntry;
00806     PDPH_HEAP_BLOCK Node, NodeFound = NULL;
00807 
00808     CurEntry = DphRoot->AvailableAllocationHead.Flink;
00809 
00810     while (CurEntry != &DphRoot->AvailableAllocationHead)
00811     {
00812         /* Get the current available node */
00813         Node = CONTAINING_RECORD(CurEntry, DPH_HEAP_BLOCK, AvailableEntry);
00814 
00815         /* Check its size */
00816         if (Node->nVirtualBlockSize >= Size)
00817         {
00818             NodeFound = Node;
00819             break;
00820         }
00821 
00822         /* Move to the next available entry */
00823         CurEntry = CurEntry->Flink;
00824     }
00825 
00826     /* Make sure Adjacency list pointers are biased */
00827     //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Flink));
00828     //ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Blink));
00829 
00830     return NodeFound;
00831 }
00832 
00833 PDPH_HEAP_BLOCK NTAPI
00834 RtlpDphFindAvailableMemory(PDPH_HEAP_ROOT DphRoot,
00835                            SIZE_T Size,
00836                            BOOLEAN Grow)
00837 {
00838     PDPH_HEAP_BLOCK Node;
00839     ULONG NewSize;
00840 
00841     /* Find an available best fitting node */
00842     Node = RtlpDphSearchAvailableMemoryListForBestFit(DphRoot, Size);
00843 
00844     /* If that didn't work, try to search a smaller one in the loop */
00845     while (!Node)
00846     {
00847         /* Break if the free list becomes too small */
00848         if (DphRoot->nFreeAllocations <= DPH_FREE_LIST_MINIMUM) break;
00849 
00850         /* Calculate a new free list size */
00851         NewSize = DphRoot->nFreeAllocations >> 2;
00852         if (NewSize < DPH_FREE_LIST_MINIMUM) NewSize = DPH_FREE_LIST_MINIMUM;
00853 
00854         /* Coalesce free into available */
00855         RtlpDphCoalesceFreeIntoAvailable(DphRoot, NewSize);
00856 
00857         /* Try to find an available best fitting node again */
00858         Node = RtlpDphSearchAvailableMemoryListForBestFit(DphRoot, Size);
00859     }
00860 
00861     /* If Node is NULL, then we could fix the situation only by
00862        growing the available VM size */
00863     if (!Node && Grow)
00864     {
00865         /* Grow VM size, if it fails - return failure directly */
00866         if (!RtlpDphGrowVirtual(DphRoot, Size)) return NULL;
00867 
00868         /* Try to find an available best fitting node again */
00869         Node = RtlpDphSearchAvailableMemoryListForBestFit(DphRoot, Size);
00870 
00871         if (!Node)
00872         {
00873             /* Do the last attempt: coalesce all free into available (if Size fits there) */
00874             if (DphRoot->nFreeAllocationBytesCommitted + DphRoot->nAvailableAllocationBytesCommitted >= Size)
00875             {
00876                 /* Coalesce free into available */
00877                 RtlpDphCoalesceFreeIntoAvailable(DphRoot, 0);
00878 
00879                 /* Try to find an available best fitting node again */
00880                 Node = RtlpDphSearchAvailableMemoryListForBestFit(DphRoot, Size);
00881             }
00882         }
00883     }
00884 
00885     /* Return node we found */
00886     return Node;
00887 }
00888 
00889 PDPH_HEAP_BLOCK NTAPI
00890 RtlpDphFindBusyMemory(PDPH_HEAP_ROOT DphRoot,
00891                       PVOID pUserMem)
00892 {
00893     PDPH_HEAP_BLOCK Node;
00894     PVOID Ptr;
00895 
00896     /* Lookup busy block in AVL */
00897     Ptr = RtlLookupElementGenericTableAvl(&DphRoot->BusyNodesTable, &pUserMem);
00898     if (!Ptr) return NULL;
00899 
00900     /* Restore pointer to the heap block */
00901     Node = CONTAINING_RECORD(Ptr, DPH_HEAP_BLOCK, pUserAllocation);
00902     ASSERT(Node->pUserAllocation == pUserMem);
00903     return Node;
00904 }
00905 
00906 NTSTATUS NTAPI
00907 RtlpDphSetProtectionBeforeUse(PDPH_HEAP_ROOT DphRoot, PUCHAR VirtualBlock, ULONG UserSize)
00908 {
00909     ULONG Protection;
00910     PVOID Base;
00911 
00912     if (DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN)
00913     {
00914         Base = VirtualBlock + PAGE_SIZE;
00915     }
00916     else
00917     {
00918         Base = VirtualBlock;
00919     }
00920 
00921     // FIXME: It should be different, but for now it's fine
00922     Protection = PAGE_READWRITE;
00923 
00924     return RtlpDphProtectVm(Base, UserSize, Protection);
00925 }
00926 
00927 NTSTATUS NTAPI
00928 RtlpDphSetProtectionAfterUse(PDPH_HEAP_ROOT DphRoot, /*PUCHAR VirtualBlock*/PDPH_HEAP_BLOCK Node)
00929 {
00930     ASSERT((Node->nVirtualAccessSize + PAGE_SIZE) <= Node->nVirtualBlockSize);
00931 
00932     // FIXME: Bring stuff here
00933     if (DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN)
00934     {
00935     }
00936     else
00937     {
00938     }
00939 
00940     return STATUS_SUCCESS;
00941 }
00942 
00943 PDPH_HEAP_BLOCK NTAPI
00944 RtlpDphAllocateNode(PDPH_HEAP_ROOT DphRoot)
00945 {
00946     PDPH_HEAP_BLOCK Node;
00947     NTSTATUS Status;
00948     SIZE_T Size = DPH_POOL_SIZE, SizeVirtual;
00949     PVOID Ptr = NULL;
00950 
00951     /* Check for the easy case */
00952     if (DphRoot->pUnusedNodeListHead)
00953     {
00954         /* Just take a node from this list */
00955         Node = RtlpDphTakeNodeFromUnusedList(DphRoot);
00956         ASSERT(Node);
00957         return Node;
00958     }
00959 
00960     /* There is a need to make free space */
00961     Node = RtlpDphFindAvailableMemory(DphRoot, DPH_POOL_SIZE, FALSE);
00962 
00963     if (!DphRoot->pUnusedNodeListHead && !Node)
00964     {
00965         /* Retry with a smaller request */
00966         Size = PAGE_SIZE;
00967         Node = RtlpDphFindAvailableMemory(DphRoot, PAGE_SIZE, FALSE);
00968     }
00969 
00970     if (!DphRoot->pUnusedNodeListHead)
00971     {
00972         if (Node)
00973         {
00974             RtlpDphRemoveFromAvailableList(DphRoot, Node);
00975             Ptr = Node->pVirtualBlock;
00976             SizeVirtual = Node->nVirtualBlockSize;
00977         }
00978         else
00979         {
00980             /* No free space, need to alloc a new VM block */
00981             Size = DPH_POOL_SIZE;
00982             SizeVirtual = DPH_RESERVE_SIZE;
00983             Status = RtlpDphAllocateVm(&Ptr, SizeVirtual, MEM_COMMIT, PAGE_NOACCESS);
00984 
00985             if (!NT_SUCCESS(Status))
00986             {
00987                 /* Retry with a smaller size */
00988                 SizeVirtual = 0x10000;
00989                 Status = RtlpDphAllocateVm(&Ptr, SizeVirtual, MEM_COMMIT, PAGE_NOACCESS);
00990                 if (!NT_SUCCESS(Status)) return NULL;
00991             }
00992         }
00993 
00994         /* VM is allocated at this point, set protection */
00995         Status = RtlpDphProtectVm(Ptr, Size, PAGE_READWRITE);
00996         if (!NT_SUCCESS(Status))
00997         {
00998             if (Node)
00999             {
01000                 RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node);
01001             }
01002             else
01003             {
01004                 //RtlpDphFreeVm();
01005                 ASSERT(FALSE);
01006             }
01007 
01008             return NULL;
01009         }
01010 
01011         /* Zero the memory */
01012         if (Node) RtlZeroMemory(Ptr, Size);
01013 
01014         /* Add a new pool based on this VM */
01015         RtlpDphAddNewPool(DphRoot, Node, Ptr, Size, TRUE);
01016 
01017         if (Node)
01018         {
01019             if (Node->nVirtualBlockSize > Size)
01020             {
01021                 Node->pVirtualBlock += Size;
01022                 Node->nVirtualBlockSize -= Size;
01023 
01024                 RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node);
01025             }
01026             else
01027             {
01028                 RtlpDphReturnNodeToUnusedList(DphRoot, Node);
01029             }
01030         }
01031         else
01032         {
01033             /* The new VM block was just allocated a few code lines ago,
01034                so initialize it */
01035             Node = RtlpDphTakeNodeFromUnusedList(DphRoot);
01036             Node->pVirtualBlock = Ptr;
01037             Node->nVirtualBlockSize = SizeVirtual;
01038             RtlpDphPlaceOnVirtualList(DphRoot, Node);
01039 
01040             Node = RtlpDphTakeNodeFromUnusedList(DphRoot);
01041             Node->pVirtualBlock = (PUCHAR)Ptr + Size;
01042             Node->nVirtualBlockSize = SizeVirtual - Size;
01043             RtlpDphPlaceOnVirtualList(DphRoot, Node);
01044 
01045             /* Coalesce them into available list */
01046             RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node);
01047         }
01048     }
01049 
01050     return RtlpDphTakeNodeFromUnusedList(DphRoot);
01051 }
01052 
01053 BOOLEAN NTAPI
01054 RtlpDphGrowVirtual(PDPH_HEAP_ROOT DphRoot,
01055                    SIZE_T Size)
01056 {
01057     PDPH_HEAP_BLOCK Node, AvailableNode;
01058     PVOID Base = NULL;
01059     SIZE_T VirtualSize;
01060     NTSTATUS Status;
01061 
01062     /* Start with allocating a couple of nodes */
01063     Node = RtlpDphAllocateNode(DphRoot);
01064     if (!Node) return FALSE;
01065 
01066     AvailableNode = RtlpDphAllocateNode(DphRoot);
01067     if (!AvailableNode)
01068     {
01069         /* Free the allocated node and return failure */
01070         RtlpDphReturnNodeToUnusedList(DphRoot, Node);
01071         return FALSE;
01072     }
01073 
01074     /* Calculate size of VM to allocate by rounding it up */
01075     Size = ROUND_UP(Size, 0xFFFF);
01076     VirtualSize = Size;
01077     if (Size < DPH_RESERVE_SIZE)
01078         VirtualSize = DPH_RESERVE_SIZE;
01079 
01080     /* Allocate the virtual memory */
01081     // FIXME: Shouldn't it be MEM_RESERVE with later committing?
01082     Status = RtlpDphAllocateVm(&Base, VirtualSize, MEM_COMMIT, PAGE_NOACCESS);
01083     if (!NT_SUCCESS(Status))
01084     {
01085         /* Retry again with a smaller size */
01086         VirtualSize = Size;
01087         Status = RtlpDphAllocateVm(&Base, VirtualSize, MEM_COMMIT, PAGE_NOACCESS);
01088         if (!NT_SUCCESS(Status))
01089         {
01090             /* Free the allocated node and return failure */
01091             RtlpDphReturnNodeToUnusedList(DphRoot, Node);
01092             RtlpDphReturnNodeToUnusedList(DphRoot, AvailableNode);
01093             return FALSE;
01094         }
01095     }
01096 
01097     /* Set up our two nodes describing this VM */
01098     Node->pVirtualBlock = Base;
01099     Node->nVirtualBlockSize = VirtualSize;
01100     AvailableNode->pVirtualBlock = Base;
01101     AvailableNode->nVirtualBlockSize = VirtualSize;
01102 
01103     /* Add them to virtual and available lists respectively */
01104     RtlpDphPlaceOnVirtualList(DphRoot, Node);
01105     RtlpDphCoalesceNodeIntoAvailable(DphRoot, AvailableNode);
01106 
01107     /* Return success */
01108     return TRUE;
01109 }
01110 
01111 RTL_GENERIC_COMPARE_RESULTS
01112 NTAPI
01113 RtlpDphCompareNodeForTable(IN PRTL_AVL_TABLE Table,
01114                            IN PVOID FirstStruct,
01115                            IN PVOID SecondStruct)
01116 {
01117     ULONG_PTR FirstBlock, SecondBlock;
01118 
01119     FirstBlock = *((ULONG_PTR *)FirstStruct);
01120     SecondBlock = *((ULONG_PTR *)SecondStruct);
01121 
01122     if (FirstBlock < SecondBlock)
01123         return GenericLessThan;
01124     else if (FirstBlock > SecondBlock)
01125         return GenericGreaterThan;
01126 
01127     return GenericEqual;
01128 }
01129 
01130 PVOID
01131 NTAPI
01132 RtlpDphAllocateNodeForTable(IN PRTL_AVL_TABLE Table,
01133                             IN CLONG ByteSize)
01134 {
01135     PDPH_HEAP_BLOCK pBlock;
01136     PDPH_HEAP_ROOT DphRoot;
01137 
01138     /* This mega-assert comes from a text search over Windows 2003 checked binary of ntdll.dll */
01139     ASSERT((ULONG_PTR)(((PRTL_BALANCED_LINKS)0)+1) + sizeof(PUCHAR) == ByteSize);
01140 
01141     /* Get pointer to the containing heap root record */
01142     DphRoot = CONTAINING_RECORD(Table, DPH_HEAP_ROOT, BusyNodesTable);
01143     pBlock = DphRoot->NodeToAllocate;
01144 
01145     DphRoot->NodeToAllocate = NULL;
01146     ASSERT(pBlock);
01147 
01148     return &(pBlock->TableLinks);
01149 }
01150 
01151 VOID
01152 NTAPI
01153 RtlpDphFreeNodeForTable(IN PRTL_AVL_TABLE Table,
01154                         IN PVOID Buffer)
01155 {
01156     /* Nothing */
01157 }
01158 
01159 NTSTATUS NTAPI
01160 RtlpDphInitializeDelayedFreeQueue()
01161 {
01162     NTSTATUS Status;
01163 
01164     Status = RtlInitializeCriticalSection(&RtlpDphDelayedFreeQueueLock);
01165     if (!NT_SUCCESS(Status))
01166     {
01167         // TODO: Log this error!
01168         DPRINT1("Failure initializing delayed free queue critical section\n");
01169         return Status;
01170     }
01171 
01172     /* Initialize lists */
01173     InitializeListHead(&RtlpDphDelayedFreeQueue);
01174     RtlInitializeSListHead(&RtlpDphDelayedTemporaryPushList);
01175 
01176     /* Reset counters */
01177     RtlpDphMemoryUsedByDelayedFreeBlocks = 0;
01178     RtlpDphNumberOfDelayedFreeBlocks = 0;
01179 
01180     return Status;
01181 }
01182 
01183 VOID NTAPI
01184 RtlpDphFreeDelayedBlocksFromHeap(PDPH_HEAP_ROOT DphRoot,
01185                                  PHEAP NormalHeap)
01186 {
01187     PLIST_ENTRY Current, Next;
01188     PDPH_BLOCK_INFORMATION BlockInfo;
01189     ULONG ValidationInfo;
01190 
01191     /* The original routine seems to use a temporary SList to put blocks to be freed,
01192        then it releases the lock and frees the blocks. But let's make it simple for now */
01193 
01194     /* Acquire the delayed free queue lock */
01195     RtlEnterCriticalSection(&RtlpDphDelayedFreeQueueLock);
01196 
01197     /* Traverse the list */
01198     Current = RtlpDphDelayedFreeQueue.Flink;
01199     while (Current != &RtlpDphDelayedFreeQueue)
01200     {
01201         /* Get the next entry pointer */
01202         Next = Current->Flink;
01203 
01204         BlockInfo = CONTAINING_RECORD(Current, DPH_BLOCK_INFORMATION, FreeQueue);
01205 
01206         /* Check if it belongs to the same heap */
01207         if (BlockInfo->Heap == DphRoot)
01208         {
01209             /* Remove it from the list */
01210             RemoveEntryList(Current);
01211 
01212             /* Reset its heap to NULL */
01213             BlockInfo->Heap = NULL;
01214 
01215             if (!RtlpDphIsNormalFreeHeapBlock(BlockInfo + 1, &ValidationInfo, TRUE))
01216             {
01217                 RtlpDphReportCorruptedBlock(DphRoot, 10, BlockInfo + 1, ValidationInfo);
01218             }
01219 
01220             /* Decrement counters */
01221             RtlpDphMemoryUsedByDelayedFreeBlocks -= BlockInfo->ActualSize;
01222             RtlpDphNumberOfDelayedFreeBlocks--;
01223 
01224             /* Free the normal heap */
01225             RtlFreeHeap (NormalHeap, 0, BlockInfo);
01226         }
01227 
01228         /* Move to the next one */
01229         Current = Next;
01230     }
01231 
01232     /* Release the delayed free queue lock */
01233     RtlLeaveCriticalSection(&RtlpDphDelayedFreeQueueLock);
01234 }
01235 
01236 NTSTATUS NTAPI
01237 RtlpDphTargetDllsLogicInitialize()
01238 {
01239     UNIMPLEMENTED;
01240     return STATUS_SUCCESS;
01241 }
01242 
01243 VOID NTAPI
01244 RtlpDphInternalValidatePageHeap(PDPH_HEAP_ROOT DphRoot, PVOID Address, ULONG Value)
01245 {
01246     UNIMPLEMENTED;
01247 }
01248 
01249 VOID NTAPI
01250 RtlpDphVerifyIntegrity(PDPH_HEAP_ROOT DphRoot)
01251 {
01252     UNIMPLEMENTED;
01253 }
01254 
01255 VOID NTAPI
01256 RtlpDphReportCorruptedBlock(PDPH_HEAP_ROOT DphRoot,
01257                             ULONG Reserved,
01258                             PVOID Block,
01259                             ULONG ValidationInfo)
01260 {
01261     //RtlpDphGetBlockSizeFromCorruptedBlock();
01262 
01263     if (ValidationInfo & DPH_VALINFO_CORRUPTED_AFTER_FREE)
01264     {
01265         DPRINT1("block corrupted after having been freed\n");
01266     }
01267 
01268     if (ValidationInfo & DPH_VALINFO_ALREADY_FREED)
01269     {
01270         DPRINT1("block already freed\n");
01271     }
01272 
01273     if (ValidationInfo & DPH_VALINFO_BAD_INFIX_PATTERN)
01274     {
01275         DPRINT1("corrupted infix pattern for freed block\n");
01276     }
01277 
01278     if (ValidationInfo & DPH_VALINFO_BAD_POINTER)
01279     {
01280         DPRINT1("corrupted heap pointer or using wrong heap\n");
01281     }
01282 
01283     if (ValidationInfo & DPH_VALINFO_BAD_SUFFIX_PATTERN)
01284     {
01285         DPRINT1("corrupted suffix pattern\n");
01286     }
01287 
01288     if (ValidationInfo & DPH_VALINFO_BAD_PREFIX_PATTERN)
01289     {
01290         DPRINT1("corrupted prefix pattern\n");
01291     }
01292 
01293     if (ValidationInfo & DPH_VALINFO_BAD_START_STAMP)
01294     {
01295         DPRINT1("corrupted start stamp\n");
01296     }
01297 
01298     if (ValidationInfo & DPH_VALINFO_BAD_END_STAMP)
01299     {
01300         DPRINT1("corrupted end stamp\n");
01301     }
01302 
01303     if (ValidationInfo & DPH_VALINFO_EXCEPTION)
01304     {
01305         DPRINT1("exception raised while verifying block\n");
01306     }
01307 
01308     DPRINT1("Corrupted heap block %p\n", Block);
01309 }
01310 
01311 BOOLEAN NTAPI
01312 RtlpDphIsPageHeapBlock(PDPH_HEAP_ROOT DphRoot,
01313                        PVOID Block,
01314                        PULONG ValidationInformation,
01315                        BOOLEAN CheckFillers)
01316 {
01317     PDPH_BLOCK_INFORMATION BlockInfo;
01318     BOOLEAN SomethingWrong = FALSE;
01319     PUCHAR Byte, Start, End;
01320 
01321     ASSERT(ValidationInformation != NULL);
01322     *ValidationInformation = 0;
01323 
01324     // _SEH2_TRY {
01325     BlockInfo = (PDPH_BLOCK_INFORMATION)Block - 1;
01326 
01327     /* Check stamps */
01328     if (BlockInfo->StartStamp != DPH_FILL_START_STAMP_1)
01329     {
01330         *ValidationInformation |= DPH_VALINFO_BAD_START_STAMP;
01331         SomethingWrong = TRUE;
01332 
01333         /* Check if it has an alloc/free mismatch */
01334         if (BlockInfo->StartStamp == DPH_FILL_START_STAMP_2)
01335         {
01336             /* Notify respectively */
01337             *ValidationInformation = 0x101;
01338         }
01339     }
01340 
01341     if (BlockInfo->EndStamp != DPH_FILL_END_STAMP_1)
01342     {
01343         *ValidationInformation |= DPH_VALINFO_BAD_END_STAMP;
01344         SomethingWrong = TRUE;
01345     }
01346 
01347     /* Check root heap pointer */
01348     if (BlockInfo->Heap != DphRoot)
01349     {
01350         *ValidationInformation |= DPH_VALINFO_BAD_POINTER;
01351         SomethingWrong = TRUE;
01352     }
01353 
01354     /* Check other fillers if requested */
01355     if (CheckFillers)
01356     {
01357         /* Check space after the block */
01358         Start = (PUCHAR)Block + BlockInfo->RequestedSize;
01359         End = (PUCHAR)ROUND_UP(Start, PAGE_SIZE);
01360         for (Byte = Start; Byte < End; Byte++)
01361         {
01362             if (*Byte != DPH_FILL_SUFFIX)
01363             {
01364                 *ValidationInformation |= DPH_VALINFO_BAD_SUFFIX_PATTERN;
01365                 SomethingWrong = TRUE;
01366                 break;
01367             }
01368         }
01369     }
01370 
01371     return (SomethingWrong == FALSE);
01372 }
01373 
01374 BOOLEAN NTAPI
01375 RtlpDphIsNormalFreeHeapBlock(PVOID Block,
01376                              PULONG ValidationInformation,
01377                              BOOLEAN CheckFillers)
01378 {
01379     ASSERT(ValidationInformation != NULL);
01380 
01381     UNIMPLEMENTED;
01382     *ValidationInformation = 0;
01383     return TRUE;
01384 }
01385 
01386 NTSTATUS NTAPI
01387 RtlpDphProcessStartupInitialization()
01388 {
01389     NTSTATUS Status;
01390     PTEB Teb = NtCurrentTeb();
01391 
01392     /* Initialize the DPH heap list and its critical section */
01393     InitializeListHead(&RtlpDphPageHeapList);
01394     Status = RtlInitializeCriticalSection(&RtlpDphPageHeapListLock);
01395     if (!NT_SUCCESS(Status))
01396     {
01397         ASSERT(FALSE);
01398         return Status;
01399     }
01400 
01401     /* Initialize delayed-free queue */
01402     Status = RtlpDphInitializeDelayedFreeQueue();
01403     if (!NT_SUCCESS(Status)) return Status;
01404 
01405     /* Initialize the target dlls string */
01406     RtlInitUnicodeString(&RtlpDphTargetDllsUnicode, RtlpDphTargetDlls);
01407     Status = RtlpDphTargetDllsLogicInitialize();
01408 
01409     /* Per-process DPH init is done */
01410     RtlpDphPageHeapListInitialized = TRUE;
01411 
01412     DPRINT1("Page heap: pid 0x%X: page heap enabled with flags 0x%X.\n", Teb->ClientId.UniqueProcess, RtlpDphGlobalFlags);
01413 
01414     return Status;
01415 }
01416 
01417 BOOLEAN NTAPI
01418 RtlpDphShouldAllocateInPageHeap(PDPH_HEAP_ROOT DphRoot,
01419                                 SIZE_T Size)
01420 {
01421     //UNIMPLEMENTED;
01422     /* Always use page heap for now */
01423     return TRUE;
01424 }
01425 
01426 HANDLE NTAPI
01427 RtlpPageHeapCreate(ULONG Flags,
01428                    PVOID Addr,
01429                    SIZE_T TotalSize,
01430                    SIZE_T CommitSize,
01431                    PVOID Lock,
01432                    PRTL_HEAP_PARAMETERS Parameters)
01433 {
01434     PVOID Base = NULL;
01435     PHEAP HeapPtr;
01436     PDPH_HEAP_ROOT DphRoot;
01437     PDPH_HEAP_BLOCK DphNode;
01438     ULONG MemSize;
01439     NTSTATUS Status;
01440     LARGE_INTEGER PerfCounter;
01441 
01442     /* Check for a DPH bypass flag */
01443     if ((ULONG_PTR)Parameters == -1) return NULL;
01444 
01445     /* Make sure no user-allocated stuff was provided */
01446     if (Addr || Lock) return NULL;
01447 
01448     /* Allocate minimum amount of virtual memory */
01449     MemSize = DPH_RESERVE_SIZE;
01450     Status = RtlpDphAllocateVm(&Base, MemSize, MEM_COMMIT, PAGE_NOACCESS);
01451     if (!NT_SUCCESS(Status))
01452     {
01453         ASSERT(FALSE);
01454         return NULL;
01455     }
01456 
01457     /* Set protection */
01458     Status = RtlpDphProtectVm(Base, 2*PAGE_SIZE + DPH_POOL_SIZE, PAGE_READWRITE);
01459     if (!NT_SUCCESS(Status))
01460     {
01461         //RtlpDphFreeVm(Base, 0, 0, 0);
01462         ASSERT(FALSE);
01463         return NULL;
01464     }
01465 
01466     /* Start preparing the 1st page. Fill it with the default filler */
01467     RtlFillMemoryUlong(Base, PAGE_SIZE, DPH_FILL);
01468 
01469     /* Set flags in the "HEAP" structure */
01470     HeapPtr = (PHEAP)Base;
01471     HeapPtr->Flags = Flags | HEAP_FLAG_PAGE_ALLOCS;
01472     HeapPtr->ForceFlags = Flags | HEAP_FLAG_PAGE_ALLOCS;
01473 
01474     /* Set 1st page to read only now */
01475     Status = RtlpDphProtectVm(Base, PAGE_SIZE, PAGE_READONLY);
01476     if (!NT_SUCCESS(Status))
01477     {
01478         ASSERT(FALSE);
01479         return NULL;
01480     }
01481 
01482     /* 2nd page is the real DPH root block */
01483     DphRoot = (PDPH_HEAP_ROOT)((PCHAR)Base + PAGE_SIZE);
01484 
01485     /* Initialize the DPH root */
01486     DphRoot->Signature = DPH_SIGNATURE;
01487     DphRoot->HeapFlags = Flags;
01488     DphRoot->HeapCritSect = (PRTL_CRITICAL_SECTION)((PCHAR)DphRoot + DPH_POOL_SIZE);
01489     DphRoot->ExtraFlags = RtlpDphGlobalFlags;
01490 
01491     ZwQueryPerformanceCounter(&PerfCounter, NULL);
01492     DphRoot->Seed = PerfCounter.LowPart;
01493 
01494     RtlInitializeCriticalSection(DphRoot->HeapCritSect);
01495     InitializeListHead(&DphRoot->AvailableAllocationHead);
01496 
01497     /* Create a normal heap for this paged heap */
01498     DphRoot->NormalHeap = RtlCreateHeap(Flags, NULL, TotalSize, CommitSize, NULL, (PRTL_HEAP_PARAMETERS)-1);
01499     if (!DphRoot->NormalHeap)
01500     {
01501         ASSERT(FALSE);
01502         return NULL;
01503     }
01504 
01505     /* 3rd page: a pool for DPH allocations */
01506     RtlpDphAddNewPool(DphRoot, NULL, DphRoot + 1, DPH_POOL_SIZE - sizeof(DPH_HEAP_ROOT), FALSE);
01507 
01508     /* Allocate internal heap blocks. For the root */
01509     DphNode = RtlpDphAllocateNode(DphRoot);
01510     ASSERT(DphNode != NULL);
01511     DphNode->pVirtualBlock = (PUCHAR)DphRoot;
01512     DphNode->nVirtualBlockSize = DPH_POOL_SIZE;
01513     RtlpDphPlaceOnPoolList(DphRoot, DphNode);
01514 
01515     /* For the memory we allocated as a whole */
01516     DphNode = RtlpDphAllocateNode(DphRoot);
01517     ASSERT(DphNode != NULL);
01518     DphNode->pVirtualBlock = Base;
01519     DphNode->nVirtualBlockSize = MemSize;
01520     RtlpDphPlaceOnVirtualList(DphRoot, DphNode);
01521 
01522     /* For the remaining part */
01523     DphNode = RtlpDphAllocateNode(DphRoot);
01524     ASSERT(DphNode != NULL);
01525     DphNode->pVirtualBlock = (PUCHAR)Base + 2*PAGE_SIZE + DPH_POOL_SIZE;
01526     DphNode->nVirtualBlockSize = MemSize - (2*PAGE_SIZE + DPH_POOL_SIZE);
01527     RtlpDphCoalesceNodeIntoAvailable(DphRoot, DphNode);
01528 
01529     //DphRoot->CreateStackTrace = RtlpDphLogStackTrace(1);
01530 
01531     /* Initialize AVL-based busy nodes table */
01532     RtlInitializeGenericTableAvl(&DphRoot->BusyNodesTable,
01533                                  RtlpDphCompareNodeForTable,
01534                                  RtlpDphAllocateNodeForTable,
01535                                  RtlpDphFreeNodeForTable,
01536                                  NULL);
01537 
01538     /* Initialize per-process startup info */
01539     if (!RtlpDphPageHeapListInitialized) RtlpDphProcessStartupInitialization();
01540 
01541     /* Acquire the heap list lock */
01542     RtlEnterCriticalSection(&RtlpDphPageHeapListLock);
01543 
01544     /* Insert this heap to the tail of the global list */
01545     InsertTailList(&RtlpDphPageHeapList, &DphRoot->NextHeap);
01546 
01547     /* Note we increased the size of the list */
01548     RtlpDphPageHeapListLength++;
01549 
01550     /* Release the heap list lock */
01551     RtlLeaveCriticalSection(&RtlpDphPageHeapListLock);
01552 
01553     if (RtlpDphDebugOptions & DPH_DEBUG_VERBOSE)
01554     {
01555         DPRINT1("Page heap: process 0x%X created heap @ %p (%p, flags 0x%X)\n",
01556             NtCurrentTeb()->ClientId.UniqueProcess, (PUCHAR)DphRoot - PAGE_SIZE, DphRoot->NormalHeap, DphRoot->ExtraFlags);
01557     }
01558 
01559     /* Perform internal validation if required */
01560     if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE)
01561         RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0);
01562 
01563     return (PUCHAR)DphRoot - PAGE_SIZE;
01564 }
01565 
01566 PVOID NTAPI
01567 RtlpPageHeapDestroy(HANDLE HeapPtr)
01568 {
01569     PDPH_HEAP_ROOT DphRoot;
01570     PDPH_HEAP_BLOCK Node, Next;
01571     PHEAP NormalHeap;
01572     ULONG Value;
01573 
01574     /* Check if it's not a process heap */
01575     if (HeapPtr == RtlGetProcessHeap())
01576     {
01577         DbgBreakPoint();
01578         return NULL;
01579     }
01580 
01581     /* Get pointer to the heap root */
01582     DphRoot = RtlpDphPointerFromHandle(HeapPtr);
01583     if (!DphRoot) return NULL;
01584 
01585     RtlpDphPreProcessing(DphRoot, DphRoot->HeapFlags);
01586 
01587     /* Get the pointer to the normal heap */
01588     NormalHeap = DphRoot->NormalHeap;
01589 
01590     /* Free the delayed-free blocks */
01591     RtlpDphFreeDelayedBlocksFromHeap(DphRoot, NormalHeap);
01592 
01593     /* Go through the busy blocks */
01594     Node = RtlEnumerateGenericTableAvl(&DphRoot->BusyNodesTable, TRUE);
01595 
01596     while (Node)
01597     {
01598         if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN))
01599         {
01600             if (!RtlpDphIsPageHeapBlock(DphRoot, Node->pUserAllocation, &Value, TRUE))
01601             {
01602                 RtlpDphReportCorruptedBlock(DphRoot, 3, Node->pUserAllocation, Value);
01603             }
01604         }
01605 
01606         /* FIXME: Call AV notification */
01607         //AVrfInternalHeapFreeNotification();
01608 
01609         /* Go to the next node */
01610         Node = RtlEnumerateGenericTableAvl(&DphRoot->BusyNodesTable, FALSE);
01611     }
01612 
01613     /* Acquire the global heap list lock */
01614     RtlEnterCriticalSection(&RtlpDphPageHeapListLock);
01615 
01616     /* Remove the entry and decrement the global counter */
01617     RemoveEntryList(&DphRoot->NextHeap);
01618     RtlpDphPageHeapListLength--;
01619 
01620     /* Release the global heap list lock */
01621     RtlLeaveCriticalSection(&RtlpDphPageHeapListLock);
01622 
01623     /* Leave and delete this heap's critical section */
01624     RtlLeaveCriticalSection(DphRoot->HeapCritSect);
01625     RtlDeleteCriticalSection(DphRoot->HeapCritSect);
01626 
01627     /* Now go through all virtual list nodes and release the VM */
01628     Node = DphRoot->pVirtualStorageListHead;
01629     while (Node)
01630     {
01631         Next = Node->pNextAlloc;
01632         /* Release the memory without checking result */
01633         RtlpDphFreeVm(Node->pVirtualBlock, 0, MEM_RELEASE);
01634         Node = Next;
01635     }
01636 
01637     /* Destroy the normal heap */
01638     RtlDestroyHeap(NormalHeap);
01639 
01640     /* Report success */
01641     if (RtlpDphDebugOptions & DPH_DEBUG_VERBOSE)
01642         DPRINT1("Page heap: process 0x%X destroyed heap @ %p (%p)\n", NtCurrentTeb()->ClientId.UniqueProcess, HeapPtr, NormalHeap);
01643 
01644     return NULL;
01645 }
01646 
01647 PVOID NTAPI
01648 RtlpPageHeapAllocate(IN PVOID HeapPtr,
01649                      IN ULONG Flags,
01650                      IN SIZE_T Size)
01651 {
01652     PDPH_HEAP_ROOT DphRoot;
01653     PDPH_HEAP_BLOCK AvailableNode, BusyNode;
01654     BOOLEAN Biased = FALSE;
01655     ULONG AllocateSize, AccessSize;
01656     NTSTATUS Status;
01657     SIZE_T UserActualSize;
01658     PVOID Ptr;
01659 
01660     /* Check requested size */
01661     if (Size > 0x7FF00000)
01662     {
01663         DPRINT1("extreme size request\n");
01664 
01665         /* Generate an exception if needed */
01666         if (Flags & HEAP_GENERATE_EXCEPTIONS) RtlpDphRaiseException(STATUS_NO_MEMORY);
01667 
01668         return NULL;
01669     }
01670 
01671     /* Unbias the pointer if necessary */
01672     if (IS_BIASED_POINTER(HeapPtr))
01673     {
01674         HeapPtr = (PVOID)POINTER_REMOVE_BIAS(HeapPtr);
01675         Biased = TRUE;
01676     }
01677 
01678     /* Get a pointer to the heap root */
01679     DphRoot = RtlpDphPointerFromHandle(HeapPtr);
01680     if (!DphRoot) return NULL;
01681 
01682     /* Acquire the heap lock */
01683     RtlpDphPreProcessing(DphRoot, Flags);
01684 
01685     /* Perform internal validation if specified by flags */
01686     if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE && !Biased)
01687     {
01688         RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0);
01689     }
01690 
01691     /* Add heap flags */
01692     Flags |= DphRoot->HeapFlags;
01693 
01694     if (!Biased && !RtlpDphShouldAllocateInPageHeap(DphRoot, Size))
01695     {
01696         /* Perform allocation from a normal heap */
01697         ASSERT(FALSE);
01698     }
01699 
01700     /* Perform heap integrity check if specified by flags */
01701     if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE)
01702     {
01703         RtlpDphVerifyIntegrity(DphRoot);
01704     }
01705 
01706     /* Calculate sizes */
01707     AccessSize = ROUND_UP(Size + sizeof(DPH_BLOCK_INFORMATION), PAGE_SIZE);
01708     AllocateSize = AccessSize + PAGE_SIZE;
01709 
01710     // FIXME: Move RtlpDphAllocateNode(DphRoot) to this place
01711     AvailableNode = RtlpDphFindAvailableMemory(DphRoot, AllocateSize, TRUE);
01712     if (!AvailableNode)
01713     {
01714         DPRINT1("Page heap: Unable to allocate virtual memory\n");
01715         DbgBreakPoint();
01716 
01717         /* Release the lock */
01718         RtlpDphPostProcessing(DphRoot);
01719 
01720         return NULL;
01721     }
01722     ASSERT(AvailableNode->nVirtualBlockSize >= AllocateSize);
01723 
01724     /* Set protection */
01725     Status = RtlpDphSetProtectionBeforeUse(DphRoot,
01726                                            AvailableNode->pVirtualBlock,
01727                                            AccessSize);
01728     if (!NT_SUCCESS(Status))
01729     {
01730         ASSERT(FALSE);
01731     }
01732 
01733     /* Save available node pointer */
01734     Ptr = AvailableNode->pVirtualBlock;
01735 
01736     /* Check node's size */
01737     if (AvailableNode->nVirtualBlockSize > AllocateSize)
01738     {
01739         /* The block contains too much free space, reduce it */
01740         AvailableNode->pVirtualBlock += AllocateSize;
01741         AvailableNode->nVirtualBlockSize -= AllocateSize;
01742         DphRoot->nAvailableAllocationBytesCommitted -= AllocateSize;
01743 
01744         /* Allocate a new node which will be our busy node */
01745         BusyNode = RtlpDphAllocateNode(DphRoot);
01746         ASSERT(BusyNode != NULL);
01747         BusyNode->pVirtualBlock = Ptr;
01748         BusyNode->nVirtualBlockSize = AllocateSize;
01749     }
01750     else
01751     {
01752         /* The block's size fits exactly */
01753         RtlpDphRemoveFromAvailableList(DphRoot, AvailableNode);
01754         BusyNode = AvailableNode;
01755     }
01756 
01757     /* Calculate actual user size  */
01758     if (DphRoot->HeapFlags & HEAP_NO_ALIGNMENT)
01759         UserActualSize = Size;
01760     else
01761         UserActualSize = ROUND_UP(Size, 8);
01762 
01763     /* Set up the block */
01764     BusyNode->nVirtualAccessSize = AccessSize;
01765     BusyNode->nUserActualSize = UserActualSize;
01766     BusyNode->nUserRequestedSize = Size;
01767 
01768     if (DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN)
01769         BusyNode->pUserAllocation = BusyNode->pVirtualBlock + PAGE_SIZE;
01770     else
01771         BusyNode->pUserAllocation = BusyNode->pVirtualBlock + BusyNode->nVirtualAccessSize - UserActualSize;
01772 
01773     BusyNode->UserValue = NULL;
01774     BusyNode->UserFlags = Flags & HEAP_SETTABLE_USER_FLAGS;
01775 
01776     // FIXME: Don't forget about stack traces if such flag was set
01777     BusyNode->StackTrace = NULL;
01778 
01779     /* Place it on busy list */
01780     RtlpDphPlaceOnBusyList(DphRoot, BusyNode);
01781 
01782     /* Zero or patter-fill memory depending on flags */
01783     if (Flags & HEAP_ZERO_MEMORY)
01784         RtlZeroMemory(BusyNode->pUserAllocation, Size);
01785     else
01786         RtlFillMemory(BusyNode->pUserAllocation, Size, DPH_FILL_INFIX);
01787 
01788     /* Write DPH info */
01789     if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN))
01790     {
01791         RtlpDphWritePageHeapBlockInformation(DphRoot,
01792                                              BusyNode->pUserAllocation,
01793                                              Size,
01794                                              AccessSize);
01795     }
01796 
01797     /* Finally allocation is done, perform validation again if required */
01798     if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE && !Biased)
01799     {
01800         RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0);
01801     }
01802 
01803     /* Release the lock */
01804     RtlpDphPostProcessing(DphRoot);
01805 
01806     DPRINT("Allocated user block pointer: %p\n", BusyNode->pUserAllocation);
01807 
01808     /* Return pointer to user allocation */
01809     return BusyNode->pUserAllocation;
01810 }
01811 
01812 BOOLEAN NTAPI
01813 RtlpPageHeapFree(HANDLE HeapPtr,
01814                  ULONG Flags,
01815                  PVOID Ptr)
01816 {
01817     PDPH_HEAP_ROOT DphRoot;
01818     PDPH_HEAP_BLOCK Node;
01819     ULONG ValidationInfo;
01820     PDPH_BLOCK_INFORMATION Info;
01821 
01822     /* Check for a NULL pointer freeing */
01823     if (!Ptr)
01824     {
01825         if (RtlpDphBreakOptions & DPH_BREAK_ON_NULL_FREE)
01826         {
01827             DPRINT1("Page heap: freeing a null pointer \n");
01828             DbgBreakPoint();
01829         }
01830         return TRUE;
01831     }
01832 
01833     /* Get a pointer to the heap root */
01834     DphRoot = RtlpDphPointerFromHandle(HeapPtr);
01835     if (!DphRoot) return FALSE;
01836 
01837     /* Acquire the heap lock */
01838     RtlpDphPreProcessing(DphRoot, Flags);
01839 
01840     /* Perform internal validation if specified by flags */
01841     if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE)
01842         RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0);
01843 
01844     /* Add heap flags */
01845     Flags |= DphRoot->HeapFlags;
01846 
01847     /* Find busy memory */
01848     Node = RtlpDphFindBusyMemory(DphRoot, Ptr);
01849 
01850     if (!Node)
01851     {
01852         /* This block was not found in page heap, try a normal heap instead */
01853         //RtlpDphNormalHeapFree();
01854         ASSERT(FALSE);
01855     }
01856 
01857     if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN))
01858     {
01859         /* Check and report corrupted block */
01860         if (!RtlpDphIsPageHeapBlock(DphRoot, Ptr, &ValidationInfo, TRUE))
01861         {
01862             RtlpDphReportCorruptedBlock(DphRoot, 1, Ptr, ValidationInfo);
01863         }
01864 
01865         // FIXME: Should go inside RtlpDphSetProtectionAfterUse
01866         if (Node->nVirtualAccessSize != 0)
01867         {
01868             /* Set stamps */
01869             Info = (PDPH_BLOCK_INFORMATION)Node->pUserAllocation - 1;
01870             Info->StartStamp = DPH_FILL_START_STAMP_2;
01871             Info->EndStamp = DPH_FILL_END_STAMP_2;
01872 
01873             RtlpDphProtectVm(Node->pVirtualBlock, Node->nVirtualAccessSize, PAGE_NOACCESS);
01874         }
01875     }
01876     else
01877     {
01878         // FIXME: Should go inside RtlpDphSetProtectionAfterUse
01879         if (Node->nVirtualAccessSize != 0)
01880             RtlpDphProtectVm(Node->pVirtualBlock + PAGE_SIZE, Node->nVirtualAccessSize, PAGE_NOACCESS);
01881     }
01882 
01883     /* Set new protection */
01884     //RtlpDphSetProtectionAfterUse(DphRoot, Node);
01885 
01886     /* Remove it from the list of busy nodes */
01887     RtlpDphRemoveFromBusyList(DphRoot, Node);
01888 
01889     /* And put it into the list of free nodes */
01890     RtlpDphPlaceOnFreeList(DphRoot, Node);
01891 
01892     //if (DphRoot->ExtraFlags & DPH_EXTRA_LOG_STACK_TRACES)
01893     //    Node->StackTrace = RtlpDphLogStackTrace(3);
01894     //else
01895         Node->StackTrace = NULL;
01896 
01897     /* Leave the heap lock */
01898     RtlpDphPostProcessing(DphRoot);
01899 
01900     /* Return success */
01901     return TRUE;
01902 }
01903 
01904 PVOID NTAPI
01905 RtlpPageHeapReAllocate(HANDLE HeapPtr,
01906                        ULONG Flags,
01907                        PVOID Ptr,
01908                        SIZE_T Size)
01909 {
01910     PDPH_HEAP_ROOT DphRoot;
01911     PDPH_HEAP_BLOCK Node = NULL, AllocatedNode;
01912     BOOLEAN Biased = FALSE, UseNormalHeap = FALSE, OldBlockPageHeap = TRUE;
01913     ULONG ValidationInfo;
01914     SIZE_T DataSize;
01915     PVOID NewAlloc = NULL;
01916 
01917     /* Check requested size */
01918     if (Size > 0x7FF00000)
01919     {
01920         DPRINT1("extreme size request\n");
01921 
01922         /* Generate an exception if needed */
01923         if (Flags & HEAP_GENERATE_EXCEPTIONS) RtlpDphRaiseException(STATUS_NO_MEMORY);
01924 
01925         return NULL;
01926     }
01927 
01928     /* Unbias the pointer if necessary */
01929     if (IS_BIASED_POINTER(HeapPtr))
01930     {
01931         HeapPtr = (PVOID)POINTER_REMOVE_BIAS(HeapPtr);
01932         Biased = TRUE;
01933     }
01934 
01935     /* Get a pointer to the heap root */
01936     DphRoot = RtlpDphPointerFromHandle(HeapPtr);
01937     if (!DphRoot) return NULL;
01938 
01939     /* Acquire the heap lock */
01940     RtlpDphPreProcessing(DphRoot, Flags);
01941 
01942     /* Perform internal validation if specified by flags */
01943     if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE)
01944     {
01945         RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0);
01946     }
01947 
01948     /* Add heap flags */
01949     Flags |= DphRoot->HeapFlags;
01950 
01951     /* Exit with NULL right away if inplace is specified */
01952     if (Flags & HEAP_REALLOC_IN_PLACE_ONLY)
01953     {
01954         /* Release the lock */
01955         RtlpDphPostProcessing(DphRoot);
01956 
01957         /* Generate an exception if needed */
01958         if (Flags & HEAP_GENERATE_EXCEPTIONS) RtlpDphRaiseException(STATUS_NO_MEMORY);
01959 
01960         return NULL;
01961     }
01962 
01963     /* Try to get node of the allocated block */
01964     AllocatedNode = RtlpDphFindBusyMemory(DphRoot, Ptr);
01965 
01966     if (!AllocatedNode)
01967     {
01968         /* This block was not found in page heap, try a normal heap instead */
01969         //RtlpDphNormalHeapFree();
01970         ASSERT(FALSE);
01971         OldBlockPageHeap = FALSE;
01972     }
01973 
01974     /* Check the block */
01975     if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN))
01976     {
01977         if (!RtlpDphIsPageHeapBlock(DphRoot, AllocatedNode->pUserAllocation, &ValidationInfo, TRUE))
01978         {
01979             RtlpDphReportCorruptedBlock(DphRoot, 3, AllocatedNode->pUserAllocation, ValidationInfo);
01980         }
01981     }
01982 
01983     /* Remove old one from the busy list */
01984     RtlpDphRemoveFromBusyList(DphRoot, AllocatedNode);
01985 
01986     if (!Biased && !RtlpDphShouldAllocateInPageHeap(DphRoot, Size))
01987     {
01988         // FIXME: Use normal heap
01989         ASSERT(FALSE);
01990         UseNormalHeap = TRUE;
01991     }
01992     else
01993     {
01994         /* Now do a trick: bias the pointer and call our allocate routine */
01995         NewAlloc = RtlpPageHeapAllocate((PVOID)POINTER_ADD_BIAS(HeapPtr), Flags, Size);
01996     }
01997 
01998     if (!NewAlloc)
01999     {
02000         /* New allocation failed, put the block back (if it was found in page heap) */
02001         RtlpDphPlaceOnBusyList(DphRoot, AllocatedNode);
02002 
02003         /* Release the lock */
02004         RtlpDphPostProcessing(DphRoot);
02005 
02006         /* Perform validation again if required */
02007         if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE)
02008         {
02009             RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0);
02010         }
02011 
02012         /* Generate an exception if needed */
02013         if (Flags & HEAP_GENERATE_EXCEPTIONS) RtlpDphRaiseException(STATUS_NO_MEMORY);
02014 
02015         return NULL;
02016     }
02017 
02018     /* Copy contents of the old block */
02019     if (AllocatedNode->nUserRequestedSize > Size)
02020         DataSize = Size;
02021     else
02022         DataSize = AllocatedNode->nUserRequestedSize;
02023 
02024     if (DataSize != 0) RtlCopyMemory(NewAlloc, Ptr, DataSize);
02025 
02026     /* Copy user flags and values */
02027     if (!UseNormalHeap)
02028     {
02029         /* Get the node of the new block */
02030         Node = RtlpDphFindBusyMemory(DphRoot, NewAlloc);
02031         ASSERT(Node != NULL);
02032 
02033         /* Set its values/flags */
02034         Node->UserValue = AllocatedNode->UserValue;
02035         if (Flags & HEAP_SETTABLE_USER_FLAGS)
02036             Node->UserFlags = Flags & HEAP_SETTABLE_USER_FLAGS;
02037         else
02038             Node->UserFlags = AllocatedNode->UserFlags;
02039     }
02040 
02041     if (!OldBlockPageHeap)
02042     {
02043         /* Weird scenario, investigate */
02044         ASSERT(FALSE);
02045     }
02046 
02047     /* Mark the old block as no access */
02048     if (AllocatedNode->nVirtualAccessSize != 0)
02049     {
02050         RtlpDphProtectVm(AllocatedNode->pVirtualBlock, AllocatedNode->nVirtualAccessSize, PAGE_NOACCESS);
02051     }
02052 
02053     /* And place it on the free list */
02054     RtlpDphPlaceOnFreeList(DphRoot, AllocatedNode);
02055 
02056     // FIXME: Capture stack traces if needed
02057     AllocatedNode->StackTrace = NULL;
02058 
02059     /* Finally allocation is done, perform validation again if required */
02060     if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE && !Biased)
02061     {
02062         RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0);
02063     }
02064 
02065     /* Release the lock */
02066     RtlpDphPostProcessing(DphRoot);
02067 
02068     DPRINT("Allocated new user block pointer: %p\n", NewAlloc);
02069 
02070     /* Return pointer to user allocation */
02071     return NewAlloc;
02072 }
02073 
02074 BOOLEAN NTAPI
02075 RtlpPageHeapGetUserInfo(PVOID HeapHandle,
02076                         ULONG Flags,
02077                         PVOID BaseAddress,
02078                         PVOID *UserValue,
02079                         PULONG UserFlags)
02080 {
02081     PDPH_HEAP_ROOT DphRoot;
02082     PDPH_HEAP_BLOCK Node;
02083 
02084     /* Get a pointer to the heap root */
02085     DphRoot = RtlpDphPointerFromHandle(HeapHandle);
02086     if (!DphRoot) return FALSE;
02087 
02088     /* Add heap flags */
02089     Flags |= DphRoot->HeapFlags;
02090 
02091     /* Acquire the heap lock */
02092     RtlpDphPreProcessing(DphRoot, Flags);
02093 
02094     /* Find busy memory */
02095     Node = RtlpDphFindBusyMemory(DphRoot, BaseAddress);
02096 
02097     if (!Node)
02098     {
02099         /* This block was not found in page heap, try a normal heap instead */
02100         //RtlpDphNormalHeapGetUserInfo();
02101         ASSERT(FALSE);
02102         return FALSE;
02103     }
02104 
02105     /* Get user values and flags and store them in user provided pointers */
02106     if (UserValue) *UserValue = Node->UserValue;
02107     if (UserFlags) *UserFlags = Node->UserFlags;
02108 
02109     /* Leave the heap lock */
02110     RtlpDphPostProcessing(DphRoot);
02111 
02112     /* Return success */
02113     return TRUE;
02114 }
02115 
02116 BOOLEAN NTAPI
02117 RtlpPageHeapSetUserValue(PVOID HeapHandle,
02118                          ULONG Flags,
02119                          PVOID BaseAddress,
02120                          PVOID UserValue)
02121 {
02122     PDPH_HEAP_ROOT DphRoot;
02123     PDPH_HEAP_BLOCK Node;
02124 
02125     /* Get a pointer to the heap root */
02126     DphRoot = RtlpDphPointerFromHandle(HeapHandle);
02127     if (!DphRoot) return FALSE;
02128 
02129     /* Add heap flags */
02130     Flags |= DphRoot->HeapFlags;
02131 
02132     /* Acquire the heap lock */
02133     RtlpDphPreProcessing(DphRoot, Flags);
02134 
02135     /* Find busy memory */
02136     Node = RtlpDphFindBusyMemory(DphRoot, BaseAddress);
02137 
02138     if (!Node)
02139     {
02140         /* This block was not found in page heap, try a normal heap instead */
02141         //RtlpDphNormalHeapSetUserValue();
02142         ASSERT(FALSE);
02143         return FALSE;
02144     }
02145 
02146     /* Get user values and flags and store them in user provided pointers */
02147     Node->UserValue = UserValue;
02148 
02149     /* Leave the heap lock */
02150     RtlpDphPostProcessing(DphRoot);
02151 
02152     /* Return success */
02153     return TRUE;
02154 }
02155 
02156 BOOLEAN
02157 NTAPI
02158 RtlpPageHeapSetUserFlags(PVOID HeapHandle,
02159                          ULONG Flags,
02160                          PVOID BaseAddress,
02161                          ULONG UserFlagsReset,
02162                          ULONG UserFlagsSet)
02163 {
02164     PDPH_HEAP_ROOT DphRoot;
02165     PDPH_HEAP_BLOCK Node;
02166 
02167     /* Get a pointer to the heap root */
02168     DphRoot = RtlpDphPointerFromHandle(HeapHandle);
02169     if (!DphRoot) return FALSE;
02170 
02171     /* Add heap flags */
02172     Flags |= DphRoot->HeapFlags;
02173 
02174     /* Acquire the heap lock */
02175     RtlpDphPreProcessing(DphRoot, Flags);
02176 
02177     /* Find busy memory */
02178     Node = RtlpDphFindBusyMemory(DphRoot, BaseAddress);
02179 
02180     if (!Node)
02181     {
02182         /* This block was not found in page heap, try a normal heap instead */
02183         //RtlpDphNormalHeapSetUserFlags();
02184         ASSERT(FALSE);
02185         return FALSE;
02186     }
02187 
02188     /* Get user values and flags and store them in user provided pointers */
02189     Node->UserFlags &= ~(UserFlagsReset);
02190     Node->UserFlags |= UserFlagsSet;
02191 
02192     /* Leave the heap lock */
02193     RtlpDphPostProcessing(DphRoot);
02194 
02195     /* Return success */
02196     return TRUE;
02197 }
02198 
02199 SIZE_T NTAPI
02200 RtlpPageHeapSize(HANDLE HeapHandle,
02201                  ULONG Flags,
02202                  PVOID BaseAddress)
02203 {
02204     PDPH_HEAP_ROOT DphRoot;
02205     PDPH_HEAP_BLOCK Node;
02206     SIZE_T Size;
02207 
02208     /* Get a pointer to the heap root */
02209     DphRoot = RtlpDphPointerFromHandle(HeapHandle);
02210     if (!DphRoot) return -1;
02211 
02212     /* Add heap flags */
02213     Flags |= DphRoot->HeapFlags;
02214 
02215     /* Acquire the heap lock */
02216     RtlpDphPreProcessing(DphRoot, Flags);
02217 
02218     /* Find busy memory */
02219     Node = RtlpDphFindBusyMemory(DphRoot, BaseAddress);
02220 
02221     if (!Node)
02222     {
02223         /* This block was not found in page heap, try a normal heap instead */
02224         //RtlpDphNormalHeapSize();
02225         ASSERT(FALSE);
02226         return -1;
02227     }
02228 
02229     /* Get heap block size */
02230     Size = Node->nUserRequestedSize;
02231 
02232     /* Leave the heap lock */
02233     RtlpDphPostProcessing(DphRoot);
02234 
02235     /* Return user requested size */
02236     return Size;
02237 }
02238 
02239 BOOLEAN
02240 NTAPI
02241 RtlpDebugPageHeapValidate(PVOID HeapHandle,
02242                           ULONG Flags,
02243                           PVOID BaseAddress)
02244 {
02245     PDPH_HEAP_ROOT DphRoot;
02246     PDPH_HEAP_BLOCK Node = NULL;
02247     BOOLEAN Valid = FALSE;
02248 
02249     /* Get a pointer to the heap root */
02250     DphRoot = RtlpDphPointerFromHandle(HeapHandle);
02251     if (!DphRoot) return -1;
02252 
02253     /* Add heap flags */
02254     Flags |= DphRoot->HeapFlags;
02255 
02256     /* Acquire the heap lock */
02257     RtlpDphPreProcessing(DphRoot, Flags);
02258 
02259     /* Find busy memory */
02260     if (BaseAddress)
02261         Node = RtlpDphFindBusyMemory(DphRoot, BaseAddress);
02262 
02263     if (!Node)
02264     {
02265         /* This block was not found in page heap, or the request is to validate all normal heap */
02266         Valid = RtlpDphNormalHeapValidate(DphRoot, Flags, BaseAddress);
02267     }
02268 
02269     /* Leave the heap lock */
02270     RtlpDphPostProcessing(DphRoot);
02271 
02272     /* Return result of a normal heap validation */
02273     if (BaseAddress && !Node)
02274         return Valid;
02275 
02276     /* Otherwise return our own result */
02277     if (!BaseAddress || Node) Valid = TRUE;
02278 
02279     return Valid;
02280 }
02281 
02282 BOOLEAN
02283 NTAPI
02284 RtlpDphNormalHeapValidate(PDPH_HEAP_ROOT DphRoot,
02285                           ULONG Flags,
02286                           PVOID BaseAddress)
02287 {
02288     PDPH_BLOCK_INFORMATION BlockInfo = (PDPH_BLOCK_INFORMATION)BaseAddress - 1;
02289     if (!BaseAddress)
02290     {
02291         /* Validate all normal heap */
02292         return RtlValidateHeap(DphRoot->NormalHeap, Flags, NULL);
02293     }
02294 
02295     // FIXME: Check is this a normal heap block
02296     /*if (!RtlpDphIsNormalHeapBlock(DphRoot, BaseAddress, &ValidationInfo))
02297     {
02298     }*/
02299 
02300     return RtlValidateHeap(DphRoot->NormalHeap, Flags, BlockInfo);
02301 }
02302 
02303 /* EOF */

Generated on Sun May 27 2012 04:36:22 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.