[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / mm / anonmem.c
index 9aaa9a0..a7c3dd2 100644 (file)
@@ -1033,11 +1033,11 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
         /* Check for user-mode parameters */
         if (PreviousMode != KernelMode)
         {
-            /* Make sure they are writable */
+            /* Make sure they are writeable */
             ProbeForWritePointer(UBaseAddress);
             ProbeForWriteUlong(URegionSize);
         }
-        
+
         /* Capture their values */
         PBaseAddress = *UBaseAddress;
         PRegionSize = *URegionSize;
@@ -1090,8 +1090,6 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
     }
 
     BaseAddress = (PVOID)PAGE_ROUND_DOWN((PBaseAddress));
-    RegionSize = PAGE_ROUND_UP((ULONG_PTR)(PBaseAddress) + (PRegionSize)) -
-        PAGE_ROUND_DOWN((PBaseAddress));
 
     AddressSpace = &Process->Vm;
 
@@ -1099,26 +1097,69 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
     MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
     if (MemoryArea == NULL)
     {
-        Status = STATUS_UNSUCCESSFUL;
+        DPRINT1("Unable to find memory area from address 0x%p\n", BaseAddress);
+        Status = STATUS_UNABLE_TO_FREE_VM;
         goto unlock_deref_and_return;
     }
 
+    if (PRegionSize != 0)
+    {
+        /* Use the region the caller wanted, rounded to whole pages */
+        RegionSize = PAGE_ROUND_UP((ULONG_PTR)(PBaseAddress) + (PRegionSize)) -
+        PAGE_ROUND_DOWN((PBaseAddress));
+    }
+    else
+    {
+        /* The caller wanted the whole memory area */
+        RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
+                     (ULONG_PTR)MemoryArea->StartingAddress;
+    }
+
     switch (FreeType)
     {
     case MEM_RELEASE:
-        /* We can only free a memory area in one step. */
-        if (MemoryArea->StartingAddress != BaseAddress ||
-                MemoryArea->Type != MEMORY_AREA_VIRTUAL_MEMORY)
+        /* MEM_RELEASE must be used with the exact base and length
+         * that was returned by NtAllocateVirtualMemory */
+            
+        /* Verify the base address is correct */
+        if (MemoryArea->StartingAddress != BaseAddress)
+        {
+            DPRINT1("Base address is illegal for MEM_RELEASE (0x%p != 0x%p)\n",
+                    MemoryArea->StartingAddress,
+                    BaseAddress);
+            Status = STATUS_UNABLE_TO_FREE_VM;
+            goto unlock_deref_and_return;
+        }
+
+        /* Verify the region size is correct */
+        if ((ULONG_PTR)MemoryArea->StartingAddress + RegionSize !=
+            (ULONG_PTR)MemoryArea->EndingAddress)
+        {
+            DPRINT1("Region size is illegal for MEM_RELEASE (0x%x)\n", RegionSize);
+            Status = STATUS_UNABLE_TO_FREE_VM;
+            //goto unlock_deref_and_return;
+        }
+
+        if (MemoryArea->Type != MEMORY_AREA_VIRTUAL_MEMORY)
         {
-            Status = STATUS_UNSUCCESSFUL;
+            DPRINT1("Memory area is not VM\n");
+            Status = STATUS_UNABLE_TO_FREE_VM;
             goto unlock_deref_and_return;
         }
 
         MmFreeVirtualMemory(Process, MemoryArea);
         Status = STATUS_SUCCESS;
-        goto unlock_deref_and_return;
+        break;
 
     case MEM_DECOMMIT:
+        if ((ULONG_PTR)BaseAddress + RegionSize >
+            (ULONG_PTR)MemoryArea->EndingAddress)
+        {
+            DPRINT1("Invald base address (0x%p) and region size (0x%x) for MEM_DECOMMIT\n",
+                    BaseAddress, RegionSize);
+            Status = STATUS_UNABLE_TO_FREE_VM;
+            goto unlock_deref_and_return;
+        }
         Status = MmAlterRegion(AddressSpace,
             MemoryArea->StartingAddress,
             (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) ?
@@ -1129,13 +1170,34 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
             MEM_RESERVE,
             PAGE_NOACCESS,
             MmModifyAttributes);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("MmAlterRegion failed with status 0x%x\n", Status);
+            Status = STATUS_UNABLE_TO_FREE_VM;
+            goto unlock_deref_and_return;
+        }
+        break;
+
+    default:
+        Status = STATUS_NOT_IMPLEMENTED;
         goto unlock_deref_and_return;
     }
 
-    Status = STATUS_NOT_IMPLEMENTED;
-
-    unlock_deref_and_return:
+    /* Enter SEH */
+    _SEH2_TRY
+    {
+        /* Copy rounded values back in success case */
+        *UBaseAddress = BaseAddress;
+        *URegionSize = RegionSize;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+        DPRINT1("Failed to copy values back! (Status: 0x%x)\n", Status);
+    }
+    _SEH2_END;
 
+unlock_deref_and_return:
     MmUnlockAddressSpace(AddressSpace);
     if (Attached) KeUnstackDetachProcess(&ApcState);
     if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);