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/NtAllocate…
==============================================================================
--- 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(a)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_apit…
==============================================================================
--- 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 }
 };