mirror of
https://github.com/reactos/reactos.git
synced 2024-12-04 08:53:32 +08:00
7f208124c9
* Fix 1 failure on both WS03 and ReactOS. * Create CheckSomeDefaultAddresses(), with additional checks. * Update license header. * ROSTESTS-297
795 lines
27 KiB
C
795 lines
27 KiB
C
/*
|
|
* PROJECT: ReactOS API Tests
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: Test for NtAllocateVirtualMemory
|
|
* COPYRIGHT: Copyright 2011 Thomas Faber <thomas.faber@reactos.org>
|
|
* Copyright 2013 Timo Kreuzer <timo.kreuzer@reactos.org>
|
|
* Copyright 2015 Jérôme Gardou <jerome.gardou@reactos.org>
|
|
* Copyright 2018 Serge Gautherie <reactos-git_serge_171003@gautherie.fr>
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
static PVOID Allocations[4096] = { NULL };
|
|
static ULONG CurrentAllocation = 0;
|
|
|
|
static
|
|
VOID
|
|
ValidateAllocations(VOID)
|
|
{
|
|
ULONG i;
|
|
|
|
ASSERT(CurrentAllocation < sizeof(Allocations) / sizeof(Allocations[0]));
|
|
for (i = 0; i < CurrentAllocation; ++i)
|
|
{
|
|
PUCHAR UserBuffer = Allocations[i];
|
|
SIZE_T AllocationSize;
|
|
SIZE_T DataSize;
|
|
|
|
if (UserBuffer == NULL)
|
|
continue;
|
|
|
|
AllocationSize = ((PSIZE_T)UserBuffer)[-2];
|
|
DataSize = ((PSIZE_T)UserBuffer)[-1];
|
|
ASSERT(AllocationSize != 0);
|
|
ASSERT(AllocationSize % PAGE_SIZE == 0);
|
|
ASSERT(DataSize != 0);
|
|
ASSERT(((SIZE_T)UserBuffer + DataSize) % PAGE_SIZE == 0);
|
|
}
|
|
}
|
|
|
|
static
|
|
PVOID
|
|
Allocate(
|
|
SIZE_T DataSize)
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID AllocationStart = NULL;
|
|
SIZE_T AllocationSize = PAGE_ROUND_UP(DataSize + PAGE_SIZE + 2 * sizeof(SIZE_T));
|
|
PVOID FirstPageStart;
|
|
SIZE_T NumberOfPages = AllocationSize / PAGE_SIZE;
|
|
SIZE_T Size;
|
|
PUCHAR UserBuffer;
|
|
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(), &AllocationStart, 0, &AllocationSize, MEM_RESERVE, PAGE_NOACCESS);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
return NULL;
|
|
|
|
FirstPageStart = (PUCHAR)AllocationStart + AllocationSize - PAGE_SIZE * NumberOfPages;
|
|
Size = (NumberOfPages - 1) * PAGE_SIZE;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(), &FirstPageStart, 0, &Size, MEM_COMMIT, PAGE_READWRITE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
AllocationSize = 0;
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &AllocationStart, &AllocationSize, MEM_RELEASE);
|
|
ASSERT(Status == STATUS_SUCCESS);
|
|
return NULL;
|
|
}
|
|
ASSERT(Size % sizeof(ULONG) == 0);
|
|
ASSERT(RtlCompareMemoryUlong(FirstPageStart, Size, 0) == Size);
|
|
|
|
UserBuffer = AllocationStart;
|
|
UserBuffer += AllocationSize - PAGE_SIZE - DataSize;
|
|
RtlFillMemory(FirstPageStart, UserBuffer - (PUCHAR)FirstPageStart, 0xae);
|
|
RtlZeroMemory(UserBuffer, DataSize);
|
|
((PSIZE_T)UserBuffer)[-2] = AllocationSize;
|
|
((PSIZE_T)UserBuffer)[-1] = DataSize;
|
|
|
|
Allocations[CurrentAllocation++] = UserBuffer;
|
|
ValidateAllocations();
|
|
return UserBuffer;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
Free(
|
|
PVOID UserBuffer)
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID AllocationStart;
|
|
SIZE_T Zero = 0;
|
|
SIZE_T AllocationSize;
|
|
SIZE_T DataSize;
|
|
ULONG i;
|
|
|
|
AllocationSize = ((PSIZE_T)UserBuffer)[-2];
|
|
DataSize = ((PSIZE_T)UserBuffer)[-1];
|
|
ASSERT(DataSize != 0);
|
|
|
|
AllocationStart = (PUCHAR)UserBuffer + DataSize + PAGE_SIZE - AllocationSize;
|
|
ASSERT((SIZE_T)AllocationStart % PAGE_SIZE == 0);
|
|
|
|
RtlFillMemory(UserBuffer, DataSize, 0xbe);
|
|
((PSIZE_T)UserBuffer)[-1] = 0;
|
|
((PSIZE_T)UserBuffer)[-2] = 0xFAFBFCFD;
|
|
|
|
for (i = 0; i < CurrentAllocation; ++i)
|
|
if (Allocations[i] == UserBuffer)
|
|
{
|
|
Allocations[i] = NULL;
|
|
break;
|
|
}
|
|
ValidateAllocations();
|
|
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &AllocationStart, &Zero, MEM_RELEASE);
|
|
ASSERT(Status == STATUS_SUCCESS);
|
|
}
|
|
|
|
static
|
|
PVOID
|
|
ReAllocate(
|
|
PVOID OldUserBuffer,
|
|
SIZE_T NewDataSize)
|
|
{
|
|
PVOID NewUserBuffer;
|
|
SIZE_T OldDataSize;
|
|
|
|
OldDataSize = ((PSIZE_T)OldUserBuffer)[-1];
|
|
ASSERT(OldDataSize != 0);
|
|
|
|
NewUserBuffer = Allocate(NewDataSize);
|
|
ASSERT(((PSIZE_T)OldUserBuffer)[-1] == OldDataSize);
|
|
RtlCopyMemory(NewUserBuffer, OldUserBuffer, min(OldDataSize, NewDataSize));
|
|
ASSERT(((PSIZE_T)OldUserBuffer)[-1] == OldDataSize);
|
|
Free(OldUserBuffer);
|
|
return NewUserBuffer;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
AccessMemory1(
|
|
PVOID UserBuffer,
|
|
SIZE_T DataSize)
|
|
{
|
|
PBYTE Buffer = UserBuffer;
|
|
SIZE_T i;
|
|
|
|
for (i = 0; i < DataSize; ++i)
|
|
Buffer[i] = LOBYTE(i);
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
CheckMemory1(
|
|
PVOID UserBuffer,
|
|
SIZE_T DataSize)
|
|
{
|
|
PBYTE Buffer = UserBuffer;
|
|
SIZE_T i;
|
|
|
|
for (i = 0; i < DataSize; ++i)
|
|
if (Buffer[i] != LOBYTE(i))
|
|
{
|
|
trace("Mismatch in region %p at index %lu. Value=%02x\n", UserBuffer, (ULONG)i, Buffer[i]);
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
AccessMemory2(
|
|
PVOID UserBuffer,
|
|
SIZE_T DataSize)
|
|
{
|
|
PBYTE Buffer = UserBuffer;
|
|
SIZE_T i;
|
|
|
|
for (i = 0; i < DataSize; ++i)
|
|
Buffer[i] = UCHAR_MAX - LOBYTE(i);
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
CheckMemory2(
|
|
PVOID UserBuffer,
|
|
SIZE_T DataSize)
|
|
{
|
|
PBYTE Buffer = UserBuffer;
|
|
SIZE_T i;
|
|
|
|
for (i = 0; i < DataSize; ++i)
|
|
if (Buffer[i] != UCHAR_MAX - LOBYTE(i))
|
|
{
|
|
trace("Mismatch in region %p at index %lu. Value=%02x\n", UserBuffer, (ULONG)i, Buffer[i]);
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
CheckSize(ULONG_PTR Base, SIZE_T InSize, SIZE_T ExpectedSize)
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID BaseAddress;
|
|
SIZE_T Size;
|
|
|
|
/* Reserve memory */
|
|
BaseAddress = (PVOID)Base;
|
|
Size = InSize;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE,
|
|
PAGE_NOACCESS);
|
|
ok(NT_SUCCESS(Status), "NtAllocateVirtualMemory failed!\n");
|
|
ok(BaseAddress == (PVOID)(Base & ~((ULONG_PTR)0xFFFF)), "Got back wrong base address: %p\n", BaseAddress);
|
|
ok(Size == ExpectedSize, "Alloc of 0x%Ix: got back wrong size: 0x%Ix, expected 0x%Ix\n", InSize, Size, ExpectedSize);
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok(NT_SUCCESS(Status), "NtFreeVirtualMemory failed!\n");
|
|
}
|
|
|
|
VOID
|
|
CheckAlignment()
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID BaseAddress;
|
|
SIZE_T Size;
|
|
|
|
CheckSize(0x50000000, 0x0001, 0x1000);
|
|
CheckSize(0x50008000, 0x0001, 0x9000);
|
|
CheckSize(0x50000010, 0x1000, 0x2000);
|
|
CheckSize(0x50010000, 0x2000, 0x2000);
|
|
CheckSize(0x5000FFFF, 0x3000, 0x13000);
|
|
CheckSize(0x50001010, 0x7000, 0x9000);
|
|
CheckSize(0x50001010, 0xC000, 0xe000);
|
|
|
|
/* Reserve memory not aligned to allocation granularity */
|
|
BaseAddress = UlongToPtr(0x50001010);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE,
|
|
PAGE_NOACCESS);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
ok(BaseAddress == UlongToPtr(0x50000000), "Got back wrong base address: %p", BaseAddress);
|
|
ok(Size == 0x3000, "Got back wrong size: 0x%Ix", Size);
|
|
|
|
/* Try to reserve again in the same 64k region */
|
|
BaseAddress = UlongToPtr(0x50008000);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE,
|
|
PAGE_NOACCESS);
|
|
ok_ntstatus(Status, STATUS_CONFLICTING_ADDRESSES);
|
|
|
|
/* Commit memory */
|
|
BaseAddress = UlongToPtr(0x50002000);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_COMMIT,
|
|
PAGE_NOACCESS);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
ok(BaseAddress == UlongToPtr(0x50002000), "Got back wrong base address: %p", BaseAddress);
|
|
ok(Size == 0x1000, "Got back wrong size: 0x%Ix", Size);
|
|
|
|
/* Commit the same address again with a different protection */
|
|
BaseAddress = UlongToPtr(0x50002000);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
ok(BaseAddress == UlongToPtr(0x50002000), "Got back wrong base address: %p", BaseAddress);
|
|
ok(Size == 0x1000, "Got back wrong size: 0x%Ix", Size);
|
|
|
|
/* Commit memory at a too high address */
|
|
BaseAddress = UlongToPtr(0x50003000);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_COMMIT,
|
|
PAGE_NOACCESS);
|
|
ok_ntstatus(Status, STATUS_CONFLICTING_ADDRESSES);
|
|
|
|
/* Decommit the memory, even those pages that were not committed */
|
|
BaseAddress = UlongToPtr(0x50000000);
|
|
Size = 0x3000;
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_DECOMMIT);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
/* Try to release memory in a different 64k region */
|
|
BaseAddress = UlongToPtr(0x50010000);
|
|
Size = 0x1000;
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_MEMORY_NOT_ALLOCATED);
|
|
|
|
/* Release the memory in the same 64k region at a different address */
|
|
BaseAddress = UlongToPtr(0x50008000);
|
|
Size = 0x1000;
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_MEMORY_NOT_ALLOCATED);
|
|
|
|
/* Release the memory at the correct address but with wrong size */
|
|
BaseAddress = UlongToPtr(0x50000000);
|
|
Size = 0x4000;
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_UNABLE_TO_FREE_VM);
|
|
|
|
/* Release the memory */
|
|
BaseAddress = UlongToPtr(0x50000000);
|
|
Size = 0x3000;
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
/* Reserve and commit at once */
|
|
BaseAddress = UlongToPtr(0x50004080);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE | MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
ok(BaseAddress == UlongToPtr(0x50000000), "Got back wrong base address: %p", BaseAddress);
|
|
ok(Size == 0x6000, "Got back wrong size: 0x%Ix", Size);
|
|
|
|
_SEH2_TRY
|
|
{
|
|
*(int*)BaseAddress = 1;
|
|
*(int*)UlongToPtr(0x50004080) = 1;
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
ok(0, "Got exception\n");
|
|
}
|
|
_SEH2_END;
|
|
|
|
/* Release the memory */
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
static
|
|
VOID
|
|
CheckAdjacentVADs()
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID BaseAddress;
|
|
SIZE_T Size;
|
|
MEMORY_BASIC_INFORMATION MemoryBasicInfo;
|
|
|
|
/* Reserve a full 64k region */
|
|
BaseAddress = UlongToPtr(0x50000000);
|
|
Size = 0x10000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE,
|
|
PAGE_NOACCESS);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
if (!NT_SUCCESS(Status))
|
|
return;
|
|
|
|
/* Reserve another 64k region, but with 64k between */
|
|
BaseAddress = UlongToPtr(0x50020000);
|
|
Size = 0x10000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE,
|
|
PAGE_NOACCESS);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
if (!NT_SUCCESS(Status))
|
|
return;
|
|
|
|
/* Try to free the whole at once */
|
|
BaseAddress = UlongToPtr(0x50000000);
|
|
Size = 0x30000;
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_UNABLE_TO_FREE_VM);
|
|
|
|
/* Reserve the part in the middle */
|
|
BaseAddress = UlongToPtr(0x50010000);
|
|
Size = 0x10000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE,
|
|
PAGE_NOACCESS);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
/* Try to commit memory covering 2 allocations */
|
|
BaseAddress = UlongToPtr(0x50004000);
|
|
Size = 0x10000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_COMMIT,
|
|
PAGE_NOACCESS);
|
|
ok_ntstatus(Status, STATUS_CONFLICTING_ADDRESSES);
|
|
|
|
/* Commit a page */
|
|
BaseAddress = UlongToPtr(0x50000000);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
/* Commit another page */
|
|
BaseAddress = UlongToPtr(0x50002000);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_COMMIT,
|
|
PAGE_NOACCESS);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
_SEH2_TRY
|
|
{
|
|
*(int*)UlongToPtr(0x50000000) = 1;
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
ok(0, "Got exception\n");
|
|
}
|
|
_SEH2_END;
|
|
|
|
_SEH2_TRY
|
|
{
|
|
(void)*(volatile int*)UlongToPtr(0x50002000);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
ok_ntstatus(Status, STATUS_ACCESS_VIOLATION);
|
|
|
|
/* Allocate 3 pages, on top of the previous 2 */
|
|
BaseAddress = UlongToPtr(0x50000000);
|
|
Size = 0x3000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_COMMIT,
|
|
PAGE_READONLY);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
_SEH2_TRY
|
|
{
|
|
*(int*)UlongToPtr(0x50000000) = 1;
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
ok_ntstatus(Status, STATUS_ACCESS_VIOLATION);
|
|
|
|
/* Commit a page at the end of the first region */
|
|
BaseAddress = UlongToPtr(0x5000F000);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
ok_ptr(BaseAddress, UlongToPtr(0x5000F000));
|
|
|
|
/* See where is the base of this newly committed area
|
|
* (choose a base address in the middle of it) */
|
|
Status = NtQueryVirtualMemory(NtCurrentProcess(),
|
|
UlongToPtr(0x5000F700),
|
|
MemoryBasicInformation,
|
|
&MemoryBasicInfo,
|
|
sizeof(MemoryBasicInfo),
|
|
NULL);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
/* The base address is the beginning of the committed area */
|
|
ok_ptr(MemoryBasicInfo.BaseAddress, UlongToPtr(0x5000F000));
|
|
/* The allocation base address is the beginning of the whole region */
|
|
ok_ptr(MemoryBasicInfo.AllocationBase, UlongToPtr(0x50000000));
|
|
/* This is the protection of the memory when it was reserved. */
|
|
ok_long(MemoryBasicInfo.AllocationProtect, PAGE_NOACCESS);
|
|
/* This is the size of the committed region. (ie, smallest chunk size) */
|
|
ok_long(MemoryBasicInfo.RegionSize, 0x1000);
|
|
/* This is the state of the queried address */
|
|
ok_long(MemoryBasicInfo.State, MEM_COMMIT);
|
|
/* This is the protection of the queried address */
|
|
ok_long(MemoryBasicInfo.Protect, PAGE_READWRITE);
|
|
/* NtAllocateVirtualMemory makes it MEM_PRIVATE */
|
|
ok_long(MemoryBasicInfo.Type, MEM_PRIVATE);
|
|
|
|
/* Try to free the whole region at once */
|
|
BaseAddress = UlongToPtr(0x50000000);
|
|
Size = 0x30000;
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_UNABLE_TO_FREE_VM);
|
|
|
|
BaseAddress = UlongToPtr(0x50000000);
|
|
Size = 0x10000;
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
BaseAddress = UlongToPtr(0x50010000);
|
|
Size = 0x10000;
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
BaseAddress = UlongToPtr(0x50020000);
|
|
Size = 0x10000;
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
/* Reserve 3 full 64k region */
|
|
BaseAddress = UlongToPtr(0x50000000);
|
|
Size = 0x30000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE,
|
|
PAGE_NOACCESS);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
if (!NT_SUCCESS(Status))
|
|
return;
|
|
|
|
/* Release the 64k region in the middle */
|
|
BaseAddress = UlongToPtr(0x50010000);
|
|
Size = 0x10000;
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
static
|
|
VOID
|
|
CheckSomeDefaultAddresses(VOID)
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID BaseAddress;
|
|
SIZE_T Size;
|
|
|
|
// NULL.
|
|
|
|
/* Reserve memory dynamically, not at 0x00000000 */
|
|
BaseAddress = NULL;
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
ok(BaseAddress != 0x00000000, "Unexpected BaseAddress = 0x00000000\n");
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
// 0x00000000, 64k: Free.
|
|
|
|
/* Reserve and commit memory at 0x00000000, after round down */
|
|
BaseAddress = UlongToPtr(0x00000000 + 0x0FFF);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE | MEM_COMMIT,
|
|
PAGE_READWRITE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
ok_ptr(BaseAddress, 0x00000000);
|
|
|
|
// Double-check that it is not forbidden "in order to catch null pointer accesses".
|
|
StartSeh()
|
|
*(int*)UlongToPtr(0x00000000) = 1;
|
|
EndSeh(STATUS_SUCCESS)
|
|
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
/* Reserve memory above 0x00000000 */
|
|
BaseAddress = UlongToPtr(0x00000000 + 0x1000);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
/* The following checks assume very default addresses,
|
|
* no address space layout randomization (ASLR). */
|
|
#ifdef _WIN64
|
|
ok(FALSE, "ToDo, 64-bit: Check/Adapt 32-bit results\n");
|
|
#endif
|
|
|
|
// 0x00010000, 4k: Private Data.
|
|
// 0x00011000, 60k: Unusable.
|
|
|
|
/* Reserve memory below 0x00010000 */
|
|
BaseAddress = UlongToPtr(0x00010000 - 0x1000);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
/* Reserve memory at 0x00010000:
|
|
* Windows NT legacy default executable image base */
|
|
BaseAddress = UlongToPtr(0x00010000);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
ok_ntstatus(Status, STATUS_CONFLICTING_ADDRESSES);
|
|
if (NT_SUCCESS(Status))
|
|
{ // Unexpected, cleanup.
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
}
|
|
|
|
// 0x00400000: Image base.
|
|
|
|
/* Reserve memory below 0x00400000 */
|
|
BaseAddress = UlongToPtr(0x00400000 - 0x1000);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
trace("Below 0x00400000 is available, as on ReactOS and Windows S03\n");
|
|
// 0x003F0000, 64k: Free.
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
}
|
|
else
|
|
{
|
|
trace("Below 0x00400000 is not available, as on Windows XP\n");
|
|
// 0x003F0000, 4k: Shareable.
|
|
// 0x003F1000, 60k: Unusable.
|
|
ok_ntstatus(Status, STATUS_CONFLICTING_ADDRESSES);
|
|
}
|
|
|
|
/* Reserve memory at 0x00400000:
|
|
* Windows NT legacy default DLL image base,
|
|
* (ReactOS and) Windows 95 new default executable image base */
|
|
BaseAddress = UlongToPtr(0x00400000);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
ok_ntstatus(Status, STATUS_CONFLICTING_ADDRESSES);
|
|
if (NT_SUCCESS(Status))
|
|
{ // Unexpected, cleanup.
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
}
|
|
|
|
// 0x10000000: Free.
|
|
|
|
/* Reserve memory below 0x10000000 */
|
|
BaseAddress = UlongToPtr(0x10000000 - 0x1000);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
/* Reserve memory at 0x10000000:
|
|
* Windows new default non-OS DLL image base */
|
|
BaseAddress = UlongToPtr(0x10000000);
|
|
Size = 0x1000;
|
|
Status = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
&Size,
|
|
MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
|
|
ok_ntstatus(Status, STATUS_SUCCESS);
|
|
|
|
#ifdef _WIN64
|
|
skip("ToDo, 64-bit: Add 0x140000000/Exe and 0x180000000/DLL checks\n");
|
|
#endif
|
|
}
|
|
|
|
#define RUNS 32
|
|
|
|
START_TEST(NtAllocateVirtualMemory)
|
|
{
|
|
PVOID Mem1, Mem2;
|
|
SIZE_T Size1, Size2;
|
|
ULONG i;
|
|
|
|
CheckAlignment();
|
|
CheckAdjacentVADs();
|
|
CheckSomeDefaultAddresses();
|
|
|
|
Size1 = 32;
|
|
Mem1 = Allocate(Size1);
|
|
AccessMemory1(Mem1, Size1);
|
|
Size2 = 128;
|
|
Mem2 = Allocate(Size2);
|
|
AccessMemory2(Mem2, Size2);
|
|
for (i = 0; i < RUNS; ++i)
|
|
{
|
|
PVOID New;
|
|
ok(CheckMemory1(Mem1, Size1) == TRUE, "CheckMemory1 failure\n");
|
|
New = ReAllocate(Mem1, Size1 * 3 / 2);
|
|
if (New == NULL)
|
|
{
|
|
skip("Realloc failure\n");
|
|
break;
|
|
}
|
|
Mem1 = New;
|
|
ok(CheckMemory1(Mem1, Size1) == TRUE, "CheckMemory1 failure\n");
|
|
Size1 = Size1 * 3 / 2;
|
|
AccessMemory1(Mem1, Size1);
|
|
|
|
ok(CheckMemory2(Mem2, Size2) == TRUE, "CheckMemory2 failure\n");
|
|
New = ReAllocate(Mem2, Size2 + 128);
|
|
if (New == NULL)
|
|
{
|
|
skip("Realloc failure\n");
|
|
break;
|
|
}
|
|
Mem2 = New;
|
|
ok(CheckMemory2(Mem2, Size2) == TRUE, "CheckMemory2 failure\n");
|
|
Size2 += 128;
|
|
AccessMemory2(Mem2, Size2);
|
|
}
|
|
ok(CheckMemory2(Mem2, Size2) == TRUE, "CheckMemory2 failure\n");
|
|
Free(Mem2);
|
|
ok(CheckMemory1(Mem1, Size1) == TRUE, "CheckMemory1 failure\n");
|
|
Free(Mem1);
|
|
}
|