[KMTESTS]
authorThomas Faber <thomas.faber@reactos.org>
Sat, 6 Aug 2011 17:09:39 +0000 (17:09 +0000)
committerThomas Faber <thomas.faber@reactos.org>
Sat, 6 Aug 2011 17:09:39 +0000 (17:09 +0000)
- Rename ObCreate test to ObType, and apply some major refactoring. Now _almost_ works on Windows....
- Add a readme file

svn path=/branches/GSoC_2011/KMTestSuite/; revision=53103

kmtests/CMakeLists.txt
kmtests/kmtest_drv.rbuild
kmtests/kmtest_drv/testlist.c
kmtests/ntos_ob/ObCreate.c [deleted file]
kmtests/ntos_ob/ObType.c [new file with mode: 0644]
kmtests/readme.txt [new file with mode: 0644]

index 1ab1719..63f86c2 100644 (file)
@@ -34,7 +34,7 @@ list(APPEND KMTEST_DRV_SOURCE
     ntos_ke/KeIrql.c
     ntos_ke/KeProcessor.c
     ntos_ke/KeSpinLock.c
-    ntos_ob/ObCreate.c
+    ntos_ob/ObType.c
     rtl/RtlAvlTree.c
     rtl/RtlMemory.c
     rtl/RtlSplayTree.c
index 3586454..f5464dc 100644 (file)
@@ -41,7 +41,7 @@
                <file>KeSpinLock.c</file>
        </directory>
        <directory name="ntos_ob">
-               <file>ObCreate.c</file>
+               <file>ObType.c</file>
        </directory>
        <directory name="rtl">
                <file>RtlAvlTree.c</file>
index 2c208fb..ed8c13e 100644 (file)
@@ -27,7 +27,9 @@ KMT_TESTFUNC Test_KeEvent;
 KMT_TESTFUNC Test_KeIrql;
 KMT_TESTFUNC Test_KeProcessor;
 KMT_TESTFUNC Test_KernelType;
-KMT_TESTFUNC Test_ObCreate;
+KMT_TESTFUNC Test_ObType;
+KMT_TESTFUNC Test_ObTypeClean;
+KMT_TESTFUNC Test_ObTypeNoClean;
 KMT_TESTFUNC Test_RtlAvlTree;
 KMT_TESTFUNC Test_RtlMemory;
 KMT_TESTFUNC Test_RtlSplayTree;
@@ -54,7 +56,9 @@ const KMT_TEST TestList[] =
     { "KeIrql",                             Test_KeIrql },
     { "KeProcessor",                        Test_KeProcessor },
     { "-KernelType",                        Test_KernelType },
-    { "ObCreate",                           Test_ObCreate },
+    { "ObType",                             Test_ObType },
+    { "-ObTypeClean",                       Test_ObTypeClean },
+    { "-ObTypeNoClean",                     Test_ObTypeNoClean },
     { "RtlAvlTreeKM",                       Test_RtlAvlTree },
     { "RtlMemoryKM",                        Test_RtlMemory },
     { "RtlSplayTreeKM",                     Test_RtlSplayTree },
diff --git a/kmtests/ntos_ob/ObCreate.c b/kmtests/ntos_ob/ObCreate.c
deleted file mode 100644 (file)
index 84d88e8..0000000
+++ /dev/null
@@ -1,506 +0,0 @@
-/*
- * PROJECT:         ReactOS kernel-mode tests
- * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
- * PURPOSE:         Kernel-Mode Test Suite Ob Regressions KM-Test
- * PROGRAMMER:      Aleksey Bragin <aleksey@reactos.org>
- */
-
-/* TODO: this test terminates with an access violation in Windows */
-
-#include <kmt_test.h>
-
-#define NDEBUG
-#include <debug.h>
-
-// I ment to make this test scalable, but for now
-// we work with two object types only
-#define NUM_OBTYPES 2
-
-typedef struct _MY_OBJECT1
-{
-    ULONG Something1;
-} MY_OBJECT1, *PMY_OBJECT1;
-
-typedef struct _MY_OBJECT2
-{
-    ULONG Something1;
-    ULONG SomeLong[10];
-} MY_OBJECT2, *PMY_OBJECT2;
-
-static POBJECT_TYPE            ObTypes[NUM_OBTYPES];
-static UNICODE_STRING          ObTypeName[NUM_OBTYPES];
-static UNICODE_STRING          ObName[NUM_OBTYPES];
-static OBJECT_TYPE_INITIALIZER ObTypeInitializer[NUM_OBTYPES];
-static UNICODE_STRING          ObDirectoryName;
-static OBJECT_ATTRIBUTES       ObDirectoryAttributes;
-static OBJECT_ATTRIBUTES       ObAttributes[NUM_OBTYPES];
-static PVOID                   ObBody[NUM_OBTYPES];
-//static PMY_OBJECT1             ObObject1;
-//static PMY_OBJECT2             ObObject2;
-static HANDLE                  ObHandle1[NUM_OBTYPES];
-static HANDLE                  ObHandle2[NUM_OBTYPES];
-static HANDLE                  DirectoryHandle;
-
-static USHORT                  DumpCount, OpenCount, CloseCount, DeleteCount,
-                               ParseCount, OkayToCloseCount, QueryNameCount;
-
-static
-VOID
-NTAPI
-DumpProc(IN PVOID Object,
-         IN POB_DUMP_CONTROL DumpControl)
-{
-    DbgPrint("DumpProc() called\n");
-    DumpCount++;
-}
-
-// Tested in Win2k3
-static
-VOID
-NTAPI
-OpenProc(IN OB_OPEN_REASON OpenReason,
-         IN PEPROCESS Process,
-         IN PVOID Object,
-         IN ACCESS_MASK GrantedAccess,
-         IN ULONG HandleCount)
-{
-    DbgPrint("OpenProc() 0x%p, OpenReason %d, HC %d, AM 0x%X\n",
-        Object, OpenReason, HandleCount, GrantedAccess);
-    OpenCount++;
-}
-
-// Tested in Win2k3
-static
-VOID
-NTAPI
-CloseProc(IN PEPROCESS Process,
-          IN PVOID Object,
-          IN ACCESS_MASK GrantedAccess,
-          IN ULONG ProcessHandleCount,
-          IN ULONG SystemHandleCount)
-{
-    DbgPrint("CloseProc() 0x%p, PHC %d, SHC %d, AM 0x%X\n", Object,
-        ProcessHandleCount, SystemHandleCount, GrantedAccess);
-    CloseCount++;
-}
-
-// Tested in Win2k3
-static
-VOID
-NTAPI
-DeleteProc(IN PVOID Object)
-{
-    DbgPrint("DeleteProc() 0x%p\n", Object);
-    DeleteCount++;
-}
-
-static
-NTSTATUS
-NTAPI
-ParseProc(IN PVOID ParseObject,
-          IN PVOID ObjectType,
-          IN OUT PACCESS_STATE AccessState,
-          IN KPROCESSOR_MODE AccessMode,
-          IN ULONG Attributes,
-          IN OUT PUNICODE_STRING CompleteName,
-          IN OUT PUNICODE_STRING RemainingName,
-          IN OUT PVOID Context OPTIONAL,
-          IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
-          OUT PVOID *Object)
-{
-    DbgPrint("ParseProc() called\n");
-    *Object = NULL;
-
-    ParseCount++;
-    return STATUS_OBJECT_NAME_NOT_FOUND;//STATUS_SUCCESS;
-}
-
-#if 0
-// Tested in Win2k3
-static
-NTSTATUS
-NTAPI
-OkayToCloseProc(IN PEPROCESS Process OPTIONAL,
-                IN PVOID Object,
-                IN HANDLE Handle,
-                IN KPROCESSOR_MODE AccessMode)
-{
-    DbgPrint("OkayToCloseProc() 0x%p, H 0x%p, AM 0x%X\n", Object, Handle,
-        AccessMode);
-    OkayToCloseCount++;
-    return STATUS_SUCCESS;
-}
-
-static
-NTSTATUS
-NTAPI
-QueryNameProc(IN PVOID Object,
-              IN BOOLEAN HasObjectName,
-              OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
-              IN ULONG Length,
-              OUT PULONG ReturnLength,
-              IN KPROCESSOR_MODE AccessMode)
-{
-    DbgPrint("QueryNameProc() 0x%p, HON %d, Len %d, AM 0x%X\n",
-        Object, HasObjectName, Length, AccessMode);
-    QueryNameCount++;
-
-    ObjectNameInfo = NULL;
-    ReturnLength = 0;
-    return STATUS_OBJECT_NAME_NOT_FOUND;
-}
-#endif /* 0 */
-
-static
-VOID
-ObtCreateObjectTypes()
-{
-    USHORT i;
-    NTSTATUS Status;
-    WCHAR   Name[15];
-
-    for (i=0; i<NUM_OBTYPES; i++)
-    {
-        // Prepare object type name
-        // TODO: Generate type names and don't use this unprofessional,
-        swprintf(Name, L"MyObjectType%lx", i);
-        RtlInitUnicodeString(&ObTypeName[i], Name);
-
-        // Prepare initializer
-        RtlZeroMemory(&ObTypeInitializer[i], sizeof(ObTypeInitializer[i]));
-        ObTypeInitializer[i].Length = sizeof(ObTypeInitializer[i]);
-        ObTypeInitializer[i].PoolType = NonPagedPool;
-        ObTypeInitializer[i].MaintainHandleCount = TRUE;
-        ObTypeInitializer[i].ValidAccessMask = OBJECT_TYPE_ALL_ACCESS;
-
-        // Test for invalid parameter
-        // FIXME: Make it more exact, to see which params Win2k3 checks
-        // existence of
-        Status = ObCreateObjectType(&ObTypeName[i], &ObTypeInitializer[i],
-            (PSECURITY_DESCRIPTOR)NULL, &ObTypes[i]);
-        ok(Status == STATUS_INVALID_PARAMETER,
-            "ObCreateObjectType returned 0x%lX", Status);
-
-        // Object procedures
-        ObTypeInitializer[i].CloseProcedure = (OB_CLOSE_METHOD)CloseProc;
-        ObTypeInitializer[i].DeleteProcedure = (OB_DELETE_METHOD)DeleteProc;
-        ObTypeInitializer[i].DumpProcedure = (OB_DUMP_METHOD)DumpProc;
-        ObTypeInitializer[i].OpenProcedure = (OB_OPEN_METHOD)OpenProc;
-        ObTypeInitializer[i].ParseProcedure = (OB_PARSE_METHOD)ParseProc;
-        //ObTypeInitializer[i].OkayToCloseProcedure =
-        //    (OB_OKAYTOCLOSE_METHOD)OkayToCloseProc;
-
-        //ObTypeInitializer[i].QueryNameProcedure =
-        //    (OB_QUERYNAME_METHOD)QueryNameProc;
-
-        //ObTypeInitializer[i].SecurityProcedure =
-        // (OB_SECURITY_METHOD)SecurityProc;
-
-        Status = ObCreateObjectType(&ObTypeName[i], &ObTypeInitializer[i],
-            (PSECURITY_DESCRIPTOR)NULL, &ObTypes[i]);
-        ok(Status == STATUS_SUCCESS,
-            "Failed to create object type with status=0x%lX", Status);
-    }
-}
-
-static
-VOID
-ObtCreateDirectory()
-{
-    NTSTATUS Status;
-
-    // Directory will have permanent and case insensitive flags
-    RtlInitUnicodeString(&ObDirectoryName, L"\\ObtDirectory");
-    InitializeObjectAttributes(&ObDirectoryAttributes, &ObDirectoryName,
-        OBJ_PERMANENT | OBJ_CASE_INSENSITIVE, NULL, NULL);
-
-    Status = ZwCreateDirectoryObject(&DirectoryHandle, 0, &ObDirectoryAttributes);
-    ok(Status == STATUS_SUCCESS,
-        "Failed to create directory object with status=0x%lX", Status);
-}
-
-static
-VOID
-ObtCreateObjects()
-{
-    PVOID ObBody1[2];
-    NTSTATUS Status;
-    USHORT OpenSave, CloseSave, DeleteSave, ParseSave,
-           OkayToCloseSave, QueryNameSave;
-
-    // Create two objects
-    RtlInitUnicodeString(&ObName[0], L"\\ObtDirectory\\MyObject1");
-    InitializeObjectAttributes(&ObAttributes[0], &ObName[0],
-        OBJ_CASE_INSENSITIVE, NULL, NULL);
-
-    RtlInitUnicodeString(&ObName[1], L"\\ObtDirectory\\MyObject2");
-    InitializeObjectAttributes(&ObAttributes[1], &ObName[1],
-        OBJ_CASE_INSENSITIVE, NULL, NULL);
-
-    Status = ObCreateObject(KernelMode, ObTypes[0], &ObAttributes[0],
-        KernelMode, NULL, (ULONG)sizeof(MY_OBJECT1), 0L, 0L,
-        (PVOID *)&ObBody[0]);
-    ok(Status == STATUS_SUCCESS,
-        "Failed to create object with status=0x%lX", Status);
-
-    Status = ObCreateObject(KernelMode, ObTypes[1], &ObAttributes[1],
-        KernelMode, NULL, (ULONG)sizeof(MY_OBJECT2), 0L, 0L,
-        (PVOID *)&ObBody[1]);
-    ok(Status == STATUS_SUCCESS,
-        "Failed to create object with status=0x%lX", Status);
-
-    // save counters
-    OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
-    ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
-    QueryNameSave=QueryNameCount;
-
-    // Insert them
-    Status = ObInsertObject(ObBody[0], NULL, STANDARD_RIGHTS_ALL, 0,
-        &ObBody[0], &ObHandle1[0]);
-    ok(Status == STATUS_SUCCESS,
-        "Failed to insert object 0 with status=0x%lX", Status);
-    ok(ObBody[0] != NULL, "Object body = NULL");
-    ok(ObHandle1[0] != NULL, "Handle = NULL");
-
-    // check counters
-    ok(OpenSave+1 == OpenCount, "Open method calls mismatch\n");
-    ok(CloseSave == CloseCount, "Excessive Close method call\n");
-    ok(DeleteSave == DeleteCount, "Excessive Delete method call\n");
-    ok(ParseSave == ParseCount, "Excessive Parse method call\n");
-
-    // save counters
-    OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
-    ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
-    QueryNameSave=QueryNameCount;
-
-    Status = ObInsertObject(ObBody[1], NULL, GENERIC_ALL, 0,
-        &ObBody[1], &ObHandle1[1]);
-    ok(Status == STATUS_SUCCESS,
-        "Failed to insert object 1 with status=0x%lX", Status);
-    ok(ObBody[1] != NULL, "Object body = NULL");
-    ok(ObHandle1[1] != NULL, "Handle = NULL");
-
-    // check counters
-    ok(OpenSave+1 == OpenCount, "Open method calls mismatch\n");
-    ok(CloseSave == CloseCount, "Excessive Close method call\n");
-    ok(DeleteSave == DeleteCount, "Excessive Delete method call\n");
-    ok(ParseSave == ParseCount, "Excessive Parse method call\n");
-
-    // save counters
-    OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
-    ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
-    QueryNameSave=QueryNameCount;
-
-    // Now create an object of type 0, of the same name and expect it to fail
-    // inserting, but success creation
-    RtlInitUnicodeString(&ObName[0], L"\\ObtDirectory\\MyObject1");
-    InitializeObjectAttributes(&ObAttributes[0], &ObName[0], OBJ_OPENIF,
-        NULL, NULL);
-
-    Status = ObCreateObject(KernelMode, ObTypes[0], &ObAttributes[0], KernelMode,
-        NULL, (ULONG)sizeof(MY_OBJECT1), 0L, 0L, (PVOID *)&ObBody1[0]);
-    ok(Status == STATUS_SUCCESS,
-        "Failed to create object with status=0x%lX", Status);
-
-    // check counters
-    ok(OpenSave == OpenCount, "Excessive Open method call\n");
-    ok(CloseSave == CloseCount, "Excessive Close method call\n");
-    ok(DeleteSave == DeleteCount, "Excessive Delete method call\n");
-    ok(ParseSave == ParseCount, "Excessive Parse method call\n");
-
-    Status = ObInsertObject(ObBody1[0], NULL, GENERIC_ALL, 0,
-        &ObBody1[1], &ObHandle2[0]);
-    ok(Status == STATUS_OBJECT_NAME_EXISTS,
-        "Object insertion should have failed, but got 0x%lX", Status);
-    ok(ObBody[0] == ObBody1[1],
-        "Object bodies doesn't match, 0x%p != 0x%p", ObBody[0], ObBody1[1]);
-    ok(ObHandle2[0] != NULL, "Bad handle returned 0x%lX", (ULONG_PTR)ObHandle2[0]);
-
-    DPRINT1("%d %d %d %d %d %d %d\n", DumpCount, OpenCount, // deletecount+1
-        CloseCount, DeleteCount, ParseCount, OkayToCloseCount, QueryNameCount);
-
-    // check counters and then save
-    ok(OpenSave+1 == OpenCount, "Excessive Open method call\n");
-    ok(CloseSave == CloseCount, "Excessive Close method call\n");
-    ok(DeleteSave+1 == DeleteCount, "Delete method call mismatch\n");
-    ok(ParseSave == ParseCount, "Excessive Parse method call\n");
-    OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
-    ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
-    QueryNameSave=QueryNameCount;
-
-    // Close its handle
-    Status = ZwClose(ObHandle2[0]);
-    ok(Status == STATUS_SUCCESS,
-        "Failed to close handle status=0x%lX", Status);
-
-    // check counters and then save
-    ok(OpenSave == OpenCount, "Excessive Open method call\n");
-    ok(CloseSave+1 == CloseCount, "Close method call mismatch\n");
-    ok(DeleteSave == DeleteCount, "Excessive Delete method call\n");
-    ok(ParseSave == ParseCount, "Excessive Parse method call\n");
-    OpenSave=OpenCount; CloseSave=CloseCount; DeleteSave=DeleteCount;
-    ParseSave=ParseCount; OkayToCloseSave=OkayToCloseCount;
-    QueryNameSave=QueryNameCount;
-
-
-    // Object referenced 2 times:
-    // 1) ObInsertObject
-    // 2) AdditionalReferences
-    ObDereferenceObject(ObBody1[1]);
-
-    //DPRINT1("%d %d %d %d %d %d %d\n", DumpCount, OpenCount, // no change
-    //    CloseCount, DeleteCount, ParseCount, OkayToCloseCount, QueryNameCount);
-    ok(OpenSave == OpenCount, "Open method call mismatch\n");
-    ok(CloseSave == CloseCount, "Close method call mismatch\n");
-    ok(DeleteSave == DeleteCount, "Delete method call mismatch\n");
-    ok(ParseSave == ParseCount, "Parse method call mismatch\n");
-}
-
-static
-VOID
-ObtClose()
-{
-    PVOID DirObject;
-    NTSTATUS Status;
-    //PVOID TypeObject;
-    USHORT i;
-    //UNICODE_STRING ObPathName[NUM_OBTYPES];
-
-    // Close what we have opened and free what we allocated
-    ZwClose(ObHandle1[0]);
-    ZwClose(ObHandle1[1]);
-    ZwClose(ObHandle2[0]);
-    ZwClose(ObHandle2[1]);
-
-    // Now we have to get rid of a directory object
-    // Since it is permanent, we have to firstly make it temporary
-    // and only then kill
-    // (this procedure is described in DDK)
-    Status = ObReferenceObjectByHandle(DirectoryHandle, 0L, NULL,
-        KernelMode, &DirObject, NULL);
-    ok(Status == STATUS_SUCCESS,
-        "Failed to reference object by handle with status=0x%lX", Status);
-
-    // Dereference 2 times - first for just previous referencing
-    // and 2nd time for creation of permanent object itself
-    ObDereferenceObject(DirObject);
-    ObDereferenceObject(DirObject);
-
-    Status = ZwMakeTemporaryObject(DirectoryHandle);
-    ok(Status == STATUS_SUCCESS,
-        "Failed to make temp object with status=0x%lX", Status);
-
-    // Close the handle now and we are done
-    Status = ZwClose(DirectoryHandle);
-    ok(Status == STATUS_SUCCESS,
-        "Failed to close handle with status=0x%lX", Status);
-
-    // Now delete the last piece - object types
-    // In fact, it's weird to get rid of object types, especially the way,
-    // how it's done in the commented section below
-    for (i=0; i<NUM_OBTYPES; i++)
-        ObDereferenceObject(ObTypes[i]);
-/*
-    RtlInitUnicodeString(&ObPathName[0], L"\\ObjectTypes\\MyObjectType1");
-    RtlInitUnicodeString(&ObPathName[1], L"\\ObjectTypes\\MyObjectType2");
-
-    for (i=0; i<NUM_OBTYPES; i++)
-    {
-        Status = ObReferenceObjectByName(&ObPathName[i],
-            OBJ_CASE_INSENSITIVE, NULL, 0L, NULL, KernelMode, NULL,
-            &TypeObject);
-
-        ObDereferenceObject(TypeObject);
-        ObDereferenceObject(TypeObject);
-        DPRINT("Reference Name %S = %p, ObTypes[%d] = %p\n",
-            ObPathName[i], TypeObject, i, ObTypes[i]);
-    }
-*/
-}
-
-#if 0
-static
-VOID
-ObtReferenceTests()
-{
-    USHORT i;
-    NTSTATUS Status;
-    UNICODE_STRING ObPathName[NUM_OBTYPES];
-
-    // Reference them by handle
-    for (i=0; i<NUM_OBTYPES; i++)
-    {
-        Status = ObReferenceObjectByHandle(ObHandle1[i], 0L, ObTypes[i],
-            KernelMode, &ObBody[i], NULL);
-        ok(Status == STATUS_SUCCESS,
-            "Failed to reference object by handle, status=0x%lX", Status);
-        DPRINT("Ref by handle %lx = %p\n", ObHandle1[i], ObBody[i]);
-    }
-
-    // Reference them by pointer
-    for (i=0; i<NUM_OBTYPES; i++)
-    {
-        Status = ObReferenceObjectByPointer(ObBody[i], 0L, ObTypes[i], KernelMode);
-        ok(Status == STATUS_SUCCESS,
-            "Failed to reference object by pointer, status=0x%lX", Status);
-    }
-
-    // Reference them by name
-    RtlInitUnicodeString(&ObPathName[0], L"\\ObtDirectory\\MyObject1");
-    RtlInitUnicodeString(&ObPathName[1], L"\\ObtDirectory\\MyObject2");
-
-    for (i=0; i<NUM_OBTYPES; i++)
-    {
-        Status = ObReferenceObjectByName(&ObPathName[i],
-            OBJ_CASE_INSENSITIVE, NULL, 0L, ObTypes[i], KernelMode, NULL,
-            &ObBody[0]);
-
-        DPRINT("Ref by name %wZ = %p\n", &ObPathName[i], ObBody[i]);
-    }
-
-    // Dereference now all of them
-
-    // For ObInsertObject, AdditionalReference
-    ObDereferenceObject(ObBody[0]);
-    ObDereferenceObject(ObBody[1]);
-
-    // For ByHandle
-    ObDereferenceObject(ObBody[0]);
-    ObDereferenceObject(ObBody[1]);
-
-    // For ByPointer
-    ObDereferenceObject(ObBody[0]);
-    ObDereferenceObject(ObBody[1]);
-
-    // For ByName
-    ObDereferenceObject(ObBody[0]);
-    ObDereferenceObject(ObBody[1]);
-}
-#endif /* 0 */
-
-START_TEST(ObCreate)
-{
-    DumpCount = 0; OpenCount = 0; CloseCount = 0;
-    DeleteCount = 0; ParseCount = 0;
-
-    // Create object-types to use in tests
-    ObtCreateObjectTypes();
-    DPRINT("ObtCreateObjectTypes() done\n");
-
-    // Create Directory
-    ObtCreateDirectory();
-    DPRINT("ObtCreateDirectory() done\n");
-
-    // Create and insert objects
-    ObtCreateObjects();
-    DPRINT("ObtCreateObjects() done\n");
-
-    // Reference them in a variety of ways
-    //ObtReferenceTests();
-
-    // Clean up
-    // FIXME: Disable to see results of creating objects in usermode.
-    //        Also it has problems with object types removal
-    ObtClose();
-    DPRINT("Cleanup done\n");
-}
diff --git a/kmtests/ntos_ob/ObType.c b/kmtests/ntos_ob/ObType.c
new file mode 100644 (file)
index 0000000..892a0b3
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ * PROJECT:         ReactOS kernel-mode tests
+ * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
+ * PURPOSE:         Kernel-Mode Test Suite Ob Regressions KM-Test
+ * PROGRAMMER:      Aleksey Bragin <aleksey@reactos.org>
+ *                  Thomas Faber <thfabba@gmx.de>
+ */
+
+/* TODO: split this into multiple tests! ObLifetime, ObHandle, ObName, ... */
+
+#include <kmt_test.h>
+
+//#define NDEBUG
+#include <debug.h>
+
+#define CheckObject(Handle, PCount, HCount) do                      \
+{                                                                   \
+    PUBLIC_OBJECT_BASIC_INFORMATION ObjectInfo;                     \
+    Status = ZwQueryObject(Handle, ObjectBasicInformation,          \
+                            &ObjectInfo, sizeof ObjectInfo, NULL);  \
+    ok_eq_hex(Status, STATUS_SUCCESS);                              \
+    ok_eq_ulong(ObjectInfo.PointerCount, PCount);                   \
+    ok_eq_ulong(ObjectInfo.HandleCount, HCount);                    \
+} while (0)
+
+#define NUM_OBTYPES 5
+
+typedef struct _MY_OBJECT1
+{
+    ULONG Something1;
+} MY_OBJECT1, *PMY_OBJECT1;
+
+typedef struct _MY_OBJECT2
+{
+    ULONG Something1;
+    ULONG SomeLong[10];
+} MY_OBJECT2, *PMY_OBJECT2;
+
+static POBJECT_TYPE            ObTypes[NUM_OBTYPES];
+static UNICODE_STRING          ObTypeName[NUM_OBTYPES];
+static UNICODE_STRING          ObName[NUM_OBTYPES];
+static OBJECT_TYPE_INITIALIZER ObTypeInitializer[NUM_OBTYPES];
+static UNICODE_STRING          ObDirectoryName;
+static OBJECT_ATTRIBUTES       ObDirectoryAttributes;
+static OBJECT_ATTRIBUTES       ObAttributes[NUM_OBTYPES];
+static PVOID                   ObBody[NUM_OBTYPES];
+static HANDLE                  ObHandle1[NUM_OBTYPES];
+static HANDLE                  ObHandle2[NUM_OBTYPES];
+static HANDLE                  DirectoryHandle;
+
+static USHORT                  DumpCount, OpenCount, CloseCount, DeleteCount,
+                               ParseCount, OkayToCloseCount, QueryNameCount;
+
+static
+VOID
+NTAPI
+DumpProc(
+    IN PVOID Object,
+    IN POB_DUMP_CONTROL DumpControl)
+{
+    DPRINT("DumpProc() called\n");
+    DumpCount++;
+}
+
+static
+NTSTATUS
+NTAPI
+OpenProc(
+    IN OB_OPEN_REASON OpenReason,
+    IN PEPROCESS Process,
+    IN PVOID Object,
+    IN ACCESS_MASK GrantedAccess,
+    IN ULONG HandleCount)
+{
+    DPRINT("OpenProc() 0x%p, OpenReason %d, HandleCount %lu, AccessMask 0x%lX\n",
+        Object, OpenReason, HandleCount, GrantedAccess);
+    OpenCount++;
+    return STATUS_SUCCESS;
+}
+
+static
+VOID
+NTAPI
+CloseProc(
+    IN PEPROCESS Process,
+    IN PVOID Object,
+    IN ACCESS_MASK GrantedAccess,
+    IN ULONG ProcessHandleCount,
+    IN ULONG SystemHandleCount)
+{
+    DPRINT("CloseProc() 0x%p, ProcessHandleCount %lu, SystemHandleCount %lu, AccessMask 0x%lX\n",
+        Object, ProcessHandleCount, SystemHandleCount, GrantedAccess);
+    CloseCount++;
+}
+
+static
+VOID
+NTAPI
+DeleteProc(
+    IN PVOID Object)
+{
+    DPRINT("DeleteProc() 0x%p\n", Object);
+    DeleteCount++;
+}
+
+static
+NTSTATUS
+NTAPI
+ParseProc(
+    IN PVOID ParseObject,
+    IN PVOID ObjectType,
+    IN OUT PACCESS_STATE AccessState,
+    IN KPROCESSOR_MODE AccessMode,
+    IN ULONG Attributes,
+    IN OUT PUNICODE_STRING CompleteName,
+    IN OUT PUNICODE_STRING RemainingName,
+    IN OUT PVOID Context OPTIONAL,
+    IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
+    OUT PVOID *Object)
+{
+    DPRINT("ParseProc() called\n");
+    *Object = NULL;
+
+    ParseCount++;
+    return STATUS_OBJECT_NAME_NOT_FOUND;//STATUS_SUCCESS;
+}
+
+#if 0
+static
+NTSTATUS
+NTAPI
+OkayToCloseProc(
+    IN PEPROCESS Process OPTIONAL,
+    IN PVOID Object,
+    IN HANDLE Handle,
+    IN KPROCESSOR_MODE AccessMode)
+{
+    DPRINT("OkayToCloseProc() 0x%p, Handle 0x%p, AccessMask 0x%lX\n",
+        Object, Handle, AccessMode);
+    OkayToCloseCount++;
+    return STATUS_SUCCESS;
+}
+
+static
+NTSTATUS
+NTAPI
+QueryNameProc(
+    IN PVOID Object,
+    IN BOOLEAN HasObjectName,
+    OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
+    IN ULONG Length,
+    OUT PULONG ReturnLength,
+    IN KPROCESSOR_MODE AccessMode)
+{
+    DPRINT("QueryNameProc() 0x%p, HasObjectName %d, Len %lu, AccessMask 0x%lX\n",
+        Object, HasObjectName, Length, AccessMode);
+    QueryNameCount++;
+
+    ObjectNameInfo = NULL;
+    ReturnLength = 0;
+    return STATUS_OBJECT_NAME_NOT_FOUND;
+}
+#endif /* 0 */
+
+static
+VOID
+ObtCreateObjectTypes(VOID)
+{
+    INT i;
+    NTSTATUS Status;
+    WCHAR Name[15];
+
+    for (i = 0; i < NUM_OBTYPES; i++)
+    {
+        Status = RtlStringCbPrintfW(Name, sizeof Name, L"MyObjectType%x", i);
+        ASSERT(NT_SUCCESS(Status));
+        RtlInitUnicodeString(&ObTypeName[i], Name);
+
+        RtlZeroMemory(&ObTypeInitializer[i], sizeof ObTypeInitializer[i]);
+        ObTypeInitializer[i].Length = sizeof ObTypeInitializer[i];
+        ObTypeInitializer[i].PoolType = NonPagedPool;
+        ObTypeInitializer[i].MaintainHandleCount = TRUE;
+        ObTypeInitializer[i].ValidAccessMask = OBJECT_TYPE_ALL_ACCESS;
+
+        // Test for invalid parameter
+        // FIXME: Make it more exact, to see which params Win2k3 checks
+        // existence of
+        Status = ObCreateObjectType(&ObTypeName[i], &ObTypeInitializer[i], NULL, &ObTypes[i]);
+        ok_eq_hex(Status, STATUS_INVALID_PARAMETER);
+
+        ObTypeInitializer[i].CloseProcedure = CloseProc;
+        ObTypeInitializer[i].DeleteProcedure = DeleteProc;
+        ObTypeInitializer[i].DumpProcedure = DumpProc;
+        ObTypeInitializer[i].OpenProcedure = OpenProc;
+        ObTypeInitializer[i].ParseProcedure = ParseProc;
+        //ObTypeInitializer[i].OkayToCloseProcedure = OkayToCloseProc;
+        //ObTypeInitializer[i].QueryNameProcedure = QueryNameProc;
+        //ObTypeInitializer[i].SecurityProcedure = SecurityProc;
+
+        Status = ObCreateObjectType(&ObTypeName[i], &ObTypeInitializer[i], NULL, &ObTypes[i]);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+    }
+}
+
+static
+VOID
+ObtCreateDirectory(VOID)
+{
+    NTSTATUS Status;
+
+    RtlInitUnicodeString(&ObDirectoryName, L"\\ObtDirectory");
+    InitializeObjectAttributes(&ObDirectoryAttributes, &ObDirectoryName, OBJ_PERMANENT | OBJ_CASE_INSENSITIVE, NULL, NULL);
+    Status = ZwCreateDirectoryObject(&DirectoryHandle, DELETE, &ObDirectoryAttributes);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+    CheckObject(DirectoryHandle, 3LU, 1LU);
+}
+
+#define CheckCounts(Open, Close, Delete, Parse, OkayToClose, QueryName) do  \
+{                                                                           \
+    ok_eq_uint(OpenCount, Open);                                            \
+    ok_eq_uint(CloseCount, Close);                                          \
+    ok_eq_uint(DeleteCount, Delete);                                        \
+    ok_eq_uint(ParseCount, Parse);                                          \
+    ok_eq_uint(OkayToCloseCount, OkayToClose);                              \
+    ok_eq_uint(QueryNameCount, QueryName);                                  \
+} while (0)
+
+#define SaveCounts(Open, Close, Delete, Parse, OkayToClose, QueryName) do   \
+{                                                                           \
+    Open = OpenCount;                                                       \
+    Close = CloseCount;                                                     \
+    Delete = DeleteCount;                                                   \
+    Parse = ParseCount;                                                     \
+    OkayToClose = OkayToCloseCount;                                         \
+    QueryName = QueryNameCount;                                             \
+} while (0)
+
+/* TODO: make this the same as NUM_OBTYPES */
+#define NUM_OBTYPES2 2
+static
+VOID
+ObtCreateObjects(VOID)
+{
+    PVOID ObBody1[2] = { NULL };
+    NTSTATUS Status;
+    WCHAR Name[NUM_OBTYPES2][MAX_PATH];
+    USHORT OpenSave, CloseSave, DeleteSave, ParseSave, OkayToCloseSave, QueryNameSave;
+    INT i;
+    ACCESS_MASK Access[NUM_OBTYPES2] = { STANDARD_RIGHTS_ALL, GENERIC_ALL };
+    ULONG ObjectSize[NUM_OBTYPES2] = { sizeof(MY_OBJECT1), sizeof(MY_OBJECT2) };
+
+    // Create two objects
+    for (i = 0; i < NUM_OBTYPES2; ++i)
+    {
+        ASSERT(sizeof Name[i] == MAX_PATH * sizeof(WCHAR));
+        Status = RtlStringCbPrintfW(Name[i], sizeof Name[i], L"\\ObtDirectory\\MyObject%d", i + 1);
+        ASSERT(Status == STATUS_SUCCESS);
+        RtlInitUnicodeString(&ObName[i], Name[i]);
+        InitializeObjectAttributes(&ObAttributes[i], &ObName[i], OBJ_CASE_INSENSITIVE, NULL, NULL);
+    }
+
+    for (i = 0; i < NUM_OBTYPES2; ++i)
+    {
+        Status = ObCreateObject(KernelMode, ObTypes[i], &ObAttributes[i], KernelMode, NULL, ObjectSize[i], 0L, 0L, &ObBody[i]);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+    }
+
+    SaveCounts(OpenSave, CloseSave, DeleteSave, ParseSave, OkayToCloseSave, QueryNameSave);
+
+    // Insert them
+    for (i = 0; i < NUM_OBTYPES2; ++i)
+    {
+        Status = ObInsertObject(ObBody[i], NULL, Access[i], 0, &ObBody[i], &ObHandle1[i]);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        ok(ObBody[i] != NULL, "Object body = NULL\n");
+        ok(ObHandle1[i] != NULL, "Handle = NULL\n");
+        CheckObject(ObHandle1[i], 3LU, 1LU);
+        CheckCounts(OpenSave + 1, CloseSave, DeleteSave, ParseSave, OkayToCloseSave, QueryNameSave);
+        SaveCounts(OpenSave, CloseSave, DeleteSave, ParseSave, OkayToCloseSave, QueryNameSave);
+    }
+
+    // Now create an object of type 0, of the same name and expect it to fail
+    // inserting, but success creation
+    ok_eq_wstr(ObName[0].Buffer, L"\\ObtDirectory\\MyObject1");
+    RtlInitUnicodeString(&ObName[0], L"\\ObtDirectory\\MyObject1");
+    InitializeObjectAttributes(&ObAttributes[0], &ObName[0], OBJ_OPENIF, NULL, NULL);
+
+    Status = ObCreateObject(KernelMode, ObTypes[0], &ObAttributes[0], KernelMode, NULL, sizeof(MY_OBJECT1), 0L, 0L, &ObBody1[0]);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+    CheckCounts(OpenSave, CloseSave, DeleteSave, ParseSave, OkayToCloseSave, QueryNameSave);
+
+    Status = ObInsertObject(ObBody1[0], NULL, GENERIC_ALL, 0, &ObBody1[1], &ObHandle2[0]);
+    ok_eq_hex(Status, STATUS_ACCESS_DENIED/*STATUS_OBJECT_NAME_EXISTS*/);
+    ok_eq_pointer(ObBody[0], ObBody1[1]);
+    ok(ObHandle2[0] != NULL, "NULL handle returned\n");
+
+    DPRINT("%d %d %d %d %d %d %d\n", DumpCount, OpenCount, CloseCount, DeleteCount, ParseCount, OkayToCloseCount, QueryNameCount);
+    CheckCounts(OpenSave + 1, CloseSave, DeleteSave + 1, ParseSave, OkayToCloseSave, QueryNameSave);
+    SaveCounts(OpenSave, CloseSave, DeleteSave, ParseSave, OkayToCloseSave, QueryNameSave);
+
+    // Close its handle
+    if (!skip(ObHandle2[0] && ObHandle2[0] != INVALID_HANDLE_VALUE, "Nothing to close\n"))
+    {
+        Status = ZwClose(ObHandle2[0]);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        CheckCounts(OpenSave, CloseSave + 1, DeleteSave, ParseSave, OkayToCloseSave, QueryNameSave);
+        SaveCounts(OpenSave, CloseSave, DeleteSave, ParseSave, OkayToCloseSave, QueryNameSave);
+    }
+
+    // Object referenced 2 times:
+    // 1) ObInsertObject
+    // 2) AdditionalReferences
+    if (ObBody1[1])
+        ObDereferenceObject(ObBody1[1]);
+    //DPRINT1("%d %d %d %d %d %d %d\n", DumpCount, OpenCount, CloseCount, DeleteCount, ParseCount, OkayToCloseCount, QueryNameCount);
+    CheckCounts(OpenSave, CloseSave, DeleteSave, ParseSave, OkayToCloseSave, QueryNameSave);
+}
+
+static
+VOID
+ObtClose(
+    BOOLEAN Clean,
+    BOOLEAN AlternativeMethod)
+{
+    PVOID DirObject;
+    NTSTATUS Status;
+    PVOID TypeObject;
+    INT i;
+    UNICODE_STRING ObPathName[NUM_OBTYPES];
+    WCHAR Name[MAX_PATH];
+
+    // Close what we have opened and free what we allocated
+    for (i = 0; i < NUM_OBTYPES2; ++i)
+    {
+        if (ObBody[i])
+        {
+            if (ObHandle1[i]) CheckObject(ObHandle1[i], 3LU, 1LU);
+            ObDereferenceObject(ObBody[i]);
+            if (ObHandle1[i]) CheckObject(ObHandle1[i], 2LU, 1LU);
+            ObBody[i] = NULL;
+        }
+        if (ObHandle1[i])
+        {
+            ZwClose(ObHandle1[i]);
+            ObHandle1[i] = NULL;
+        }
+        if (ObHandle2[i])
+        {
+            ZwClose(ObHandle2[i]);
+            ObHandle2[i] = NULL;
+        }
+    }
+
+    if (!Clean)
+        return;
+
+    // Now we have to get rid of a directory object
+    // Since it is permanent, we have to firstly make it temporary
+    // and only then kill
+    // (this procedure is described in DDK)
+    if (DirectoryHandle && DirectoryHandle != INVALID_HANDLE_VALUE)
+    {
+        CheckObject(DirectoryHandle, 3LU, 1LU);
+        Status = ObReferenceObjectByHandle(DirectoryHandle, 0L, NULL, KernelMode, &DirObject, NULL);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        CheckObject(DirectoryHandle, 4LU, 1LU);
+
+        Status = ZwMakeTemporaryObject(DirectoryHandle);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        CheckObject(DirectoryHandle, 4LU, 1LU);
+        
+        // Dereference 2 times - first for just previous referencing
+        // and 2nd time for creation of permanent object itself
+        ObDereferenceObject(DirObject);
+        CheckObject(DirectoryHandle, 3LU, 1LU);
+        ObDereferenceObject(DirObject);
+        CheckObject(DirectoryHandle, 2LU, 1LU);
+
+        Status = ZwClose(DirectoryHandle);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+    }
+
+    // Now delete the last piece - object types
+    // In fact, it's weird to get rid of object types, especially the way,
+    // how it's done in the commented section below
+    if (!AlternativeMethod)
+    {
+        for (i = 0; i < NUM_OBTYPES; ++i)
+            if (ObTypes[i])
+            {
+                ObDereferenceObject(ObTypes[i]);
+                ObTypes[i] = NULL;
+            }
+    }
+    else
+    {
+        for (i = 0; i < NUM_OBTYPES; ++i)
+        {
+            if (ObTypes[i])
+            {
+                Status = RtlStringCbPrintfW(Name, sizeof Name, L"\\ObjectTypes\\MyObjectType%d", i);
+                RtlInitUnicodeString(&ObPathName[0], Name);
+                Status = ObReferenceObjectByName(&ObPathName[i], OBJ_CASE_INSENSITIVE, NULL, 0L, NULL, KernelMode, NULL, &TypeObject);
+
+                ObDereferenceObject(TypeObject);
+                ObDereferenceObject(TypeObject);
+                DPRINT("Reference Name %wZ = %p, ObTypes[%d] = %p\n",
+                    ObPathName[i], TypeObject, i, ObTypes[i]);
+                ObTypes[i] = NULL;
+            }
+        }
+    }
+}
+
+#if 0
+static
+VOID
+ObtReferenceTests(VOID)
+{
+    INT i;
+    NTSTATUS Status;
+    UNICODE_STRING ObPathName[NUM_OBTYPES];
+
+    // Reference them by handle
+    for (i = 0; i < NUM_OBTYPES2; i++)
+    {
+        CheckObject(ObHandle1[i], 2LU, 1LU);
+        Status = ObReferenceObjectByHandle(ObHandle1[i], 0L, ObTypes[i], KernelMode, &ObBody[i], NULL);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+        CheckObject(ObHandle1[i], 3LU, 1LU);
+        DPRINT("Ref by handle %lx = %p\n", ObHandle1[i], ObBody[i]);
+    }
+
+    // Reference them by pointer
+    for (i = 0; i < NUM_OBTYPES2; i++)
+    {
+        CheckObject(ObHandle1[i], 3LU, 1LU);
+        Status = ObReferenceObjectByPointer(ObBody[i], 0L, ObTypes[i], KernelMode);
+        CheckObject(ObHandle1[i], 4LU, 1LU);
+        ok_eq_hex(Status, STATUS_SUCCESS);
+    }
+
+    // Reference them by name
+    RtlInitUnicodeString(&ObPathName[0], L"\\ObtDirectory\\MyObject1");
+    RtlInitUnicodeString(&ObPathName[1], L"\\ObtDirectory\\MyObject2");
+
+#if 0
+    for (i = 0; i < NUM_OBTYPES2; i++)
+    {
+        Status = ObReferenceObjectByName(&ObPathName[i], OBJ_CASE_INSENSITIVE, NULL, 0L, ObTypes[i], KernelMode, NULL, &ObBody[i]);
+        DPRINT("Ref by name %wZ = %p\n", &ObPathName[i], ObBody[i]);
+    }
+#endif
+
+    // Dereference now all of them
+
+    for (i = 0; i < NUM_OBTYPES2; ++i)
+        if (!skip(ObBody[i] != NULL, "Object pointer is NULL\n"))
+        {
+            CheckObject(ObHandle1[i], 4LU, 1LU);
+            // For ObInsertObject, AdditionalReference
+            //ObDereferenceObject(ObBody[i]);
+            // For ByName
+            //ObDereferenceObject(ObBody[i]);
+            // For ByPointer
+            ObDereferenceObject(ObBody[i]);
+            CheckObject(ObHandle1[i], 3LU, 1LU);
+            // For ByHandle
+            ObDereferenceObject(ObBody[i]);
+            CheckObject(ObHandle1[i], 2LU, 1LU);
+        }
+}
+#endif /* 0 */
+
+static
+VOID
+TestObjectType(
+    IN BOOLEAN Clean)
+{
+    DumpCount = 0; OpenCount = 0; CloseCount = 0;
+    DeleteCount = 0; ParseCount = 0;
+
+    ObtCreateObjectTypes();
+    DPRINT("ObtCreateObjectTypes() done\n");
+
+    ObtCreateDirectory();
+    DPRINT("ObtCreateDirectory() done\n");
+
+    ObtCreateObjects();
+    DPRINT("ObtCreateObjects() done\n");
+
+    //ObtReferenceTests();
+
+    ObtClose(Clean, FALSE);
+}
+
+START_TEST(ObType)
+{
+    TestObjectType(TRUE);
+}
+
+/* run this to see the objects created in user mode */
+START_TEST(ObTypeNoClean)
+{
+    TestObjectType(FALSE);
+    trace("Cleanup skipped as requested! Run ObTypeClean to clean up\n");
+}
+
+/* run this to clean up after ObTypeNoClean */
+START_TEST(ObTypeClean)
+{
+    ObtClose(TRUE, FALSE);
+    trace("Cleanup done\n");
+}
diff --git a/kmtests/readme.txt b/kmtests/readme.txt
new file mode 100644 (file)
index 0000000..fa9a66b
--- /dev/null
@@ -0,0 +1,11 @@
+This directory contains the ReactOS Kernel-Mode Test Suite.
+
+The kmtest, kmtest_drv and include subdirectories contain the
+testing framework infrastructure, other directories contain tests.
+
+The example subdirectory contains a set of small tests that can be used as
+examples and templates.
+
+
+See http://www.reactos.org/wiki/User:ThFabba/KmtestsHowto for more
+information and a guide on how to use the framework.