Author: fireball
Date: Tue Feb 15 22:02:28 2011
New Revision: 50721
URL:
http://svn.reactos.org/svn/reactos?rev=50721&view=rev
Log:
[RTL/DPH]
- Implement other support locking/unlocking, handle-related routines.
- Fix RtlpDphFreeVm definition.
- Node lists related improvements: Add a function for removing a node from a free list,
implement coalescing free nodes into an available list.
- Implement a non-implemented case in RtlpDphAllocateNode when there is a need to allocate
more virtual memory, and fix incorrect size calculation too.
- Implement a function for validating the page heap block.
- Implement RtlpPageHeapDestroy. Now we have two exported APIs ready: heap create and heap
destroy.
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] Tue Feb 15 22:02:28 2011
@@ -139,8 +139,21 @@
#define DPH_DEBUG_INTERNAL_VALIDATE 0x01
#define DPH_DEBUG_VERBOSE 0x04
+/* DPH ExtraFlags */
+#define DPH_EXTRA_CHECK_CORRUPTED_BLOCKS 0x10
+
/* 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
+
+/* Validation info flags */
+#define DPH_VALINFO_BAD_START_STAMP 0x01
+#define DPH_VALINFO_BAD_END_STAMP 0x02
+#define DPH_VALINFO_BAD_POINTER 0x04
+#define DPH_VALINFO_BAD_END_FILL 0x10
/* Signatures */
#define DPH_SIGNATURE 0xFFEEDDCC
@@ -154,6 +167,67 @@
BOOLEAN NTAPI
RtlpDphGrowVirtual(PDPH_HEAP_ROOT DphRoot, SIZE_T Size);
+
+PVOID NTAPI
+RtlpDphPointerFromHandle(PVOID Handle)
+{
+ PHEAP NormalHeap = (PHEAP)Handle;
+ PDPH_HEAP_ROOT DphHeap = (PDPH_HEAP_ROOT)((PUCHAR)Handle + PAGE_SIZE);
+
+ if (NormalHeap->ForceFlags & HEAP_FLAG_PAGE_ALLOCS)
+ {
+ if (DphHeap->Signature == DPH_SIGNATURE)
+ return DphHeap;
+ }
+
+ DPRINT1("heap handle with incorrect signature\n");
+ DbgBreakPoint();
+ return NULL;
+}
+
+VOID NTAPI
+RtlpDphEnterCriticalSection(PDPH_HEAP_ROOT DphRoot, ULONG Flags)
+{
+ if (Flags & HEAP_NO_SERIALIZE)
+ {
+ /* More complex scenario */
+ if (!RtlTryEnterCriticalSection(DphRoot->HeapCritSect))
+ {
+ if (!DphRoot->nRemoteLockAcquired)
+ {
+ DPRINT1("multithreaded access in HEAP_NO_SERIALIZE heap\n");
+ DbgBreakPoint();
+
+ /* Clear out the no serialize flag */
+ DphRoot->HeapFlags &= ~HEAP_NO_SERIALIZE;
+ }
+
+ /* Enter the heap's critical section */
+ RtlEnterCriticalSection(DphRoot->HeapCritSect);
+ }
+ }
+ else
+ {
+ /* Just enter the heap's critical section */
+ RtlEnterCriticalSection(DphRoot->HeapCritSect);
+ }
+}
+
+VOID NTAPI
+RtlpDphLeaveCriticalSection(PDPH_HEAP_ROOT DphRoot)
+{
+ /* Just leave the heap's critical section */
+ RtlLeaveCriticalSection(DphRoot->HeapCritSect);
+}
+
+
+VOID NTAPI
+RtlpDphPreProcessing(PDPH_HEAP_ROOT DphRoot, ULONG Flags)
+{
+ RtlpDphEnterCriticalSection(DphRoot, Flags);
+
+ /* FIXME: Validate integrity, internal lists if necessary */
+}
NTSTATUS NTAPI
RtlpSecMemFreeVirtualMemory(HANDLE Process, PVOID *Base, PSIZE_T Size, ULONG Type)
@@ -218,7 +292,7 @@
}
NTSTATUS NTAPI
-RtlpDphFreeVm(PVOID Base, SIZE_T Size, ULONG Type, ULONG Protection)
+RtlpDphFreeVm(PVOID Base, SIZE_T Size, ULONG Type)
{
NTSTATUS Status;
@@ -363,6 +437,28 @@
}
VOID NTAPI
+RtlpDphRemoveFromFreeList(PDPH_HEAP_ROOT DphRoot,
+ PDPH_HEAP_BLOCK Node,
+ PDPH_HEAP_BLOCK Prev)
+{
+ PDPH_HEAP_BLOCK Next;
+
+ /* Detach it from the list */
+ Next = Node->pNextAlloc;
+ if (DphRoot->pFreeAllocationListHead == Node)
+ DphRoot->pFreeAllocationListHead = Next;
+ if (DphRoot->pFreeAllocationListTail == Node)
+ DphRoot->pFreeAllocationListTail = Prev;
+ if (Prev) Prev->pNextAlloc = Next;
+
+ /* Decrease heap counters */
+ DphRoot->nFreeAllocations--;
+ DphRoot->nFreeAllocationBytesCommitted -= Node->nVirtualBlockSize;
+
+ Node->StackTrace = NULL;
+}
+
+VOID NTAPI
RtlpDphCoalesceNodeIntoAvailable(PDPH_HEAP_ROOT DphRoot,
PDPH_HEAP_BLOCK Node)
{
@@ -433,9 +529,30 @@
VOID NTAPI
RtlpDphCoalesceFreeIntoAvailable(PDPH_HEAP_ROOT DphRoot,
- ULONG Size)
-{
- UNIMPLEMENTED;
+ ULONG LeaveOnFreeList)
+{
+ PDPH_HEAP_BLOCK Node = DphRoot->pFreeAllocationListHead, Next;
+ SIZE_T FreeAllocations = DphRoot->nFreeAllocations;
+
+ /* Make sure requested size is not too big */
+ ASSERT(FreeAllocations >= LeaveOnFreeList);
+
+ while (Node)
+ {
+ FreeAllocations--;
+ if (FreeAllocations <= LeaveOnFreeList) break;
+
+ /* Get the next pointer, because it may be changed after following two calls */
+ Next = Node->pNextAlloc;
+
+ /* Remove it from the free list */
+ RtlpDphRemoveFromFreeList(DphRoot, Node, NULL);
+
+ /* And put into the available */
+ RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node);
+
+ Node = Next;
+ }
}
VOID NTAPI
@@ -573,7 +690,7 @@
{
PDPH_HEAP_BLOCK Node;
NTSTATUS Status;
- ULONG Size = DPH_POOL_SIZE;
+ SIZE_T Size = DPH_POOL_SIZE, SizeVirtual;
PVOID Ptr;
/* Check for the easy case */
@@ -601,17 +718,20 @@
{
RtlpDphRemoveFromAvailableList(DphRoot, Node);
Ptr = Node->pVirtualBlock;
+ SizeVirtual = Node->nVirtualBlockSize;
}
else
{
/* No free space, need to alloc a new VM block */
Size = DPH_POOL_SIZE;
- Status = RtlpDphAllocateVm(&Ptr, DPH_RESERVE_SIZE, MEM_COMMIT,
PAGE_NOACCESS);
+ SizeVirtual = DPH_RESERVE_SIZE;
+ Status = RtlpDphAllocateVm(&Ptr, SizeVirtual, MEM_COMMIT,
PAGE_NOACCESS);
if (!NT_SUCCESS(Status))
{
/* Retry with a smaller size */
- Status = RtlpDphAllocateVm(&Ptr, 0x10000, MEM_COMMIT,
PAGE_NOACCESS);
+ SizeVirtual = 0x10000;
+ Status = RtlpDphAllocateVm(&Ptr, SizeVirtual, MEM_COMMIT,
PAGE_NOACCESS);
if (!NT_SUCCESS(Status)) return NULL;
}
}
@@ -620,7 +740,16 @@
Status = RtlpDphProtectVm(Ptr, Size, PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
- ASSERT(FALSE);
+ if (Node)
+ {
+ RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node);
+ }
+ else
+ {
+ //RtlpDphFreeVm();
+ ASSERT(FALSE);
+ }
+
return NULL;
}
@@ -630,11 +759,7 @@
/* Add a new pool based on this VM */
RtlpDphAddNewPool(DphRoot, Node, Ptr, Size, TRUE);
- if (!Node)
- {
- ASSERT(FALSE);
- }
- else
+ if (Node)
{
if (Node->nVirtualBlockSize > Size)
{
@@ -648,6 +773,23 @@
RtlpDphReturnNodeToUnusedList(DphRoot, Node);
}
}
+ else
+ {
+ /* The new VM block was just allocated a few code lines ago,
+ so initialize it */
+ Node = RtlpDphTakeNodeFromUnusedList(DphRoot);
+ Node->pVirtualBlock = Ptr;
+ Node->nVirtualBlockSize = SizeVirtual;
+ RtlpDphPlaceOnVirtualList(DphRoot, Node);
+
+ Node = RtlpDphTakeNodeFromUnusedList(DphRoot);
+ Node->pVirtualBlock = (PUCHAR)Ptr + Size;
+ Node->nVirtualBlockSize = SizeVirtual - Size;
+ RtlpDphPlaceOnVirtualList(DphRoot, Node);
+
+ /* Coalesce them into available list */
+ RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node);
+ }
}
return RtlpDphTakeNodeFromUnusedList(DphRoot);
@@ -709,7 +851,7 @@
IN PVOID FirstStruct,
IN PVOID SecondStruct)
{
- /* FIXME: TODO */
+ UNIMPLEMENTED;
ASSERT(FALSE);
return 0;
}
@@ -719,7 +861,7 @@
RtlpDphAllocateNodeForTable(IN PRTL_AVL_TABLE Table,
IN CLONG ByteSize)
{
- /* FIXME: TODO */
+ UNIMPLEMENTED;
ASSERT(FALSE);
return NULL;
}
@@ -729,7 +871,7 @@
RtlpDphFreeNodeForTable(IN PRTL_AVL_TABLE Table,
IN PVOID Buffer)
{
- /* FIXME: TODO */
+ UNIMPLEMENTED;
ASSERT(FALSE);
}
@@ -740,6 +882,13 @@
return STATUS_SUCCESS;
}
+VOID NTAPI
+RtlpDphFreeDelayedBlocksFromHeap(PDPH_HEAP_ROOT DphRoot,
+ PHEAP NormalHeap)
+{
+ UNIMPLEMENTED;
+}
+
NTSTATUS NTAPI
RtlpDphTargetDllsLogicInitialize()
{
@@ -751,6 +900,78 @@
RtlpDphInternalValidatePageHeap(PDPH_HEAP_ROOT DphRoot, PVOID Address, ULONG Value)
{
UNIMPLEMENTED;
+}
+
+VOID NTAPI
+RtlpDphReportCorruptedBlock(PDPH_HEAP_ROOT DphRoot,
+ ULONG Reserved,
+ PVOID Block,
+ ULONG ValidationInfo)
+{
+ UNIMPLEMENTED;
+}
+
+BOOLEAN NTAPI
+RtlpDphIsPageHeapBlock(PDPH_HEAP_ROOT DphRoot,
+ PVOID Block,
+ PULONG ValidationInformation,
+ BOOLEAN CheckFillers)
+{
+ PDPH_BLOCK_INFORMATION BlockInfo;
+ BOOLEAN SomethingWrong = FALSE;
+ PUCHAR Byte, Start, End;
+
+ ASSERT(ValidationInformation != NULL);
+ *ValidationInformation = 0;
+
+ // _SEH2_TRY {
+ BlockInfo = (PDPH_BLOCK_INFORMATION)Block - 1;
+
+ /* Check stamps */
+ if (BlockInfo->StartStamp != DPH_FILL_START_STAMP_1)
+ {
+ *ValidationInformation |= DPH_VALINFO_BAD_START_STAMP;
+ SomethingWrong = TRUE;
+
+ /* Check if it has an alloc/free mismatch */
+ if (BlockInfo->StartStamp == DPH_FILL_START_STAMP_2)
+ {
+ /* Notify respectively */
+ *ValidationInformation = 0x101;
+ }
+ }
+
+ if (BlockInfo->EndStamp != DPH_FILL_END_STAMP_1)
+ {
+ *ValidationInformation |= DPH_VALINFO_BAD_END_STAMP;
+ SomethingWrong = TRUE;
+ }
+
+ /* Check root heap pointer */
+ if (BlockInfo->Heap != DphRoot)
+ {
+ *ValidationInformation |= DPH_VALINFO_BAD_POINTER;
+ SomethingWrong = TRUE;
+ }
+
+ /* Check other fillers if requested */
+ if (CheckFillers)
+ {
+ /* Check space after the block */
+ Start = (PUCHAR)Block + BlockInfo->RequestedSize;
+ End = (PUCHAR)ROUND_UP(Start, PAGE_SIZE);
+ for (Byte = Start; Byte < End; Byte++)
+ {
+ if (*Byte != DPH_FILL_BLOCK_END)
+ {
+ *ValidationInformation |= DPH_VALINFO_BAD_END_FILL;
+ SomethingWrong = TRUE;
+ break;
+ }
+ }
+ }
+
+ return (SomethingWrong == FALSE);
}
NTSTATUS NTAPI
@@ -926,7 +1147,82 @@
PVOID NTAPI
RtlpPageHeapDestroy(HANDLE HeapPtr)
{
- return FALSE;
+ PDPH_HEAP_ROOT DphRoot;
+ PDPH_HEAP_BLOCK Node, Next;
+ PHEAP NormalHeap;
+ ULONG Value;
+
+ /* Check if it's not a process heap */
+ if (HeapPtr == RtlGetProcessHeap())
+ {
+ DbgBreakPoint();
+ return NULL;
+ }
+
+ /* Get pointer to the heap root */
+ DphRoot = RtlpDphPointerFromHandle(HeapPtr);
+ if (!DphRoot) return NULL;
+
+ RtlpDphPreProcessing(DphRoot, DphRoot->HeapFlags);
+
+ /* Get the pointer to the normal heap */
+ NormalHeap = DphRoot->NormalHeap;
+
+ /* Free the delayed-free blocks */
+ RtlpDphFreeDelayedBlocksFromHeap(DphRoot, NormalHeap);
+
+ /* Go through the busy blocks */
+ Node = RtlEnumerateGenericTableAvl(&DphRoot->BusyNodesTable, TRUE);
+
+ while (Node)
+ {
+ if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_CORRUPTED_BLOCKS))
+ {
+ if (!RtlpDphIsPageHeapBlock(DphRoot, Node->pUserAllocation, &Value,
TRUE))
+ {
+ RtlpDphReportCorruptedBlock(DphRoot, 3, Node->pUserAllocation,
Value);
+ }
+ }
+
+ /* FIXME: Call AV notification */
+ //AVrfInternalHeapFreeNotification();
+
+ /* Go to the next node */
+ Node = RtlEnumerateGenericTableAvl(&DphRoot->BusyNodesTable, FALSE);
+ }
+
+ /* Acquire the global heap list lock */
+ RtlEnterCriticalSection(&RtlpDphPageHeapListLock);
+
+ /* Remove the entry and decrement the global counter */
+ RemoveEntryList(&DphRoot->NextHeap);
+ RtlpDphPageHeapListLength--;
+
+ /* Release the global heap list lock */
+ RtlLeaveCriticalSection(&RtlpDphPageHeapListLock);
+
+ /* Leave and delete this heap's critical section */
+ RtlLeaveCriticalSection(DphRoot->HeapCritSect);
+ RtlDeleteCriticalSection(DphRoot->HeapCritSect);
+
+ /* Now go through all virtual list nodes and release the VM */
+ Node = DphRoot->pVirtualStorageListHead;
+ while (Node)
+ {
+ Next = Node->pNextAlloc;
+ /* Release the memory without checking result */
+ RtlpDphFreeVm(Node->pVirtualBlock, 0, MEM_RELEASE);
+ Node = Next;
+ }
+
+ /* Destroy the normal heap */
+ RtlDestroyHeap(NormalHeap);
+
+ /* Report success */
+ if (RtlpDphDebugOptions & DPH_DEBUG_VERBOSE)
+ DPRINT1("Page heap: process 0x%X destroyed heap @ %p (%p)\n",
NtCurrentTeb()->ClientId.UniqueProcess, HeapPtr, NormalHeap);
+
+ return NULL;
}
PVOID NTAPI