[RTL/DPH]
authorAleksey Bragin <aleksey@reactos.org>
Wed, 23 Feb 2011 11:08:37 +0000 (11:08 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Wed, 23 Feb 2011 11:08:37 +0000 (11:08 +0000)
- Implement DPH version of ReAllocateHeap. Scenario of falling back to normal heap is stubbed everywhere now.
- Fix a bug in POINTER_ADD_BIAS which noone noticed.

svn path=/trunk/; revision=50872

reactos/lib/rtl/heap.c
reactos/lib/rtl/heappage.c

index bb81fc3..9b0a6f7 100644 (file)
@@ -1362,12 +1362,11 @@ RtlCreateHeap(ULONG Flags,
         Heap = RtlpPageHeapCreate(Flags, Addr, TotalSize, CommitSize, Lock, Parameters);
         if (Heap) return Heap;
 
-        //ASSERT(FALSE);
-        DPRINT1("Enabling page heap failed\n");
-
         /* Reset a special Parameters == -1 hack */
         if ((ULONG_PTR)Parameters == (ULONG_PTR)-1)
             Parameters = NULL;
+        else
+            DPRINT1("Enabling page heap failed\n");
     }
 
     /* Check validation flags */
index 41a7772..7631833 100644 (file)
@@ -174,7 +174,7 @@ LONG RtlpDphProtectFails;
 /* Biased pointer macros */
 #define IS_BIASED_POINTER(ptr) ((ULONG_PTR)(ptr) & 1)
 #define POINTER_REMOVE_BIAS(ptr) ((ULONG_PTR)(ptr) & ~(ULONG_PTR)1)
-#define POINTER_ADD_BIAS(ptr) ((ULONG_PTR)(ptr) & 1)
+#define POINTER_ADD_BIAS(ptr) ((ULONG_PTR)(ptr) | 1)
 
 
 ULONG RtlpDphBreakOptions = 0;//0xFFFFFFFF;
@@ -1896,8 +1896,167 @@ RtlpPageHeapReAllocate(HANDLE HeapPtr,
                        PVOID Ptr,
                        SIZE_T Size)
 {
-    UNIMPLEMENTED;
-    return NULL;
+    PDPH_HEAP_ROOT DphRoot;
+    PDPH_HEAP_BLOCK Node = NULL, AllocatedNode;
+    BOOLEAN Biased = FALSE, UseNormalHeap = FALSE, OldBlockPageHeap = TRUE;
+    ULONG DataSize, ValidationInfo;
+    PVOID NewAlloc = NULL;
+
+    /* 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 */
+    RtlpDphPreProcessing(DphRoot, Flags);
+
+    /* Perform internal validation if specified by flags */
+    if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE)
+    {
+        RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0);
+    }
+
+    /* Add heap flags */
+    Flags |= DphRoot->HeapFlags;
+
+    /* Exit with NULL right away if inplace is specified */
+    if (Flags & HEAP_REALLOC_IN_PLACE_ONLY)
+    {
+        /* Release the lock */
+        RtlpDphPostProcessing(DphRoot);
+
+        /* Generate an exception if needed */
+        if (Flags & HEAP_GENERATE_EXCEPTIONS) RtlpDphRaiseException(STATUS_NO_MEMORY);
+
+        return NULL;
+    }
+
+    /* Try to get node of the allocated block */
+    AllocatedNode = RtlpDphFindBusyMemory(DphRoot, Ptr);
+
+    if (!AllocatedNode)
+    {
+        /* This block was not found in page heap, try a normal heap instead */
+        //RtlpDphNormalHeapFree();
+        ASSERT(FALSE);
+        OldBlockPageHeap = FALSE;
+    }
+
+    /* Check the block */
+    if (!(DphRoot->ExtraFlags & DPH_EXTRA_CHECK_UNDERRUN))
+    {
+        if (!RtlpDphIsPageHeapBlock(DphRoot, AllocatedNode->pUserAllocation, &ValidationInfo, TRUE))
+        {
+            RtlpDphReportCorruptedBlock(DphRoot, 3, AllocatedNode->pUserAllocation, ValidationInfo);
+        }
+    }
+
+    /* Remove old one from the busy list */
+    RtlpDphRemoveFromBusyList(DphRoot, AllocatedNode);
+
+    if (!Biased && !RtlpDphShouldAllocateInPageHeap(DphRoot, Size))
+    {
+        // FIXME: Use normal heap
+        ASSERT(FALSE);
+        UseNormalHeap = TRUE;
+    }
+    else
+    {
+        /* Now do a trick: bias the pointer and call our allocate routine */
+        NewAlloc = RtlpPageHeapAllocate((PVOID)POINTER_ADD_BIAS(HeapPtr), Flags, Size);
+    }
+
+    if (!NewAlloc)
+    {
+        /* New allocation failed, put the block back (if it was found in page heap) */
+        RtlpDphPlaceOnBusyList(DphRoot, AllocatedNode);
+
+        /* Release the lock */
+        RtlpDphPostProcessing(DphRoot);
+
+        /* Perform validation again if required */
+        if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE)
+        {
+            RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0);
+        }
+
+        /* Generate an exception if needed */
+        if (Flags & HEAP_GENERATE_EXCEPTIONS) RtlpDphRaiseException(STATUS_NO_MEMORY);
+
+        return NULL;
+    }
+
+    /* Copy contents of the old block */
+    if (AllocatedNode->nUserRequestedSize > Size)
+        DataSize = Size;
+    else
+        DataSize = AllocatedNode->nUserRequestedSize;
+
+    if (DataSize != 0) RtlCopyMemory(NewAlloc, Ptr, DataSize);
+
+    /* Copy user flags and values */
+    if (!UseNormalHeap)
+    {
+        /* Get the node of the new block */
+        Node = RtlpDphFindBusyMemory(DphRoot, NewAlloc);
+        ASSERT(Node != NULL);
+
+        /* Set its values/flags */
+        Node->UserValue = AllocatedNode->UserValue;
+        if (Flags & HEAP_SETTABLE_USER_FLAGS)
+            Node->UserFlags = Flags & HEAP_SETTABLE_USER_FLAGS;
+        else
+            Node->UserFlags = AllocatedNode->UserFlags;
+    }
+
+    if (!OldBlockPageHeap)
+    {
+        /* Weird scenario, investigate */
+        ASSERT(FALSE);
+    }
+
+    /* Mark the old block as no access */
+    if (AllocatedNode->nVirtualAccessSize != 0)
+    {
+        RtlpDphProtectVm(AllocatedNode->pVirtualBlock, AllocatedNode->nVirtualAccessSize, PAGE_NOACCESS);
+    }
+
+    /* And place it on the free list */
+    RtlpDphPlaceOnFreeList(DphRoot, AllocatedNode);
+
+    // FIXME: Capture stack traces if needed
+    AllocatedNode->StackTrace = NULL;
+
+    /* 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);
+
+    DPRINT("Allocated new user block pointer: %p\n", NewAlloc);
+
+    /* Return pointer to user allocation */
+    return NewAlloc;
 }
 
 BOOLEAN NTAPI