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