Author: fireball
Date: Sat Feb 12 16:38:00 2011
New Revision: 50667
URL:
http://svn.reactos.org/svn/reactos?rev=50667&view=rev
Log:
[RTL/DPH]
- Add core DPH (Debug Page Heap) structures based on Windows 2003/Vista.
- Add misc generic support routines.
- Implement DPH version of RtlCreateHeap().
- Debug prints match those printed by Windows 2003.
Modified:
trunk/reactos/dll/ntdll/ldr/startup.c
trunk/reactos/lib/rtl/heappage.c
Modified: trunk/reactos/dll/ntdll/ldr/startup.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/ntdll/ldr/startup.c?re…
==============================================================================
--- trunk/reactos/dll/ntdll/ldr/startup.c [iso-8859-1] (original)
+++ trunk/reactos/dll/ntdll/ldr/startup.c [iso-8859-1] Sat Feb 12 16:38:00 2011
@@ -74,9 +74,9 @@
UNICODE_STRING ImageName;
UNICODE_STRING ImagePathName;
ULONG ValueSize;
- extern ULONG RtlpPageHeapGlobalFlags, RtlpPageHeapSizeRangeStart,
RtlpPageHeapSizeRangeEnd;
+ extern ULONG RtlpDphGlobalFlags, RtlpPageHeapSizeRangeStart,
RtlpPageHeapSizeRangeEnd;
extern ULONG RtlpPageHeapDllRangeStart, RtlpPageHeapDllRangeEnd;
- extern WCHAR RtlpPageHeapTargetDlls[512];
+ extern WCHAR RtlpDphTargetDlls[512];
extern BOOLEAN RtlpPageHeapEnabled;
if (Peb->ProcessParameters &&
@@ -144,8 +144,8 @@
LdrQueryImageFileExecutionOptions(&ImageName,
L"PageHeapFlags",
REG_DWORD,
- (PVOID)&RtlpPageHeapGlobalFlags,
- sizeof(RtlpPageHeapGlobalFlags),
+ (PVOID)&RtlpDphGlobalFlags,
+ sizeof(RtlpDphGlobalFlags),
&ValueSize);
LdrQueryImageFileExecutionOptions(&ImageName,
@@ -179,8 +179,8 @@
LdrQueryImageFileExecutionOptions(&ImageName,
L"PageHeapTargetDlls",
REG_SZ,
- (PVOID)RtlpPageHeapTargetDlls,
- sizeof(RtlpPageHeapTargetDlls),
+ (PVOID)RtlpDphTargetDlls,
+ sizeof(RtlpDphTargetDlls),
&ValueSize);
/* Now when all parameters are read, enable page heap */
Modified: trunk/reactos/lib/rtl/heappage.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/heappage.c?rev=506…
==============================================================================
--- trunk/reactos/lib/rtl/heappage.c [iso-8859-1] (original)
+++ trunk/reactos/lib/rtl/heappage.c [iso-8859-1] Sat Feb 12 16:38:00 2011
@@ -17,13 +17,367 @@
#define NDEBUG
#include <debug.h>
+/* TYPES **********************************************************************/
+
+typedef struct _DPH_BLOCK_INFORMATION
+{
+ ULONG StartStamp;
+ PVOID Heap;
+ ULONG RequestedSize;
+ ULONG ActualSize;
+ union
+ {
+ LIST_ENTRY FreeQueue;
+ SINGLE_LIST_ENTRY FreePushList;
+ WORD TraceIndex;
+ };
+ PVOID StackTrace;
+ ULONG EndStamp;
+} DPH_BLOCK_INFORMATION, *PDPH_BLOCK_INFORMATION;
+
+typedef struct _DPH_HEAP_BLOCK
+{
+ union
+ {
+ struct _DPH_HEAP_BLOCK *pNextAlloc;
+ LIST_ENTRY AvailableEntry;
+ RTL_BALANCED_LINKS TableLinks;
+ };
+ PUCHAR pUserAllocation;
+ PUCHAR pVirtualBlock;
+ ULONG nVirtualBlockSize;
+ ULONG nVirtualAccessSize;
+ ULONG nUserRequestedSize;
+ ULONG nUserActualSize;
+ PVOID UserValue;
+ ULONG UserFlags;
+ PRTL_TRACE_BLOCK StackTrace;
+ LIST_ENTRY AdjacencyEntry;
+ PUCHAR pVirtualRegion;
+} DPH_HEAP_BLOCK, *PDPH_HEAP_BLOCK;
+
+typedef struct _DPH_HEAP_ROOT
+{
+ ULONG Signature;
+ ULONG HeapFlags;
+ PRTL_CRITICAL_SECTION HeapCritSect;
+ ULONG nRemoteLockAcquired;
+
+ PDPH_HEAP_BLOCK pVirtualStorageListHead;
+ PDPH_HEAP_BLOCK pVirtualStorageListTail;
+ ULONG nVirtualStorageRanges;
+ ULONG nVirtualStorageBytes;
+
+ RTL_AVL_TABLE BusyNodesTable;
+ PDPH_HEAP_BLOCK NodeToAllocate;
+ ULONG nBusyAllocations;
+ ULONG nBusyAllocationBytesCommitted;
+
+ PDPH_HEAP_BLOCK pFreeAllocationListHead;
+ PDPH_HEAP_BLOCK pFreeAllocationListTail;
+ ULONG nFreeAllocations;
+ ULONG nFreeAllocationBytesCommitted;
+
+ LIST_ENTRY AvailableAllocationHead;
+ ULONG nAvailableAllocations;
+ ULONG nAvailableAllocationBytesCommitted;
+
+ PDPH_HEAP_BLOCK pUnusedNodeListHead;
+ PDPH_HEAP_BLOCK pUnusedNodeListTail;
+ ULONG nUnusedNodes;
+ ULONG nBusyAllocationBytesAccessible;
+ PDPH_HEAP_BLOCK pNodePoolListHead;
+ PDPH_HEAP_BLOCK pNodePoolListTail;
+ ULONG nNodePools;
+ ULONG nNodePoolBytes;
+
+ LIST_ENTRY NextHeap;
+ ULONG ExtraFlags;
+ ULONG Seed;
+ PVOID NormalHeap;
+ PRTL_TRACE_BLOCK CreateStackTrace;
+ PVOID FirstThread;
+} DPH_HEAP_ROOT, *PDPH_HEAP_ROOT;
+
+/* GLOBALS ********************************************************************/
+
BOOLEAN RtlpPageHeapEnabled = FALSE;
-ULONG RtlpPageHeapGlobalFlags;
+ULONG RtlpDphGlobalFlags;
ULONG RtlpPageHeapSizeRangeStart, RtlpPageHeapSizeRangeEnd;
ULONG RtlpPageHeapDllRangeStart, RtlpPageHeapDllRangeEnd;
-WCHAR RtlpPageHeapTargetDlls[512];
+WCHAR RtlpDphTargetDlls[512];
+
+ULONG RtlpDphBreakOptions;
+ULONG RtlpDphDebugOptions;
+
+LIST_ENTRY RtlpDphPageHeapList;
+BOOLEAN RtlpDphPageHeapListInitialized;
+RTL_CRITICAL_SECTION RtlpDphPageHeapListLock;
+ULONG RtlpDphPageHeapListLength;
+UNICODE_STRING RtlpDphTargetDllsUnicode;
+
+/* Counters */
+LONG RtlpDphCounter;
+LONG RtlpDphAllocFails;
+LONG RtlpDphReleaseFails;
+LONG RtlpDphFreeFails;
+LONG RtlpDphProtectFails;
+
+#define DPH_RESERVE_SIZE 0x100000
+#define DPH_POOL_SIZE 0x4000
+
+/* RtlpDphBreakOptions */
+#define DPH_BREAK_ON_RESERVE_FAIL 0x01
+#define DPH_BREAK_ON_COMMIT_FAIL 0x02
+#define DPH_BREAK_ON_RELEASE_FAIL 0x04
+#define DPH_BREAK_ON_FREE_FAIL 0x08
+#define DPH_BREAK_ON_PROTECT_FAIL 0x10
+
+/* RtlpDphDebugOptions */
+#define DPH_DEBUG_INTERNAL_VALIDATE 0x01
+#define DPH_DEBUG_VERBOSE 0x04
+
+/* Fillers */
+#define DPH_FILL 0xEEEEEEEE
+
+/* Signatures */
+#define DPH_SIGNATURE 0xFFEEDDCC
/* FUNCTIONS ******************************************************************/
+
+NTSTATUS NTAPI
+RtlpSecMemFreeVirtualMemory(HANDLE Process, PVOID *Base, PSIZE_T Size, ULONG Type)
+{
+ NTSTATUS Status;
+ //PVOID *SavedBase = Base;
+ //PSIZE_T SavedSize = Size;
+
+ /* Free the memory */
+ Status = ZwFreeVirtualMemory(Process, Base, Size, Type);
+
+ /* Flush secure memory cache if needed and retry freeing */
+#if 0
+ if (Status == STATUS_INVALID_PAGE_PROTECTION &&
+ Process == NtCurrentProcess() &&
+ RtlFlushSecureMemoryCache(*SavedBase, *SavedSize))
+ {
+ Status = ZwFreeVirtualMemory(NtCurrentProcess(), SavedBase, SavedSize, Type);
+ }
+#endif
+
+ return Status;
+}
+
+NTSTATUS NTAPI
+RtlpDphAllocateVm(PVOID *Base, SIZE_T Size, ULONG Type, ULONG Protection)
+{
+ NTSTATUS Status;
+ Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
+ Base,
+ 0,
+ &Size,
+ Type,
+ Protection);
+
+ /* Check for failures */
+ if (!NT_SUCCESS(Status))
+ {
+ if (Type == MEM_RESERVE)
+ {
+ _InterlockedIncrement(&RtlpDphCounter);
+ if (RtlpDphBreakOptions & DPH_BREAK_ON_RESERVE_FAIL)
+ {
+ DPRINT1("Page heap: AllocVm (%p, %p, %x) failed with %x \n",
Base, Size, Type, Status);
+ DbgBreakPoint();
+ return Status;
+ }
+ }
+ else
+ {
+ _InterlockedIncrement(&RtlpDphAllocFails);
+ if (RtlpDphBreakOptions & DPH_BREAK_ON_COMMIT_FAIL)
+ {
+ DPRINT1("Page heap: AllocVm (%p, %p, %x) failed with %x \n",
Base, Size, Type, Status);
+ DbgBreakPoint();
+ return Status;
+ }
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS NTAPI
+RtlpDphFreeVm(PVOID Base, SIZE_T Size, ULONG Type, ULONG Protection)
+{
+ NTSTATUS Status;
+
+ /* Free the memory */
+ Status = RtlpSecMemFreeVirtualMemory(NtCurrentProcess(), &Base, &Size,
Type);
+
+ /* Log/report failures */
+ if (!NT_SUCCESS(Status))
+ {
+ if (Type == MEM_RELEASE)
+ {
+ _InterlockedIncrement(&RtlpDphReleaseFails);
+ if (RtlpDphBreakOptions & DPH_BREAK_ON_RELEASE_FAIL)
+ {
+ DPRINT1("Page heap: FreeVm (%p, %p, %x) failed with %x \n",
Base, Size, Type, Status);
+ DbgBreakPoint();
+ return Status;
+ }
+ }
+ else
+ {
+ _InterlockedIncrement(&RtlpDphFreeFails);
+ if (RtlpDphBreakOptions & DPH_BREAK_ON_FREE_FAIL)
+ {
+ DPRINT1("Page heap: FreeVm (%p, %p, %x) failed with %x \n",
Base, Size, Type, Status);
+ DbgBreakPoint();
+ return Status;
+ }
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS NTAPI
+RtlpDphProtectVm(PVOID Base, SIZE_T Size, ULONG Protection)
+{
+ NTSTATUS Status;
+ ULONG OldProtection;
+
+ /* Change protection */
+ Status = ZwProtectVirtualMemory(NtCurrentProcess(), &Base, &Size, Protection,
&OldProtection);
+
+ /* Log/report failures */
+ if (!NT_SUCCESS(Status))
+ {
+ _InterlockedIncrement(&RtlpDphProtectFails);
+ if (RtlpDphBreakOptions & DPH_BREAK_ON_PROTECT_FAIL)
+ {
+ DPRINT1("Page heap: ProtectVm (%p, %p, %x) failed with %x \n",
Base, Size, Protection, Status);
+ DbgBreakPoint();
+ return Status;
+ }
+ }
+
+ return Status;
+}
+
+VOID NTAPI
+RtlpDphAddNewPool(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK NodeBlock, PVOID Virtual,
SIZE_T Size, BOOLEAN Add)
+{
+ UNIMPLEMENTED;
+}
+
+PDPH_HEAP_BLOCK NTAPI
+RtlpDphAllocateNode(PDPH_HEAP_ROOT DphRoot)
+{
+ UNIMPLEMENTED;
+ return NULL;
+}
+
+VOID NTAPI
+RtlpDphPlaceOnPoolList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK DphNode)
+{
+ UNIMPLEMENTED;
+}
+
+VOID NTAPI
+RtlpDphPlaceOnVirtualList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK DphNode)
+{
+ UNIMPLEMENTED;
+}
+
+VOID NTAPI
+RtlpDphCoalesceNodeIntoAvailable(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK DphNode)
+{
+ UNIMPLEMENTED;
+}
+
+RTL_GENERIC_COMPARE_RESULTS
+NTAPI
+RtlpDphCompareNodeForTable(IN PRTL_AVL_TABLE Table,
+ IN PVOID FirstStruct,
+ IN PVOID SecondStruct)
+{
+ /* FIXME: TODO */
+ ASSERT(FALSE);
+ return 0;
+}
+
+PVOID
+NTAPI
+RtlpDphAllocateNodeForTable(IN PRTL_AVL_TABLE Table,
+ IN CLONG ByteSize)
+{
+ /* FIXME: TODO */
+ ASSERT(FALSE);
+ return NULL;
+}
+
+VOID
+NTAPI
+RtlpDphFreeNodeForTable(IN PRTL_AVL_TABLE Table,
+ IN PVOID Buffer)
+{
+ /* FIXME: TODO */
+ ASSERT(FALSE);
+}
+
+NTSTATUS NTAPI
+RtlpDphInitializeDelayedFreeQueue()
+{
+ UNIMPLEMENTED;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS NTAPI
+RtlpDphTargetDllsLogicInitialize()
+{
+ UNIMPLEMENTED;
+ return STATUS_SUCCESS;
+}
+
+VOID NTAPI
+RtlpDphInternalValidatePageHeap(PDPH_HEAP_ROOT DphRoot, PVOID Address, ULONG Value)
+{
+ UNIMPLEMENTED;
+}
+
+NTSTATUS NTAPI
+RtlpDphProcessStartupInitialization()
+{
+ NTSTATUS Status;
+ PTEB Teb = NtCurrentTeb();
+
+ /* Initialize the DPH heap list and its critical section */
+ InitializeListHead(&RtlpDphPageHeapList);
+ Status = RtlInitializeCriticalSection(&RtlpDphPageHeapListLock);
+ if (!NT_SUCCESS(Status))
+ {
+ ASSERT(FALSE);
+ return Status;
+ }
+
+ /* Initialize delayed-free queue */
+ Status = RtlpDphInitializeDelayedFreeQueue();
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Initialize the target dlls string */
+ RtlInitUnicodeString(&RtlpDphTargetDllsUnicode, RtlpDphTargetDlls);
+ Status = RtlpDphTargetDllsLogicInitialize();
+
+ /* Per-process DPH init is done */
+ RtlpDphPageHeapListInitialized = TRUE;
+
+ DPRINT1("Page heap: pid 0x%X: page heap enabled with flags 0x%X.\n",
Teb->ClientId.UniqueProcess, RtlpDphGlobalFlags);
+
+ return Status;
+}
HANDLE NTAPI
RtlpPageHeapCreate(ULONG Flags,
@@ -33,7 +387,135 @@
PVOID Lock,
PRTL_HEAP_PARAMETERS Parameters)
{
- return NULL;
+ PVOID Base;
+ PHEAP HeapPtr;
+ PDPH_HEAP_ROOT DphRoot;
+ PDPH_HEAP_BLOCK DphNode;
+ ULONG MemSize;
+ NTSTATUS Status;
+ LARGE_INTEGER PerfCounter;
+
+ /* Check for a DPH bypass flag */
+ if ((ULONG_PTR)Parameters == -1) return NULL;
+
+ /* Make sure no user-allocated stuff was provided */
+ if (Addr || Lock) return NULL;
+
+ /* Allocate minimum amount of virtual memory */
+ MemSize = DPH_RESERVE_SIZE;
+ Status = RtlpDphAllocateVm(&Base, MemSize, MEM_COMMIT, PAGE_NOACCESS);
+ if (!NT_SUCCESS(Status))
+ {
+ ASSERT(FALSE);
+ return NULL;
+ }
+
+ /* Set protection */
+ Status = RtlpDphProtectVm(Base, 2*PAGE_SIZE + DPH_POOL_SIZE, PAGE_READWRITE);
+ if (!NT_SUCCESS(Status))
+ {
+ //RtlpDphFreeVm(Base, 0, 0, 0);
+ ASSERT(FALSE);
+ return NULL;
+ }
+
+ /* Start preparing the 1st page. Fill it with the default filler */
+ RtlFillMemory(Base, PAGE_SIZE, DPH_FILL);
+
+ /* Set flags in the "HEAP" structure */
+ HeapPtr = (PHEAP)Base;
+ HeapPtr->Flags = Flags | HEAP_FLAG_PAGE_ALLOCS;
+ HeapPtr->ForceFlags = Flags | HEAP_FLAG_PAGE_ALLOCS;
+
+ /* Set 1st page to read only now */
+ Status = RtlpDphProtectVm(Base, PAGE_SIZE, PAGE_READONLY);
+ if (!NT_SUCCESS(Status))
+ {
+ ASSERT(FALSE);
+ return NULL;
+ }
+
+ /* 2nd page is the real DPH root block */
+ DphRoot = (PDPH_HEAP_ROOT)((PCHAR)Base + PAGE_SIZE);
+
+ /* Initialize the DPH root */
+ DphRoot->Signature = DPH_SIGNATURE;
+ DphRoot->HeapFlags = Flags;
+ DphRoot->HeapCritSect = (PRTL_CRITICAL_SECTION)((PCHAR)DphRoot + DPH_POOL_SIZE);
+ DphRoot->ExtraFlags = RtlpDphGlobalFlags;
+
+ ZwQueryPerformanceCounter(&PerfCounter, NULL);
+ DphRoot->Seed = PerfCounter.LowPart;
+
+ RtlInitializeCriticalSection(DphRoot->HeapCritSect);
+
+ /* Create a normal heap for this paged heap */
+ DphRoot->NormalHeap = RtlCreateHeap(Flags, NULL, TotalSize, CommitSize, NULL,
(PRTL_HEAP_PARAMETERS)-1);
+ if (!DphRoot->NormalHeap)
+ {
+ ASSERT(FALSE);
+ return NULL;
+ }
+
+ /* 3rd page: a pool for DPH allocations */
+ RtlpDphAddNewPool(DphRoot, NULL, DphRoot + 1, DPH_POOL_SIZE - sizeof(DPH_HEAP_ROOT),
FALSE);
+
+ /* Allocate internal heap blocks. For the root */
+ DphNode = RtlpDphAllocateNode(DphRoot);
+ ASSERT(DphNode != NULL);
+ DphNode->pVirtualBlock = (PUCHAR)DphRoot;
+ DphNode->nVirtualBlockSize = DPH_POOL_SIZE;
+ RtlpDphPlaceOnPoolList(DphRoot, DphNode);
+
+ /* For the memory we allocated as a whole */
+ DphNode = RtlpDphAllocateNode(DphRoot);
+ ASSERT(DphNode != NULL);
+ DphNode->pVirtualBlock = Base;
+ DphNode->nVirtualBlockSize = MemSize;
+ RtlpDphPlaceOnVirtualList(DphRoot, DphNode);
+
+ /* For the remaining part */
+ DphNode = RtlpDphAllocateNode(DphRoot);
+ ASSERT(DphNode != NULL);
+ DphNode->pVirtualBlock = (PUCHAR)Base + 2*PAGE_SIZE + DPH_POOL_SIZE;
+ DphNode->nVirtualBlockSize = MemSize - (2*PAGE_SIZE + DPH_POOL_SIZE);
+ RtlpDphCoalesceNodeIntoAvailable(DphRoot, DphNode);
+
+ //DphRoot->CreateStackTrace = RtlpDphLogStackTrace(1);
+
+ /* Initialize AVL-based busy nodes table */
+ RtlInitializeGenericTableAvl(&DphRoot->BusyNodesTable,
+ RtlpDphCompareNodeForTable,
+ RtlpDphAllocateNodeForTable,
+ RtlpDphFreeNodeForTable,
+ NULL);
+
+ /* Initialize per-process startup info */
+ if (!RtlpDphPageHeapListInitialized) RtlpDphProcessStartupInitialization();
+
+ /* Acquire the heap list lock */
+ RtlEnterCriticalSection(&RtlpDphPageHeapListLock);
+
+ /* Insert this heap to the tail of the global list */
+ InsertTailList(&RtlpDphPageHeapList, &DphRoot->NextHeap);
+
+ /* Note we increased the size of the list */
+ RtlpDphPageHeapListLength++;
+
+ /* Release the heap list lock */
+ RtlLeaveCriticalSection(&RtlpDphPageHeapListLock);
+
+ if (RtlpDphDebugOptions & DPH_DEBUG_VERBOSE)
+ {
+ DPRINT1("Page heap: process 0x%X created heap @ %p (%p, flags
0x%X)\n",
+ NtCurrentTeb()->ClientId.UniqueProcess, (PUCHAR)DphRoot - PAGE_SIZE,
DphRoot->NormalHeap, DphRoot->ExtraFlags);
+ }
+
+ /* Perform internal validation if required */
+ if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE)
+ RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0);
+
+ return (PUCHAR)DphRoot - PAGE_SIZE;
}
PVOID NTAPI