Author: tfaber Date: Wed Nov 30 17:00:23 2011 New Revision: 54548
URL: http://svn.reactos.org/svn/reactos?rev=54548&view=rev Log: [NTDLL_APITEST] - Add NtAllocateVirtualMemory test, which is a small stress test for virtual memory allocation/freeing/reuse - Can be used to reproduce bug 5857 in third stage (install with VT-x enabled, then disable for the test) - Shows that the bug is a race condition in Mm, and not heap's fault - I've put ASSERTs instead of ok's for easier debugging
Added: trunk/rostests/apitests/ntdll/NtAllocateVirtualMemory.c (with props) Modified: trunk/rostests/apitests/ntdll/CMakeLists.txt trunk/rostests/apitests/ntdll/ntdll_apitest.rbuild trunk/rostests/apitests/ntdll/testlist.c
Modified: trunk/rostests/apitests/ntdll/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ntdll/CMakeLists.... ============================================================================== --- trunk/rostests/apitests/ntdll/CMakeLists.txt [iso-8859-1] (original) +++ trunk/rostests/apitests/ntdll/CMakeLists.txt [iso-8859-1] Wed Nov 30 17:00:23 2011 @@ -1,7 +1,6 @@ - -add_definitions(-D_DLL -D__USE_CRTIMP)
list(APPEND SOURCE + NtAllocateVirtualMemory.c NtFreeVirtualMemory.c RtlInitializeBitMap.c SystemInfo.c
Added: trunk/rostests/apitests/ntdll/NtAllocateVirtualMemory.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ntdll/NtAllocateV... ============================================================================== --- trunk/rostests/apitests/ntdll/NtAllocateVirtualMemory.c (added) +++ trunk/rostests/apitests/ntdll/NtAllocateVirtualMemory.c [iso-8859-1] Wed Nov 30 17:00:23 2011 @@ -1,0 +1,245 @@ +/* + * PROJECT: ReactOS API Tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Stress Test for virtual memory allocation + * PROGRAMMER: Thomas Faber thfabba@gmx.de + */ + +#define WIN32_NO_STATUS +#include <stdio.h> +#include <wine/test.h> +#include <ndk/rtlfuncs.h> +#include <ndk/mmfuncs.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(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)) + { + Size = 0; + Status = NtFreeVirtualMemory(NtCurrentProcess(), &AllocationStart, &AllocationSize, MEM_RELEASE); + ASSERT(Status == STATUS_SUCCESS); + return NULL; + } + + 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; +} + +#define RUNS 32 + +START_TEST(NtAllocateVirtualMemory) +{ + PVOID Mem1, Mem2; + SIZE_T Size1, Size2; + ULONG i; + + 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); +}
Propchange: trunk/rostests/apitests/ntdll/NtAllocateVirtualMemory.c ------------------------------------------------------------------------------ svn:eol-style = native
Modified: trunk/rostests/apitests/ntdll/ntdll_apitest.rbuild URL: http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ntdll/ntdll_apite... ============================================================================== --- trunk/rostests/apitests/ntdll/ntdll_apitest.rbuild [iso-8859-1] (original) +++ trunk/rostests/apitests/ntdll/ntdll_apitest.rbuild [iso-8859-1] Wed Nov 30 17:00:23 2011 @@ -10,7 +10,8 @@ <library>pseh</library> <file>testlist.c</file>
- <file>NtFreeVirtualMemory.c</file> + <file>NtAllocateVirtualMemory.c</file> + <file>NtFreeVirtualMemory.c</file> <file>RtlInitializeBitMap.c</file> <file>ZwContinue.c</file> <file>SystemInfo.c</file>
Modified: trunk/rostests/apitests/ntdll/testlist.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ntdll/testlist.c?... ============================================================================== --- trunk/rostests/apitests/ntdll/testlist.c [iso-8859-1] (original) +++ trunk/rostests/apitests/ntdll/testlist.c [iso-8859-1] Wed Nov 30 17:00:23 2011 @@ -5,17 +5,19 @@ #define STANDALONE #include "wine/test.h"
+extern void func_NtAllocateVirtualMemory(void); +extern void func_NtFreeVirtualMemory(void); +extern void func_NtSystemInformation(void); extern void func_RtlInitializeBitMap(void); extern void func_ZwContinue(void); -extern void func_NtFreeVirtualMemory(void); -extern void func_NtSystemInformation(void);
const struct test winetest_testlist[] = { - { "RtlInitializeBitMap", func_RtlInitializeBitMap }, - { "ZwContinue", func_ZwContinue }, - { "NtFreeVirtualMemory", func_NtFreeVirtualMemory }, - { "NtSystemInformation", func_NtSystemInformation }, + { "NtAllocateVirtualMemory", func_NtAllocateVirtualMemory }, + { "NtFreeVirtualMemory", func_NtFreeVirtualMemory }, + { "NtSystemInformation", func_NtSystemInformation }, + { "RtlInitializeBitMap", func_RtlInitializeBitMap }, + { "ZwContinue", func_ZwContinue },
{ 0, 0 } };