Author: fireball
Date: Thu Feb 17 14:46:30 2011
New Revision: 50766
URL:
http://svn.reactos.org/svn/reactos?rev=50766&view=rev
Log:
[RTL/DPH]
- Implement allocating from the page heap along with all necessary helper routines. Some
minor things are left though, so it doesn't work yet.
- Change some defines names to more meaningful/readable.
Modified:
trunk/reactos/lib/rtl/heappage.c
Modified: trunk/reactos/lib/rtl/heappage.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/heappage.c?rev=507…
==============================================================================
--- trunk/reactos/lib/rtl/heappage.c [iso-8859-1] (original)
+++ trunk/reactos/lib/rtl/heappage.c [iso-8859-1] Thu Feb 17 14:46:30 2011
@@ -146,14 +146,16 @@
#define DPH_DEBUG_VERBOSE 0x04
/* DPH ExtraFlags */
-#define DPH_EXTRA_CHECK_CORRUPTED_BLOCKS 0x10
+#define DPH_EXTRA_CHECK_UNDERRUN 0x10
+#define DPH_LOG_STACK_TRACES 0x0 //FIXME: Get correct value
/* Fillers */
#define DPH_FILL 0xEEEEEEEE
#define DPH_FILL_START_STAMP_1 0xABCDBBBB
#define DPH_FILL_START_STAMP_2 0xABCDBBBA
#define DPH_FILL_END_STAMP_1 0xDCBABBBB
-#define DPH_FILL_BLOCK_END 0xD0
+#define DPH_FILL_SUFFIX 0xD0
+#define DPH_FILL_INFIX 0xC0
/* Validation info flags */
#define DPH_VALINFO_BAD_START_STAMP 0x01
@@ -186,6 +188,21 @@
VOID NTAPI
RtlpDphReportCorruptedBlock(PDPH_HEAP_ROOT DphRoot, ULONG Reserved, PVOID Block, ULONG
ValidationInfo);
+VOID NTAPI
+RtlpDphRaiseException(NTSTATUS Status)
+{
+ EXCEPTION_RECORD Exception;
+
+ /* Initialize exception record */
+ Exception.ExceptionCode = Status;
+ Exception.ExceptionAddress = RtlpDphRaiseException;
+ Exception.ExceptionFlags = 0;
+ Exception.ExceptionRecord = NULL;
+ Exception.NumberParameters = 0;
+
+ /* Raise the exception */
+ RtlRaiseException(&Exception);
+}
PVOID NTAPI
RtlpDphPointerFromHandle(PVOID Handle)
@@ -246,6 +263,20 @@
RtlpDphEnterCriticalSection(DphRoot, Flags);
/* FIXME: Validate integrity, internal lists if necessary */
+}
+
+VOID NTAPI
+RtlpDphPostProcessing(PDPH_HEAP_ROOT DphRoot)
+{
+ if (!DphRoot) return;
+
+ if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE)
+ {
+ /* FIXME: Validate integrity, internal lists if necessary */
+ }
+
+ /* Release the lock */
+ RtlpDphLeaveCriticalSection(DphRoot);
}
NTSTATUS NTAPI
@@ -370,6 +401,53 @@
return Status;
}
+BOOLEAN NTAPI
+RtlpDphWritePageHeapBlockInformation(PDPH_HEAP_ROOT DphRoot, PVOID UserAllocation, SIZE_T
Size, SIZE_T UserSize)
+{
+ PDPH_BLOCK_INFORMATION BlockInfo;
+ PUCHAR FillPtr;
+
+ /* Get pointer to the block info structure */
+ BlockInfo = (PDPH_BLOCK_INFORMATION)UserAllocation - 1;
+
+ /* Set up basic fields */
+ BlockInfo->Heap = DphRoot;
+ BlockInfo->ActualSize = UserSize;
+ BlockInfo->RequestedSize = Size;
+ BlockInfo->StartStamp = DPH_FILL_START_STAMP_1;
+ BlockInfo->EndStamp = DPH_FILL_END_STAMP_1;
+
+ /* Fill with a pattern */
+ FillPtr = (PUCHAR)UserAllocation + Size;
+ RtlFillMemory(FillPtr, ROUND_UP(FillPtr, PAGE_SIZE) - FillPtr, DPH_FILL_SUFFIX);
+
+ /* FIXME: Check if logging stack traces is turned on */
+ //if (DphRoot->ExtraFlags &
+
+ return TRUE;
+}
+
+VOID NTAPI
+RtlpDphPlaceOnBusyList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK DphNode)
+{
+ BOOLEAN NewElement;
+ PVOID AddressUserData;
+
+ /* Add it to the AVL busy nodes table */
+ AddressUserData = RtlInsertElementGenericTableAvl(&DphRoot->BusyNodesTable,
+ &DphNode->pUserAllocation,
+ sizeof(ULONG_PTR),
+ &NewElement);
+
+ ASSERT(AddressUserData == &DphNode->pUserAllocation);
+ ASSERT(NewElement == TRUE);
+
+ /* Update heap counters */
+ DphRoot->nBusyAllocations++;
+ DphRoot->nBusyAllocationBytesAccessible += DphNode->nVirtualAccessSize;
+ DphRoot->nBusyAllocationBytesCommitted += DphNode->nVirtualBlockSize;
+}
+
VOID NTAPI
RtlpDphPlaceOnPoolList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK DphNode)
{
@@ -702,6 +780,28 @@
/* Return node we found */
return Node;
+}
+
+NTSTATUS NTAPI
+RtlpDphSetProtectionBeforeUse(PDPH_HEAP_ROOT DphRoot, PUCHAR VirtualBlock, ULONG
UserSize)
+{
+ ULONG Protection;
+ PVOID Base;
+
+ // FIXME: Check this, when we should add up usersize and when we shouldn't!
+ if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN))
+ {
+ Base = VirtualBlock;
+ }
+ else
+ {
+ Base = VirtualBlock + UserSize;
+ }
+
+ // FIXME: It should be different, but for now it's fine
+ Protection = PAGE_READWRITE;
+
+ return RtlpDphProtectVm(Base, PAGE_SIZE, Protection);
}
PDPH_HEAP_BLOCK NTAPI
@@ -870,9 +970,17 @@
IN PVOID FirstStruct,
IN PVOID SecondStruct)
{
- UNIMPLEMENTED;
- ASSERT(FALSE);
- return 0;
+ ULONG_PTR FirstBlock, SecondBlock;
+
+ FirstBlock = *((ULONG_PTR *)FirstStruct);
+ SecondBlock = *((ULONG_PTR *)SecondStruct);
+
+ if (FirstBlock < SecondBlock)
+ return GenericLessThan;
+ else if (FirstBlock > SecondBlock)
+ return GenericGreaterThan;
+
+ return GenericEqual;
}
PVOID
@@ -880,9 +988,21 @@
RtlpDphAllocateNodeForTable(IN PRTL_AVL_TABLE Table,
IN CLONG ByteSize)
{
- UNIMPLEMENTED;
- ASSERT(FALSE);
- return NULL;
+ PDPH_HEAP_BLOCK pBlock;
+ PDPH_HEAP_ROOT DphRoot;
+
+ /* This mega-assert comes from a text search over Windows 2003 checked binary of
ntdll.dll */
+ ASSERT((ULONG_PTR)(((PRTL_BALANCED_LINKS)0)+1) + sizeof(PUCHAR) == ByteSize);
+
+ /* Get pointer to the containing heap root record */
+ DphRoot = CONTAINING_RECORD(Table, DPH_HEAP_ROOT, BusyNodesTable);
+ pBlock = DphRoot->NodeToAllocate;
+ ASSERT(pBlock == (PDPH_HEAP_BLOCK)(Table+1)); // FIXME: Delete once confirmed
+
+ DphRoot->NodeToAllocate = NULL;
+ ASSERT(pBlock);
+
+ return &(pBlock->TableLinks);
}
VOID
@@ -890,8 +1010,7 @@
RtlpDphFreeNodeForTable(IN PRTL_AVL_TABLE Table,
IN PVOID Buffer)
{
- UNIMPLEMENTED;
- ASSERT(FALSE);
+ /* Nothing */
}
NTSTATUS NTAPI
@@ -980,6 +1099,12 @@
VOID NTAPI
RtlpDphInternalValidatePageHeap(PDPH_HEAP_ROOT DphRoot, PVOID Address, ULONG Value)
+{
+ UNIMPLEMENTED;
+}
+
+VOID NTAPI
+RtlpDphVerifyIntegrity(PDPH_HEAP_ROOT DphRoot)
{
UNIMPLEMENTED;
}
@@ -1144,6 +1269,14 @@
DPRINT1("Page heap: pid 0x%X: page heap enabled with flags 0x%X.\n",
Teb->ClientId.UniqueProcess, RtlpDphGlobalFlags);
return Status;
+}
+
+BOOLEAN NTAPI
+RtlpDphShouldAllocateInPageHeap(PDPH_HEAP_ROOT DphRoot,
+ SIZE_T Size)
+{
+ UNIMPLEMENTED;
+ return TRUE;
}
HANDLE NTAPI
@@ -1317,7 +1450,7 @@
while (Node)
{
- if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_CORRUPTED_BLOCKS))
+ if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN))
{
if (!RtlpDphIsPageHeapBlock(DphRoot, Node->pUserAllocation, &Value,
TRUE))
{
@@ -1371,7 +1504,153 @@
IN ULONG Flags,
IN SIZE_T Size)
{
- return NULL;
+ PDPH_HEAP_ROOT DphRoot;
+ PDPH_HEAP_BLOCK Node, AllocatedNode;
+ BOOLEAN Biased = FALSE;
+ ULONG TotalSize, UserSize;
+ NTSTATUS Status;
+ SIZE_T UserActualSize;
+
+ /* Check requested size */
+ if (Size > 0x7FF00000)
+ {
+ DPRINT1("extreme size request\n");
+
+ /* Generate an exception if needed */
+ if (Flags & HEAP_GENERATE_EXCEPTIONS)
RtlpDphRaiseException(STATUS_NO_MEMORY);
+
+ return NULL;
+ }
+
+ /* Unbias the pointer if necessary */
+ if (IS_BIASED_POINTER(HeapPtr))
+ {
+ HeapPtr = (PVOID)POINTER_REMOVE_BIAS(HeapPtr);
+ Biased = TRUE;
+ }
+
+ /* Get a pointer to the heap root */
+ DphRoot = RtlpDphPointerFromHandle(HeapPtr);
+ if (!DphRoot) return NULL;
+
+ /* Acquire the heap lock */
+ //RtlpDphEnterCriticalSection(DphRoot, Flags);
+ RtlpDphPreProcessing(DphRoot, Flags);
+
+ /* Perform internal validation if specified by flags */
+ if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE && !Biased)
+ {
+ RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0);
+ }
+
+ /* Add heap flags */
+ Flags |= DphRoot->HeapFlags;
+
+ if (!Biased && !RtlpDphShouldAllocateInPageHeap(DphRoot, Size))
+ {
+ /* Perform allocation from a normal heap */
+ ASSERT(FALSE);
+ }
+
+ /* Perform heap integrity check if specified by flags */
+ if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE)
+ {
+ RtlpDphVerifyIntegrity(DphRoot);
+ }
+
+ /* Calculate sizes */
+ UserSize = ROUND_UP(Size + sizeof(DPH_BLOCK_INFORMATION), PAGE_SIZE);
+ TotalSize = UserSize + PAGE_SIZE;
+
+ // RtlpDphAllocateNode(DphRoot);
+ Node = RtlpDphFindAvailableMemory(DphRoot, TotalSize, TRUE);
+ if (!Node)
+ {
+ DPRINT1("Page heap: Unable to allocate virtual memory\n");
+ DbgBreakPoint();
+
+ /* Release the lock */
+ RtlpDphPostProcessing(DphRoot);
+
+ return NULL;
+ }
+ ASSERT(Node->nVirtualBlockSize >= TotalSize);
+
+ /* Set protection */
+ Status = RtlpDphSetProtectionBeforeUse(DphRoot, Node->pVirtualBlock, UserSize);
+ if (!NT_SUCCESS(Status))
+ {
+ ASSERT(FALSE);
+ }
+
+ /* Check node's size */
+ if (Node->nVirtualBlockSize > TotalSize)
+ {
+ /* The block contains too much free space, reduce it */
+ Node->pVirtualBlock += TotalSize;
+ Node->nVirtualBlockSize -= TotalSize;
+ DphRoot->nAvailableAllocationBytesCommitted -= TotalSize;
+
+ AllocatedNode = RtlpDphAllocateNode(DphRoot);
+ ASSERT(AllocatedNode != NULL);
+ AllocatedNode->pVirtualBlock = Node->pVirtualBlock - TotalSize;
+ AllocatedNode->nVirtualBlockSize = TotalSize;
+ }
+ else
+ {
+ /* The block's size fits exactly */
+ RtlpDphRemoveFromAvailableList(DphRoot, Node);
+ AllocatedNode = Node;
+ }
+
+ /* Calculate actual user size */
+ if (DphRoot->HeapFlags & HEAP_NO_ALIGNMENT)
+ UserActualSize = Size;
+ else
+ UserActualSize = ROUND_UP(Size, 8);
+
+ /* Set up the block */
+ AllocatedNode->nVirtualAccessSize = UserSize;
+ AllocatedNode->nUserActualSize = UserActualSize;
+ AllocatedNode->nUserRequestedSize = Size;
+
+ if (DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN)
+ AllocatedNode->pUserAllocation = AllocatedNode->pVirtualBlock + PAGE_SIZE;
+ else
+ AllocatedNode->pUserAllocation = AllocatedNode->pVirtualBlock +
AllocatedNode->nVirtualAccessSize - UserActualSize;
+
+ AllocatedNode->UserValue = NULL;
+ AllocatedNode->UserFlags = Flags & HEAP_SETTABLE_USER_FLAGS;
+
+ // FIXME: Don't forget about stack traces if such flag was set
+ AllocatedNode->StackTrace = NULL;
+
+ /* Place it on busy list */
+ RtlpDphPlaceOnBusyList(DphRoot, AllocatedNode);
+
+ /* Zero or patter-fill memory depending on flags */
+ if (Flags & HEAP_ZERO_MEMORY)
+ RtlZeroMemory(AllocatedNode->pUserAllocation, Size);
+ else
+ RtlFillMemory(AllocatedNode->pUserAllocation, Size, DPH_FILL_INFIX);
+
+ /* Write DPH info */
+ if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN))
+ {
+ RtlpDphWritePageHeapBlockInformation(DphRoot, AllocatedNode->pUserAllocation,
Size, UserSize);
+ }
+
+ /* Finally allocation is done, perform validation again if required */
+ if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE && !Biased)
+ {
+ RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0);
+ }
+
+ /* Release the lock */
+ RtlpDphPostProcessing(DphRoot);
+
+ /* Return pointer to user allocation */
+ return AllocatedNode->pUserAllocation;
}
BOOLEAN NTAPI