[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.

svn path=/trunk/; revision=50721
This commit is contained in:
Aleksey Bragin 2011-02-15 22:02:28 +00:00
parent a92739091b
commit d0e56f53d1

View file

@ -139,8 +139,21 @@ LONG RtlpDphProtectFails;
#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
@ -155,6 +168,67 @@ LONG RtlpDphProtectFails;
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 @@ RtlpDphAllocateVm(PVOID *Base, SIZE_T Size, ULONG Type, ULONG Protection)
}
NTSTATUS NTAPI
RtlpDphFreeVm(PVOID Base, SIZE_T Size, ULONG Type, ULONG Protection)
RtlpDphFreeVm(PVOID Base, SIZE_T Size, ULONG Type)
{
NTSTATUS Status;
@ -362,6 +436,28 @@ RtlpDphRemoveFromAvailableList(PDPH_HEAP_ROOT DphRoot,
POINTER_REMOVE_BIAS(Node->AdjacencyEntry.Blink);
}
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 @@ RtlpDphCoalesceNodeIntoAvailable(PDPH_HEAP_ROOT DphRoot,
VOID NTAPI
RtlpDphCoalesceFreeIntoAvailable(PDPH_HEAP_ROOT DphRoot,
ULONG Size)
ULONG LeaveOnFreeList)
{
UNIMPLEMENTED;
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 @@ RtlpDphAllocateNode(PDPH_HEAP_ROOT DphRoot)
{
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 @@ RtlpDphAllocateNode(PDPH_HEAP_ROOT DphRoot)
{
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 @@ RtlpDphAllocateNode(PDPH_HEAP_ROOT DphRoot)
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 @@ RtlpDphAllocateNode(PDPH_HEAP_ROOT DphRoot)
/* 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 @@ RtlpDphAllocateNode(PDPH_HEAP_ROOT DphRoot)
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 @@ RtlpDphCompareNodeForTable(IN PRTL_AVL_TABLE Table,
IN PVOID FirstStruct,
IN PVOID SecondStruct)
{
/* FIXME: TODO */
UNIMPLEMENTED;
ASSERT(FALSE);
return 0;
}
@ -719,7 +861,7 @@ NTAPI
RtlpDphAllocateNodeForTable(IN PRTL_AVL_TABLE Table,
IN CLONG ByteSize)
{
/* FIXME: TODO */
UNIMPLEMENTED;
ASSERT(FALSE);
return NULL;
}
@ -729,7 +871,7 @@ NTAPI
RtlpDphFreeNodeForTable(IN PRTL_AVL_TABLE Table,
IN PVOID Buffer)
{
/* FIXME: TODO */
UNIMPLEMENTED;
ASSERT(FALSE);
}
@ -740,6 +882,13 @@ RtlpDphInitializeDelayedFreeQueue()
return STATUS_SUCCESS;
}
VOID NTAPI
RtlpDphFreeDelayedBlocksFromHeap(PDPH_HEAP_ROOT DphRoot,
PHEAP NormalHeap)
{
UNIMPLEMENTED;
}
NTSTATUS NTAPI
RtlpDphTargetDllsLogicInitialize()
{
@ -753,6 +902,78 @@ RtlpDphInternalValidatePageHeap(PDPH_HEAP_ROOT DphRoot, PVOID Address, ULONG Val
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
RtlpDphProcessStartupInitialization()
{
@ -926,7 +1147,82 @@ RtlpPageHeapCreate(ULONG Flags,
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