Reactos
1/*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
4 * PURPOSE: Kernel-Mode Test Suite test framework declarations
5 * COPYRIGHT: Copyright 2011-2018 Thomas Faber <thomas.faber@reactos.org>
6 * Copyright 2013 Nikolay Borisov <nib9@aber.ac.uk>
7 * Copyright 2014-2016 Pierre Schweitzer <pierre@reactos.org>
8 * Copyright 2017 Ged Murphy <gedmurphy@reactos.org>
9 */
10
11/* Inspired by Wine C unit tests, Copyright (C) 2002 Alexandre Julliard
12 * Inspired by ReactOS kernel-mode regression tests,
13 * Copyright (C) Aleksey Bragin, Filip Navara
14 */
15
16#ifndef _KMTEST_TEST_H_
17#define _KMTEST_TEST_H_
18
19#include <kmt_platform.h>
20
21#define GetNTVersion() ((SharedUserData->NtMajorVersion << 8) | SharedUserData->NtMinorVersion)
22
23typedef VOID KMT_TESTFUNC(VOID);
24typedef KMT_TESTFUNC *PKMT_TESTFUNC;
25
26typedef struct
27{
28 const char *TestName;
29 KMT_TESTFUNC *TestFunction;
30} KMT_TEST, *PKMT_TEST;
31
32typedef const KMT_TEST CKMT_TEST, *PCKMT_TEST;
33
34extern const KMT_TEST TestList[];
35
36typedef struct
37{
38 volatile LONG Successes;
39 volatile LONG Failures;
40 volatile LONG Skipped;
41 volatile LONG LogBufferLength;
42 LONG LogBufferMaxLength;
43 CHAR LogBuffer[ANYSIZE_ARRAY];
44} KMT_RESULTBUFFER, *PKMT_RESULTBUFFER;
45
46#ifndef KMT_STANDALONE_DRIVER
47
48/* usermode call-back mechanism */
49
50/* list of supported operations */
51typedef enum _KMT_CALLBACK_INFORMATION_CLASS
52{
53 QueryVirtualMemory
54} KMT_CALLBACK_INFORMATION_CLASS, *PKMT_CALLBACK_INFORMATION_CLASS;
55
56/* TODO: "response" is a little generic */
57typedef union _KMT_RESPONSE
58{
59 MEMORY_BASIC_INFORMATION MemInfo;
60} KMT_RESPONSE, *PKMT_RESPONSE;
61
62/* this struct is sent from driver to usermode */
63typedef struct _KMT_CALLBACK_REQUEST_PACKET
64{
65 ULONG RequestId;
66 KMT_CALLBACK_INFORMATION_CLASS OperationClass;
67 PVOID Parameters;
68} KMT_CALLBACK_REQUEST_PACKET, *PKMT_CALLBACK_REQUEST_PACKET;
69
70PKMT_RESPONSE KmtUserModeCallback(KMT_CALLBACK_INFORMATION_CLASS Operation, PVOID Parameters);
71VOID KmtFreeCallbackResponse(PKMT_RESPONSE Response);
72
73//macro to simplify using the mechanism
74#define Test_NtQueryVirtualMemory(BaseAddress, Size, AllocationType, ProtectionType) \
75 do { \
76 PKMT_RESPONSE NtQueryTest = KmtUserModeCallback(QueryVirtualMemory, BaseAddress); \
77 if (NtQueryTest != NULL) \
78 { \
79 ok_eq_hex(NtQueryTest->MemInfo.Protect, ProtectionType); \
80 ok_eq_hex(NtQueryTest->MemInfo.State, AllocationType); \
81 ok_eq_size(NtQueryTest->MemInfo.RegionSize, Size); \
82 KmtFreeCallbackResponse(NtQueryTest); \
83 } \
84 } while (0) \
85
86#endif
87
88#ifdef KMT_STANDALONE_DRIVER
89#define KMT_KERNEL_MODE
90
91typedef NTSTATUS (KMT_IRP_HANDLER)(
92 IN PDEVICE_OBJECT DeviceObject,
93 IN PIRP Irp,
94 IN PIO_STACK_LOCATION IoStackLocation);
95typedef KMT_IRP_HANDLER *PKMT_IRP_HANDLER;
96
97NTSTATUS KmtRegisterIrpHandler(IN UCHAR MajorFunction, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_IRP_HANDLER IrpHandler);
98NTSTATUS KmtUnregisterIrpHandler(IN UCHAR MajorFunction, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_IRP_HANDLER IrpHandler);
99
100typedef NTSTATUS (KMT_MESSAGE_HANDLER)(
101 IN PDEVICE_OBJECT DeviceObject,
102 IN ULONG ControlCode,
103 IN PVOID Buffer OPTIONAL,
104 IN SIZE_T InLength,
105 IN OUT PSIZE_T OutLength);
106typedef KMT_MESSAGE_HANDLER *PKMT_MESSAGE_HANDLER;
107
108NTSTATUS KmtRegisterMessageHandler(IN ULONG ControlCode OPTIONAL, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_MESSAGE_HANDLER MessageHandler);
109NTSTATUS KmtUnregisterMessageHandler(IN ULONG ControlCode OPTIONAL, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_MESSAGE_HANDLER MessageHandler);
110
111typedef enum
112{
113 TESTENTRY_NO_CREATE_DEVICE = 1,
114 TESTENTRY_NO_REGISTER_DISPATCH = 2,
115 TESTENTRY_NO_REGISTER_UNLOAD = 4,
116 TESTENTRY_NO_EXCLUSIVE_DEVICE = 8,
117 TESTENTRY_NO_READONLY_DEVICE = 16,
118 TESTENTRY_BUFFERED_IO_DEVICE = 32,
119} KMT_TESTENTRY_FLAGS;
120
121NTSTATUS TestEntry(IN PDRIVER_OBJECT DriverObject, IN PCUNICODE_STRING RegistryPath, OUT PCWSTR *DeviceName, IN OUT INT *Flags);
122VOID TestUnload(IN PDRIVER_OBJECT DriverObject);
123#endif /* defined KMT_STANDALONE_DRIVER */
124
125#ifdef KMT_FILTER_DRIVER
126#ifndef KMT_KERNEL_MODE
127#define KMT_KERNEL_MODE
128#endif
129
130NTSTATUS KmtFilterRegisterCallbacks(_In_ CONST FLT_OPERATION_REGISTRATION *OperationRegistration);
131
132typedef enum
133{
134 TESTENTRY_NO_REGISTER_FILTER = 0x01,
135 TESTENTRY_NO_CREATE_COMMS_PORT = 0x02,
136 TESTENTRY_NO_START_FILTERING = 0x04,
137 TESTENTRY_NO_INSTANCE_SETUP = 0x08,
138 TESTENTRY_NO_QUERY_TEARDOWN = 0x10,
139 TESTENTRY_NO_ALL = 0xFF
140} KMT_MINIFILTER_FLAGS;
141
142VOID TestFilterUnload(_In_ ULONG Flags);
143NTSTATUS TestInstanceSetup(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_SETUP_FLAGS Flags, _In_ DEVICE_TYPE VolumeDeviceType, _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType, _In_ PUNICODE_STRING VolumeName, _In_ ULONG RealSectorSize, _In_ ULONG SectorSize);
144VOID TestQueryTeardown(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags);
145
146NTSTATUS KmtFilterRegisterComms(_In_ PFLT_CONNECT_NOTIFY ConnectNotifyCallback, _In_ PFLT_DISCONNECT_NOTIFY DisconnectNotifyCallback, _In_opt_ PFLT_MESSAGE_NOTIFY MessageNotifyCallback, _In_ LONG MaxClientConnections);
147
148#endif/* defined KMT_FILTER_DRIVER */
149
150
151#ifdef KMT_KERNEL_MODE
152/* Device Extension layout */
153typedef struct
154{
155 PKMT_RESULTBUFFER ResultBuffer;
156 PMDL Mdl;
157} KMT_DEVICE_EXTENSION, *PKMT_DEVICE_EXTENSION;
158
159extern BOOLEAN KmtIsCheckedBuild;
160extern BOOLEAN KmtIsMultiProcessorBuild;
161extern BOOLEAN KmtIsVirtualMachine;
162extern PCSTR KmtMajorFunctionNames[];
163extern PDRIVER_OBJECT KmtDriverObject;
164
165VOID KmtSetIrql(IN KIRQL NewIrql);
166BOOLEAN KmtAreInterruptsEnabled(VOID);
167ULONG KmtGetPoolTag(PVOID Memory);
168USHORT KmtGetPoolType(PVOID Memory);
169PVOID KmtGetSystemRoutineAddress(IN PCWSTR RoutineName);
170PKTHREAD KmtStartThread(IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext OPTIONAL);
171VOID KmtFinishThread(IN PKTHREAD Thread OPTIONAL, IN PKEVENT Event OPTIONAL);
172#elif defined KMT_USER_MODE
173DWORD KmtRunKernelTest(IN PCSTR TestName);
174
175DWORD KmtLoadDriver(IN PCWSTR ServiceName, IN BOOLEAN RestartIfRunning);
176VOID KmtUnloadDriverKeepService(VOID);
177VOID KmtUnloadDriver(VOID);
178DWORD KmtOpenDriver(VOID);
179VOID KmtCloseDriver(VOID);
180DWORD KmtLoadAndOpenDriver(IN PCWSTR ServiceName, IN BOOLEAN RestartIfRunning);
181
182DWORD KmtSendToDriver(IN DWORD ControlCode);
183DWORD KmtSendStringToDriver(IN DWORD ControlCode, IN PCSTR String);
184DWORD KmtSendWStringToDriver(IN DWORD ControlCode, IN PCWSTR String);
185DWORD KmtSendUlongToDriver(IN DWORD ControlCode, IN DWORD Value);
186DWORD KmtSendBufferToDriver(IN DWORD ControlCode, IN OUT PVOID Buffer OPTIONAL, IN DWORD InLength, IN OUT PDWORD OutLength);
187
188
189DWORD KmtFltCreateService(_In_z_ PCWSTR ServiceName, _In_z_ PCWSTR DisplayName, _Out_ SC_HANDLE *ServiceHandle);
190DWORD KmtFltDeleteService(_In_opt_z_ PCWSTR ServiceName, _Inout_ SC_HANDLE *ServiceHandle);
191DWORD KmtFltAddAltitude(_In_z_ LPWSTR Altitude);
192DWORD KmtFltLoadDriver(_In_ BOOLEAN EnableDriverLoadPrivilege, _In_ BOOLEAN RestartIfRunning, _In_ BOOLEAN ConnectComms, _Out_ HANDLE *hPort);
193DWORD KmtFltUnloadDriver(_In_ HANDLE *hPort, _In_ BOOLEAN DisonnectComms);
194DWORD KmtFltConnectComms(_Out_ HANDLE *hPort);
195DWORD KmtFltDisconnectComms(_In_ HANDLE hPort);
196DWORD KmtFltRunKernelTest(_In_ HANDLE hPort, _In_z_ PCSTR TestName);
197DWORD KmtFltSendToDriver(_In_ HANDLE hPort, _In_ DWORD Message);
198DWORD KmtFltSendStringToDriver(_In_ HANDLE hPort, _In_ DWORD Message, _In_ PCSTR String);
199DWORD KmtFltSendWStringToDriver(_In_ HANDLE hPort, _In_ DWORD Message, _In_ PCWSTR String);
200DWORD KmtFltSendUlongToDriver(_In_ HANDLE hPort, _In_ DWORD Message, _In_ DWORD Value);
201DWORD KmtFltSendBufferToDriver(_In_ HANDLE hPort, _In_ DWORD Message, _In_reads_bytes_(BufferSize) LPVOID Buffer, _In_ DWORD BufferSize, _Out_writes_bytes_to_opt_(dwOutBufferSize, *lpBytesReturned) LPVOID lpOutBuffer, _In_ DWORD dwOutBufferSize, _Out_opt_ LPDWORD lpBytesReturned);
202
203#else /* if !defined KMT_KERNEL_MODE && !defined KMT_USER_MODE */
204#error either KMT_KERNEL_MODE or KMT_USER_MODE must be defined
205#endif /* !defined KMT_KERNEL_MODE && !defined KMT_USER_MODE */
206
207extern PKMT_RESULTBUFFER ResultBuffer;
208
209#ifdef __GNUC__
210/* TODO: GCC doesn't understand %wZ :( */
211#define KMT_FORMAT(type, fmt, first) /*__attribute__((__format__(type, fmt, first)))*/
212#elif !defined __GNUC__
213#define KMT_FORMAT(type, fmt, first)
214#endif /* !defined __GNUC__ */
215
216#define START_TEST(name) VOID Test_##name(VOID)
217
218#ifndef KMT_STRINGIZE
219#define KMT_STRINGIZE(x) #x
220#endif /* !defined KMT_STRINGIZE */
221#define ok(test, ...) ok_(test, __FILE__, __LINE__, __VA_ARGS__)
222#define trace(...) trace_( __FILE__, __LINE__, __VA_ARGS__)
223#define skip(test, ...) skip_(test, __FILE__, __LINE__, __VA_ARGS__)
224
225#define ok_(test, file, line, ...) KmtOk(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
226#define trace_(file, line, ...) KmtTrace( file ":" KMT_STRINGIZE(line), __VA_ARGS__)
227#define skip_(test, file, line, ...) KmtSkip(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
228
229BOOLEAN KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
230BOOLEAN KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 3, 4);
231VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 2, 0);
232VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 2, 3);
233BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
234BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 3, 4);
235PVOID KmtAllocateGuarded(SIZE_T SizeRequested);
236VOID KmtFreeGuarded(PVOID Pointer);
237
238#ifdef KMT_KERNEL_MODE
239#define ok_irql(irql) ok(KeGetCurrentIrql() == irql, "IRQL is %d, expected %d\n", KeGetCurrentIrql(), irql)
240#endif /* defined KMT_KERNEL_MODE */
241#define ok_eq_print(value, expected, spec) ok((value) == (expected), #value " = " spec ", expected " spec "\n", value, expected)
242#define ok_eq_pointer(value, expected) ok_eq_print(value, expected, "%p")
243#define ok_eq_int(value, expected) ok_eq_print(value, expected, "%d")
244#define ok_eq_uint(value, expected) ok_eq_print(value, expected, "%u")
245#define ok_eq_long(value, expected) ok_eq_print(value, expected, "%ld")
246#define ok_eq_ulong(value, expected) ok_eq_print(value, expected, "%lu")
247#define ok_eq_longlong(value, expected) ok_eq_print(value, expected, "%I64d")
248#define ok_eq_ulonglong(value, expected) ok_eq_print(value, expected, "%I64u")
249#define ok_eq_char(value, expected) ok_eq_print(value, expected, "%c")
250#define ok_eq_wchar(value, expected) ok_eq_print(value, expected, "%C")
251#ifndef _WIN64
252#define ok_eq_size(value, expected) ok_eq_print(value, (SIZE_T)(expected), "%lu")
253#define ok_eq_longptr(value, expected) ok_eq_print(value, (LONG_PTR)(expected), "%ld")
254#define ok_eq_ulongptr(value, expected) ok_eq_print(value, (ULONG_PTR)(expected), "%lu")
255#elif defined _WIN64
256#define ok_eq_size(value, expected) ok_eq_print(value, (SIZE_T)(expected), "%I64u")
257#define ok_eq_longptr(value, expected) ok_eq_print(value, (LONG_PTR)(expected), "%I64d")
258#define ok_eq_ulongptr(value, expected) ok_eq_print(value, (ULONG_PTR)(expected), "%I64u")
259#endif /* defined _WIN64 */
260#define ok_eq_hex(value, expected) ok_eq_print(value, expected, "0x%08lx")
261#define ok_bool_true(value, desc) ok((value) == TRUE, desc " FALSE, expected TRUE\n")
262#define ok_bool_false(value, desc) ok((value) == FALSE, desc " TRUE, expected FALSE\n")
263#define ok_eq_bool(value, expected) ok((value) == (expected), #value " = %s, expected %s\n", \
264 (value) ? "TRUE" : "FALSE", \
265 (expected) ? "TRUE" : "FALSE")
266#define ok_eq_str(value, expected) ok(!strcmp(value, expected), #value " = \"%s\", expected \"%s\"\n", value, expected)
267#define ok_eq_wstr(value, expected) ok(!wcscmp(value, expected), #value " = \"%ls\", expected \"%ls\"\n", value, expected)
268#define ok_eq_tag(value, expected) ok_eq_print(value, expected, "0x%08lx")
269
270#define ok_eq_hex64(value, expected) ok_eq_print(value, expected, "%I64x")
271#define ok_eq_xmm(value, expected) ok((value).Low == (expected).Low, #value " = %I64x'%08I64x, expected %I64x'%08I64x\n", (value).Low, (value).High, (expected).Low, (expected).High)
272
273#define KMT_MAKE_CODE(ControlCode) CTL_CODE(FILE_DEVICE_UNKNOWN, \
274 0xC00 + (ControlCode), \
275 METHOD_BUFFERED, \
276 FILE_ANY_ACCESS)
277
278#define MICROSECOND 10
279#define MILLISECOND (1000 * MICROSECOND)
280#define SECOND (1000 * MILLISECOND)
281
282/* See apitests/include/apitest.h */
283#define KmtInvalidPointer ((PVOID)0x5555555555555555ULL)
284
285#define KmtStartSeh() \
286{ \
287 NTSTATUS ExceptionStatus = STATUS_SUCCESS; \
288 _SEH2_TRY \
289 {
290
291#define KmtEndSeh(ExpectedStatus) \
292 } \
293 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) \
294 { \
295 ExceptionStatus = _SEH2_GetExceptionCode(); \
296 } \
297 _SEH2_END; \
298 ok_eq_hex(ExceptionStatus, (ExpectedStatus)); \
299}
300
301#define KmtGetSystemOrEmbeddedRoutineAddress(RoutineName) \
302 p##RoutineName = KmtGetSystemRoutineAddress(L ## #RoutineName); \
303 if (!p##RoutineName) \
304 { \
305 p##RoutineName = RoutineName; \
306 trace("Using embedded routine for " #RoutineName "\n"); \
307 } \
308 else \
309 trace("Using system routine for " #RoutineName "\n");
310
311#if defined KMT_DEFINE_TEST_FUNCTIONS
312
313#if defined KMT_KERNEL_MODE
314#include "kmt_test_kernel.h"
315#elif defined KMT_USER_MODE
316#include "kmt_test_user.h"
317#endif /* defined KMT_USER_MODE */
318
319PKMT_RESULTBUFFER ResultBuffer = NULL;
320
321static VOID KmtAddToLogBuffer(PKMT_RESULTBUFFER Buffer, PCSTR String, SIZE_T Length)
322{
323 LONG OldLength;
324 LONG NewLength;
325
326 if (!Buffer)
327 return;
328
329 do
330 {
331 OldLength = Buffer->LogBufferLength;
332 NewLength = OldLength + (ULONG)Length;
333 if (NewLength > Buffer->LogBufferMaxLength)
334 return;
335 } while (InterlockedCompareExchange(&Buffer->LogBufferLength, NewLength, OldLength) != OldLength);
336
337 memcpy(&Buffer->LogBuffer[OldLength], String, Length);
338}
339
340KMT_FORMAT(ms_printf, 5, 0)
341static SIZE_T KmtXVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, va_list Arguments)
342{
343 SIZE_T BufferLength = 0;
344 SIZE_T Length;
345
346 if (FileAndLine)
347 {
348 PCSTR Slash;
349 Slash = strrchr(FileAndLine, '\\');
350 if (Slash)
351 FileAndLine = Slash + 1;
352 Slash = strrchr(FileAndLine, '/');
353 if (Slash)
354 FileAndLine = Slash + 1;
355
356 Length = min(BufferMaxLength, strlen(FileAndLine));
357 memcpy(Buffer, FileAndLine, Length);
358 Buffer += Length;
359 BufferLength += Length;
360 BufferMaxLength -= Length;
361 }
362 if (Prepend)
363 {
364 Length = min(BufferMaxLength, strlen(Prepend));
365 memcpy(Buffer, Prepend, Length);
366 Buffer += Length;
367 BufferLength += Length;
368 BufferMaxLength -= Length;
369 }
370 if (Format)
371 {
372 Length = KmtVSNPrintF(Buffer, BufferMaxLength, Format, Arguments);
373 /* vsnprintf can return more than maxLength, we don't want to do that */
374 BufferLength += min(Length, BufferMaxLength);
375 }
376 return BufferLength;
377}
378
379KMT_FORMAT(ms_printf, 5, 6)
380static SIZE_T KmtXSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, ...)
381{
382 SIZE_T BufferLength;
383 va_list Arguments;
384 va_start(Arguments, Format);
385 BufferLength = KmtXVSNPrintF(Buffer, BufferMaxLength, FileAndLine, Prepend, Format, Arguments);
386 va_end(Arguments);
387 return BufferLength;
388}
389
390VOID KmtFinishTest(PCSTR TestName)
391{
392 CHAR MessageBuffer[512];
393 SIZE_T MessageLength;
394
395 if (!ResultBuffer)
396 return;
397
398 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, NULL, NULL,
399 "%s: %ld tests executed (0 marked as todo, %ld failures), %ld skipped.\n",
400 TestName,
401 ResultBuffer->Successes + ResultBuffer->Failures,
402 ResultBuffer->Failures,
403 ResultBuffer->Skipped);
404 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
405}
406
407BOOLEAN KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
408{
409 CHAR MessageBuffer[512];
410 SIZE_T MessageLength;
411
412 if (!ResultBuffer)
413 return Condition != 0;
414
415 if (Condition)
416 {
417 InterlockedIncrement(&ResultBuffer->Successes);
418
419 if (0/*KmtReportSuccess*/)
420 {
421 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test succeeded\n", NULL);
422 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
423 }
424 }
425 else
426 {
427 InterlockedIncrement(&ResultBuffer->Failures);
428 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test failed: ", Format, Arguments);
429 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
430 }
431
432 return Condition != 0;
433}
434
435BOOLEAN KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
436{
437 BOOLEAN Ret;
438 va_list Arguments;
439 va_start(Arguments, Format);
440 Ret = KmtVOk(Condition, FileAndLine, Format, Arguments);
441 va_end(Arguments);
442 return Ret;
443}
444
445VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments)
446{
447 CHAR MessageBuffer[512];
448 SIZE_T MessageLength;
449
450 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": ", Format, Arguments);
451 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
452}
453
454VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...)
455{
456 va_list Arguments;
457 va_start(Arguments, Format);
458 KmtVTrace(FileAndLine, Format, Arguments);
459 va_end(Arguments);
460}
461
462BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
463{
464 CHAR MessageBuffer[512];
465 SIZE_T MessageLength;
466
467 if (!ResultBuffer)
468 return !Condition;
469
470 if (!Condition)
471 {
472 InterlockedIncrement(&ResultBuffer->Skipped);
473 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Tests skipped: ", Format, Arguments);
474 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
475 }
476
477 return !Condition;
478}
479
480BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
481{
482 BOOLEAN Ret;
483 va_list Arguments;
484 va_start(Arguments, Format);
485 Ret = KmtVSkip(Condition, FileAndLine, Format, Arguments);
486 va_end(Arguments);
487 return Ret;
488}
489
490PVOID KmtAllocateGuarded(SIZE_T SizeRequested)
491{
492 NTSTATUS Status;
493 SIZE_T Size = PAGE_ROUND_UP(SizeRequested + PAGE_SIZE);
494 PVOID VirtualMemory = NULL;
495 PCHAR StartOfBuffer;
496
497 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory, 0, &Size, MEM_RESERVE, PAGE_NOACCESS);
498
499 if (!NT_SUCCESS(Status))
500 return NULL;
501
502 Size -= PAGE_SIZE;
503 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory, 0, &Size, MEM_COMMIT, PAGE_READWRITE);
504 if (!NT_SUCCESS(Status))
505 {
506 Size = 0;
507 Status = ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
508 ok_eq_hex(Status, STATUS_SUCCESS);
509 return NULL;
510 }
511
512 StartOfBuffer = VirtualMemory;
513 StartOfBuffer += Size - SizeRequested;
514
515 return StartOfBuffer;
516}
517
518VOID KmtFreeGuarded(PVOID Pointer)
519{
520 NTSTATUS Status;
521 PVOID VirtualMemory = (PVOID)PAGE_ROUND_DOWN((SIZE_T)Pointer);
522 SIZE_T Size = 0;
523
524 Status = ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
525 ok_eq_hex(Status, STATUS_SUCCESS);
526}
527
528#endif /* defined KMT_DEFINE_TEST_FUNCTIONS */
529
530#endif /* !defined _KMTEST_TEST_H_ */