2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Ob Regressions KM-Test
5 * PROGRAMMER: Aleksey Bragin <aleksey@reactos.org>
6 * Thomas Faber <thfabba@gmx.de>
9 /* TODO: split this into multiple tests! ObLife, ObHandle, ObName, ... */
16 #define CheckObject(Handle, Pointers, Handles) do \
18 PUBLIC_OBJECT_BASIC_INFORMATION ObjectInfo; \
19 Status = ZwQueryObject(Handle, ObjectBasicInformation, \
20 &ObjectInfo, sizeof ObjectInfo, NULL); \
21 ok_eq_hex(Status, STATUS_SUCCESS); \
22 ok_eq_ulong(ObjectInfo.PointerCount, Pointers); \
23 ok_eq_ulong(ObjectInfo.HandleCount, Handles); \
28 typedef struct _MY_OBJECT1
31 } MY_OBJECT1
, *PMY_OBJECT1
;
33 typedef struct _MY_OBJECT2
37 } MY_OBJECT2
, *PMY_OBJECT2
;
39 static POBJECT_TYPE ObTypes
[NUM_OBTYPES
];
40 static UNICODE_STRING ObTypeName
[NUM_OBTYPES
];
41 static UNICODE_STRING ObName
[NUM_OBTYPES
];
42 static OBJECT_TYPE_INITIALIZER ObTypeInitializer
[NUM_OBTYPES
];
43 static UNICODE_STRING ObDirectoryName
;
44 static OBJECT_ATTRIBUTES ObDirectoryAttributes
;
45 static OBJECT_ATTRIBUTES ObAttributes
[NUM_OBTYPES
];
46 static PVOID ObBody
[NUM_OBTYPES
];
47 static HANDLE ObHandle1
[NUM_OBTYPES
];
48 static HANDLE DirectoryHandle
;
50 typedef struct _COUNTS
67 IN POB_DUMP_CONTROL DumpControl
)
69 DPRINT("DumpProc() called\n");
77 IN OB_OPEN_REASON OpenReason
,
80 IN ACCESS_MASK GrantedAccess
,
83 DPRINT("OpenProc() 0x%p, OpenReason %d, HandleCount %lu, AccessMask 0x%lX\n",
84 Object
, OpenReason
, HandleCount
, GrantedAccess
);
86 return STATUS_SUCCESS
;
95 IN ACCESS_MASK GrantedAccess
,
96 IN ULONG ProcessHandleCount
,
97 IN ULONG SystemHandleCount
)
99 DPRINT("CloseProc() 0x%p, ProcessHandleCount %lu, SystemHandleCount %lu, AccessMask 0x%lX\n",
100 Object
, ProcessHandleCount
, SystemHandleCount
, GrantedAccess
);
110 DPRINT("DeleteProc() 0x%p\n", Object
);
118 IN PVOID ParseObject
,
120 IN OUT PACCESS_STATE AccessState
,
121 IN KPROCESSOR_MODE AccessMode
,
123 IN OUT PUNICODE_STRING CompleteName
,
124 IN OUT PUNICODE_STRING RemainingName
,
125 IN OUT PVOID Context OPTIONAL
,
126 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
129 DPRINT("ParseProc() called\n");
133 return STATUS_OBJECT_NAME_NOT_FOUND
;//STATUS_SUCCESS;
140 IN PEPROCESS Process OPTIONAL
,
143 IN KPROCESSOR_MODE AccessMode
)
145 DPRINT("OkayToCloseProc() 0x%p, Handle 0x%p, AccessMask 0x%lX\n",
146 Object
, Handle
, AccessMode
);
147 ++Counts
.OkayToClose
;
156 IN BOOLEAN HasObjectName
,
157 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
159 OUT PULONG ReturnLength
,
160 IN KPROCESSOR_MODE AccessMode
)
162 DPRINT("QueryNameProc() 0x%p, HasObjectName %d, Len %lu, AccessMask 0x%lX\n",
163 Object
, HasObjectName
, Length
, AccessMode
);
166 ObjectNameInfo
= NULL
;
168 return STATUS_OBJECT_NAME_NOT_FOUND
;
173 ObtCreateObjectTypes(VOID
)
179 WCHAR DirectoryName
[sizeof "\\ObjectTypes\\" - 1];
182 OBJECT_ATTRIBUTES ObjectAttributes
;
183 HANDLE ObjectTypeHandle
;
184 UNICODE_STRING ObjectPath
;
186 RtlCopyMemory(&Name
.DirectoryName
, L
"\\ObjectTypes\\", sizeof Name
.DirectoryName
);
188 for (i
= 0; i
< NUM_OBTYPES
; ++i
)
190 Status
= RtlStringCbPrintfW(Name
.TypeName
, sizeof Name
.TypeName
, L
"MyObjectType%x", i
);
191 ASSERT(NT_SUCCESS(Status
));
192 RtlInitUnicodeString(&ObTypeName
[i
], Name
.TypeName
);
193 DPRINT("Creating object type %wZ\n", &ObTypeName
[i
]);
195 RtlZeroMemory(&ObTypeInitializer
[i
], sizeof ObTypeInitializer
[i
]);
196 ObTypeInitializer
[i
].Length
= sizeof ObTypeInitializer
[i
];
197 ObTypeInitializer
[i
].PoolType
= NonPagedPool
;
198 ObTypeInitializer
[i
].MaintainHandleCount
= TRUE
;
199 ObTypeInitializer
[i
].ValidAccessMask
= OBJECT_TYPE_ALL_ACCESS
;
201 // Test for invalid parameter
202 // FIXME: Make it more exact, to see which params Win2k3 checks
204 Status
= ObCreateObjectType(&ObTypeName
[i
], &ObTypeInitializer
[i
], NULL
, &ObTypes
[i
]);
205 ok_eq_hex(Status
, STATUS_INVALID_PARAMETER
);
207 ObTypeInitializer
[i
].CloseProcedure
= CloseProc
;
208 ObTypeInitializer
[i
].DeleteProcedure
= DeleteProc
;
209 ObTypeInitializer
[i
].DumpProcedure
= DumpProc
;
210 ObTypeInitializer
[i
].OpenProcedure
= OpenProc
;
211 ObTypeInitializer
[i
].ParseProcedure
= ParseProc
;
212 ObTypeInitializer
[i
].OkayToCloseProcedure
= OkayToCloseProc
;
213 ObTypeInitializer
[i
].QueryNameProcedure
= QueryNameProc
;
214 //ObTypeInitializer[i].SecurityProcedure = SecurityProc;
216 Status
= ObCreateObjectType(&ObTypeName
[i
], &ObTypeInitializer
[i
], NULL
, &ObTypes
[i
]);
217 if (Status
== STATUS_OBJECT_NAME_COLLISION
)
219 /* as we cannot delete the object types, get a pointer if they
221 RtlInitUnicodeString(&ObjectPath
, Name
.DirectoryName
);
222 InitializeObjectAttributes(&ObjectAttributes
, &ObjectPath
, OBJ_KERNEL_HANDLE
, NULL
, NULL
);
223 Status
= ObOpenObjectByName(&ObjectAttributes
, NULL
, KernelMode
, NULL
, 0, NULL
, &ObjectTypeHandle
);
224 ok_eq_hex(Status
, STATUS_SUCCESS
);
225 ok(ObjectTypeHandle
!= NULL
, "ObjectTypeHandle = NULL\n");
226 if (!skip(Status
== STATUS_SUCCESS
&& ObjectTypeHandle
, "No handle\n"))
228 Status
= ObReferenceObjectByHandle(ObjectTypeHandle
, 0, NULL
, KernelMode
, (PVOID
)&ObTypes
[i
], NULL
);
229 ok_eq_hex(Status
, STATUS_SUCCESS
);
230 if (!skip(Status
== STATUS_SUCCESS
&& ObTypes
[i
], "blah\n"))
232 ObTypes
[i
]->TypeInfo
.CloseProcedure
= CloseProc
;
233 ObTypes
[i
]->TypeInfo
.DeleteProcedure
= DeleteProc
;
234 ObTypes
[i
]->TypeInfo
.DumpProcedure
= DumpProc
;
235 ObTypes
[i
]->TypeInfo
.OpenProcedure
= OpenProc
;
236 ObTypes
[i
]->TypeInfo
.ParseProcedure
= ParseProc
;
237 ObTypes
[i
]->TypeInfo
.OkayToCloseProcedure
= OkayToCloseProc
;
238 ObTypes
[i
]->TypeInfo
.QueryNameProcedure
= QueryNameProc
;
240 Status
= ZwClose(ObjectTypeHandle
);
244 ok_eq_hex(Status
, STATUS_SUCCESS
);
245 ok(ObTypes
[i
] != NULL
, "ObType = NULL\n");
251 ObtCreateDirectory(VOID
)
255 RtlInitUnicodeString(&ObDirectoryName
, L
"\\ObtDirectory");
256 InitializeObjectAttributes(&ObDirectoryAttributes
, &ObDirectoryName
, OBJ_KERNEL_HANDLE
| OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
257 Status
= ZwCreateDirectoryObject(&DirectoryHandle
, DELETE
, &ObDirectoryAttributes
);
258 ok_eq_hex(Status
, STATUS_SUCCESS
);
259 CheckObject(DirectoryHandle
, 3LU, 1LU);
262 #define CheckCounts(OpenCount, CloseCount, DeleteCount, ParseCount, \
263 OkayToCloseCount, QueryNameCount) do \
265 ok_eq_uint(Counts.Open, OpenCount); \
266 ok_eq_uint(Counts.Close, CloseCount); \
267 ok_eq_uint(Counts.Delete, DeleteCount); \
268 ok_eq_uint(Counts.Parse, ParseCount); \
269 ok_eq_uint(Counts.OkayToClose, OkayToCloseCount); \
270 ok_eq_uint(Counts.QueryName, QueryNameCount); \
273 #define SaveCounts(Save) memcpy(&Save, &Counts, sizeof Counts)
275 /* TODO: make this the same as NUM_OBTYPES */
276 #define NUM_OBTYPES2 2
279 ObtCreateObjects(VOID
)
282 WCHAR Name
[NUM_OBTYPES2
][MAX_PATH
];
285 ACCESS_MASK Access
[NUM_OBTYPES2
] = { STANDARD_RIGHTS_ALL
, GENERIC_ALL
};
286 ULONG ObjectSize
[NUM_OBTYPES2
] = { sizeof(MY_OBJECT1
), sizeof(MY_OBJECT2
) };
288 // Create two objects
289 for (i
= 0; i
< NUM_OBTYPES2
; ++i
)
291 ASSERT(sizeof Name
[i
] == MAX_PATH
* sizeof(WCHAR
));
292 Status
= RtlStringCbPrintfW(Name
[i
], sizeof Name
[i
], L
"\\ObtDirectory\\MyObject%d", i
+ 1);
293 ASSERT(Status
== STATUS_SUCCESS
);
294 RtlInitUnicodeString(&ObName
[i
], Name
[i
]);
295 InitializeObjectAttributes(&ObAttributes
[i
], &ObName
[i
], OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
297 CheckObject(DirectoryHandle
, 3LU, 1LU);
299 for (i
= 0; i
< NUM_OBTYPES2
; ++i
)
301 Status
= ObCreateObject(KernelMode
, ObTypes
[i
], &ObAttributes
[i
], KernelMode
, NULL
, ObjectSize
[i
], 0L, 0L, &ObBody
[i
]);
302 ok_eq_hex(Status
, STATUS_SUCCESS
);
305 SaveCounts(SaveCounts
);
308 for (i
= 0; i
< NUM_OBTYPES2
; ++i
)
310 CheckObject(DirectoryHandle
, 3LU + i
, 1LU);
311 Status
= ObInsertObject(ObBody
[i
], NULL
, Access
[i
], 0, &ObBody
[i
], &ObHandle1
[i
]);
312 ok_eq_hex(Status
, STATUS_SUCCESS
);
313 ok(ObBody
[i
] != NULL
, "Object body = NULL\n");
314 ok(ObHandle1
[i
] != NULL
, "Handle = NULL\n");
315 CheckObject(ObHandle1
[i
], 3LU, 1LU);
316 CheckCounts(SaveCounts
.Open
+ 1, SaveCounts
.Close
, SaveCounts
.Delete
, SaveCounts
.Parse
, SaveCounts
.OkayToClose
, SaveCounts
.QueryName
);
317 SaveCounts(SaveCounts
);
318 CheckObject(DirectoryHandle
, 4LU + i
, 1LU);
321 //DPRINT1("%d %d %d %d %d %d %d\n", DumpCount, OpenCount, CloseCount, DeleteCount, ParseCount, OkayToCloseCount, QueryNameCount);
322 CheckCounts(SaveCounts
.Open
, SaveCounts
.Close
, SaveCounts
.Delete
, SaveCounts
.Parse
, SaveCounts
.OkayToClose
, SaveCounts
.QueryName
);
329 BOOLEAN AlternativeMethod
)
335 UNICODE_STRING ObPathName
[NUM_OBTYPES
];
336 WCHAR Name
[MAX_PATH
];
338 // Close what we have opened and free what we allocated
339 for (i
= 0; i
< NUM_OBTYPES2
; ++i
)
341 if (!skip(ObBody
[i
] != NULL
, "Nothing to dereference\n"))
343 if (ObHandle1
[i
]) CheckObject(ObHandle1
[i
], 3LU, 1LU);
344 Ret
= ObDereferenceObject(ObBody
[i
]);
345 ok_eq_longptr(Ret
, (LONG_PTR
)1);
346 if (ObHandle1
[i
]) CheckObject(ObHandle1
[i
], 2LU, 1LU);
349 if (!skip(ObHandle1
[i
] != NULL
, "Nothing to close\n"))
351 Status
= ZwClose(ObHandle1
[i
]);
352 ok_eq_hex(Status
, STATUS_SUCCESS
);
357 if (skip(Clean
, "Not cleaning up, as requested. Use ObTypeClean to clean up\n"))
360 // Now we have to get rid of a directory object
361 // Since it is permanent, we have to firstly make it temporary
362 // and only then kill
363 // (this procedure is described in DDK)
364 if (!skip(DirectoryHandle
!= NULL
, "No directory handle\n"))
366 CheckObject(DirectoryHandle
, 3LU, 1LU);
368 Status
= ZwMakeTemporaryObject(DirectoryHandle
);
369 ok_eq_hex(Status
, STATUS_SUCCESS
);
370 CheckObject(DirectoryHandle
, 3LU, 1LU);
372 Status
= ZwClose(DirectoryHandle
);
373 ok_eq_hex(Status
, STATUS_SUCCESS
);
376 /* we don't delete the object types we created. It makes Windows unstable.
377 * TODO: perhaps make it work in ROS anyway */
379 if (!AlternativeMethod
)
381 for (i
= 0; i
< NUM_OBTYPES
; ++i
)
382 if (!skip(ObTypes
[i
] != NULL
, "No object type to delete\n"))
384 Ret
= ObDereferenceObject(ObTypes
[i
]);
385 ok_eq_longptr(Ret
, (LONG_PTR
)0);
391 for (i
= 0; i
< NUM_OBTYPES
; ++i
)
393 if (!skip(ObTypes
[i
] != NULL
, "No object type to delete\n"))
395 Status
= RtlStringCbPrintfW(Name
, sizeof Name
, L
"\\ObjectTypes\\MyObjectType%d", i
);
396 RtlInitUnicodeString(&ObPathName
[i
], Name
);
397 Status
= ObReferenceObjectByName(&ObPathName
[i
], OBJ_CASE_INSENSITIVE
, NULL
, 0L, NULL
, KernelMode
, NULL
, &TypeObject
);
399 Ret
= ObDereferenceObject(TypeObject
);
400 ok_eq_longptr(Ret
, (LONG_PTR
)2);
401 Ret
= ObDereferenceObject(TypeObject
);
402 ok_eq_longptr(Ret
, (LONG_PTR
)1);
403 DPRINT("Reference Name %wZ = %p, ObTypes[%d] = %p\n",
404 ObPathName
[i
], TypeObject
, i
, ObTypes
[i
]);
416 RtlZeroMemory(&Counts
, sizeof Counts
);
418 ObtCreateObjectTypes();
419 DPRINT("ObtCreateObjectTypes() done\n");
421 ObtCreateDirectory();
422 DPRINT("ObtCreateDirectory() done\n");
424 if (!skip(ObTypes
[0] != NULL
, "No object types!\n"))
426 DPRINT("ObtCreateObjects() done\n");
428 ObtClose(Clean
, FALSE
);
433 TestObjectType(TRUE
);
436 /* run this to see the objects created in user mode */
437 START_TEST(ObTypeNoClean
)
439 TestObjectType(FALSE
);
442 /* run this to clean up after ObTypeNoClean */
443 START_TEST(ObTypeClean
)
445 ObtClose(TRUE
, FALSE
);