[KMTESTS]
[reactos.git] / rostests / kmtests / include / kmt_test.h
1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite test framework declarations
5 * PROGRAMMER: Thomas Faber <thfabba@gmx.de>
6 */
7
8 /* Inspired by Wine C unit tests, Copyright (C) 2002 Alexandre Julliard
9 * Inspired by ReactOS kernel-mode regression tests,
10 * Copyright (C) Aleksey Bragin, Filip Navara
11 */
12
13 #ifndef _KMTEST_TEST_H_
14 #define _KMTEST_TEST_H_
15
16 #include <kmt_platform.h>
17
18 typedef VOID KMT_TESTFUNC(VOID);
19 typedef KMT_TESTFUNC *PKMT_TESTFUNC;
20
21 typedef struct
22 {
23 const char *TestName;
24 KMT_TESTFUNC *TestFunction;
25 } KMT_TEST, *PKMT_TEST;
26
27 typedef const KMT_TEST CKMT_TEST, *PCKMT_TEST;
28
29 extern const KMT_TEST TestList[];
30
31 typedef struct
32 {
33 volatile LONG Successes;
34 volatile LONG Failures;
35 volatile LONG Skipped;
36 volatile LONG LogBufferLength;
37 LONG LogBufferMaxLength;
38 CHAR LogBuffer[ANYSIZE_ARRAY];
39 } KMT_RESULTBUFFER, *PKMT_RESULTBUFFER;
40
41 #ifndef KMT_STANDALONE_DRIVER
42
43 /* usermode call-back mechanism */
44
45 /* list of supported operations */
46 typedef enum _KMT_CALLBACK_INFORMATION_CLASS
47 {
48 QueryVirtualMemory
49 } KMT_CALLBACK_INFORMATION_CLASS, *PKMT_CALLBACK_INFORMATION_CLASS;
50
51 /* TODO: "response" is a little generic */
52 typedef union _KMT_RESPONSE
53 {
54 MEMORY_BASIC_INFORMATION MemInfo;
55 } KMT_RESPONSE, *PKMT_RESPONSE;
56
57 /* this struct is sent from driver to usermode */
58 typedef struct _KMT_CALLBACK_REQUEST_PACKET
59 {
60 ULONG RequestId;
61 KMT_CALLBACK_INFORMATION_CLASS OperationClass;
62 PVOID Parameters;
63 } KMT_CALLBACK_REQUEST_PACKET, *PKMT_CALLBACK_REQUEST_PACKET;
64
65 PKMT_RESPONSE KmtUserModeCallback(KMT_CALLBACK_INFORMATION_CLASS Operation, PVOID Parameters);
66 VOID KmtFreeCallbackResponse(PKMT_RESPONSE Response);
67
68 //macro to simplify using the mechanism
69 #define Test_NtQueryVirtualMemory(BaseAddress, Size, AllocationType, ProtectionType) \
70 do { \
71 PKMT_RESPONSE NtQueryTest = KmtUserModeCallback(QueryVirtualMemory, BaseAddress); \
72 if (NtQueryTest != NULL) \
73 { \
74 ok_eq_hex(NtQueryTest->MemInfo.Protect, ProtectionType); \
75 ok_eq_hex(NtQueryTest->MemInfo.State, AllocationType); \
76 ok_eq_size(NtQueryTest->MemInfo.RegionSize, Size); \
77 KmtFreeCallbackResponse(NtQueryTest); \
78 } \
79 } while (0) \
80
81 #endif
82
83 #ifdef KMT_STANDALONE_DRIVER
84 #define KMT_KERNEL_MODE
85
86 typedef NTSTATUS (KMT_IRP_HANDLER)(
87 IN PDEVICE_OBJECT DeviceObject,
88 IN PIRP Irp,
89 IN PIO_STACK_LOCATION IoStackLocation);
90 typedef KMT_IRP_HANDLER *PKMT_IRP_HANDLER;
91
92 NTSTATUS KmtRegisterIrpHandler(IN UCHAR MajorFunction, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_IRP_HANDLER IrpHandler);
93 NTSTATUS KmtUnregisterIrpHandler(IN UCHAR MajorFunction, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_IRP_HANDLER IrpHandler);
94
95 typedef NTSTATUS (KMT_MESSAGE_HANDLER)(
96 IN PDEVICE_OBJECT DeviceObject,
97 IN ULONG ControlCode,
98 IN PVOID Buffer OPTIONAL,
99 IN SIZE_T InLength,
100 IN OUT PSIZE_T OutLength);
101 typedef KMT_MESSAGE_HANDLER *PKMT_MESSAGE_HANDLER;
102
103 NTSTATUS KmtRegisterMessageHandler(IN ULONG ControlCode OPTIONAL, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_MESSAGE_HANDLER MessageHandler);
104 NTSTATUS KmtUnregisterMessageHandler(IN ULONG ControlCode OPTIONAL, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_MESSAGE_HANDLER MessageHandler);
105
106 typedef enum
107 {
108 TESTENTRY_NO_CREATE_DEVICE = 1,
109 TESTENTRY_NO_REGISTER_DISPATCH = 2,
110 TESTENTRY_NO_REGISTER_UNLOAD = 4,
111 TESTENTRY_NO_EXCLUSIVE_DEVICE = 8,
112 } KMT_TESTENTRY_FLAGS;
113
114 NTSTATUS TestEntry(IN PDRIVER_OBJECT DriverObject, IN PCUNICODE_STRING RegistryPath, OUT PCWSTR *DeviceName, IN OUT INT *Flags);
115 VOID TestUnload(IN PDRIVER_OBJECT DriverObject);
116 #endif /* defined KMT_STANDALONE_DRIVER */
117
118 #ifdef KMT_KERNEL_MODE
119 /* Device Extension layout */
120 typedef struct
121 {
122 PKMT_RESULTBUFFER ResultBuffer;
123 PMDL Mdl;
124 } KMT_DEVICE_EXTENSION, *PKMT_DEVICE_EXTENSION;
125
126 extern BOOLEAN KmtIsCheckedBuild;
127 extern BOOLEAN KmtIsMultiProcessorBuild;
128 extern PCSTR KmtMajorFunctionNames[];
129 extern PDRIVER_OBJECT KmtDriverObject;
130
131 VOID KmtSetIrql(IN KIRQL NewIrql);
132 BOOLEAN KmtAreInterruptsEnabled(VOID);
133 ULONG KmtGetPoolTag(PVOID Memory);
134 #elif defined KMT_USER_MODE
135 DWORD KmtRunKernelTest(IN PCSTR TestName);
136
137 VOID KmtLoadDriver(IN PCWSTR ServiceName, IN BOOLEAN RestartIfRunning);
138 VOID KmtUnloadDriver(VOID);
139 VOID KmtOpenDriver(VOID);
140 VOID KmtCloseDriver(VOID);
141
142 DWORD KmtSendToDriver(IN DWORD ControlCode);
143 DWORD KmtSendStringToDriver(IN DWORD ControlCode, IN PCSTR String);
144 DWORD KmtSendWStringToDriver(IN DWORD ControlCode, IN PCWSTR String);
145 DWORD KmtSendBufferToDriver(IN DWORD ControlCode, IN OUT PVOID Buffer OPTIONAL, IN DWORD InLength, IN OUT PDWORD OutLength);
146 #else /* if !defined KMT_KERNEL_MODE && !defined KMT_USER_MODE */
147 #error either KMT_KERNEL_MODE or KMT_USER_MODE must be defined
148 #endif /* !defined KMT_KERNEL_MODE && !defined KMT_USER_MODE */
149
150 extern PKMT_RESULTBUFFER ResultBuffer;
151
152 #ifdef __GNUC__
153 /* TODO: GCC doesn't understand %wZ :( */
154 #define KMT_FORMAT(type, fmt, first) /*__attribute__((__format__(type, fmt, first)))*/
155 #elif !defined __GNUC__
156 #define KMT_FORMAT(type, fmt, first)
157 #endif /* !defined __GNUC__ */
158
159 #define START_TEST(name) VOID Test_##name(VOID)
160
161 #ifndef KMT_STRINGIZE
162 #define KMT_STRINGIZE(x) #x
163 #endif /* !defined KMT_STRINGIZE */
164 #define ok(test, ...) ok_(test, __FILE__, __LINE__, __VA_ARGS__)
165 #define trace(...) trace_( __FILE__, __LINE__, __VA_ARGS__)
166 #define skip(test, ...) skip_(test, __FILE__, __LINE__, __VA_ARGS__)
167
168 #define ok_(test, file, line, ...) KmtOk(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
169 #define trace_(file, line, ...) KmtTrace( file ":" KMT_STRINGIZE(line), __VA_ARGS__)
170 #define skip_(test, file, line, ...) KmtSkip(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
171
172 BOOLEAN KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
173 BOOLEAN KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 3, 4);
174 VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 2, 0);
175 VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 2, 3);
176 BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
177 BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 3, 4);
178 PVOID KmtAllocateGuarded(SIZE_T SizeRequested);
179 VOID KmtFreeGuarded(PVOID Pointer);
180
181 #ifdef KMT_KERNEL_MODE
182 #define ok_irql(irql) ok(KeGetCurrentIrql() == irql, "IRQL is %d, expected %d\n", KeGetCurrentIrql(), irql)
183 #endif /* defined KMT_KERNEL_MODE */
184 #define ok_eq_print(value, expected, spec) ok((value) == (expected), #value " = " spec ", expected " spec "\n", value, expected)
185 #define ok_eq_pointer(value, expected) ok_eq_print(value, expected, "%p")
186 #define ok_eq_int(value, expected) ok_eq_print(value, expected, "%d")
187 #define ok_eq_uint(value, expected) ok_eq_print(value, expected, "%u")
188 #define ok_eq_long(value, expected) ok_eq_print(value, expected, "%ld")
189 #define ok_eq_ulong(value, expected) ok_eq_print(value, expected, "%lu")
190 #define ok_eq_longlong(value, expected) ok_eq_print(value, expected, "%I64d")
191 #define ok_eq_ulonglong(value, expected) ok_eq_print(value, expected, "%I64u")
192 #ifndef _WIN64
193 #define ok_eq_size(value, expected) ok_eq_print(value, (SIZE_T)(expected), "%lu")
194 #define ok_eq_longptr(value, expected) ok_eq_print(value, (LONG_PTR)(expected), "%ld")
195 #define ok_eq_ulongptr(value, expected) ok_eq_print(value, (ULONG_PTR)(expected), "%lu")
196 #elif defined _WIN64
197 #define ok_eq_size(value, expected) ok_eq_print(value, (SIZE_T)(expected), "%I64u")
198 #define ok_eq_longptr(value, expected) ok_eq_print(value, (LONG_PTR)(expected), "%I64d")
199 #define ok_eq_ulongptr(value, expected) ok_eq_print(value, (ULONG_PTR)(expected), "%I64u")
200 #endif /* defined _WIN64 */
201 #define ok_eq_hex(value, expected) ok_eq_print(value, expected, "0x%08lx")
202 #define ok_bool_true(value, desc) ok((value) == TRUE, desc " FALSE, expected TRUE\n")
203 #define ok_bool_false(value, desc) ok((value) == FALSE, desc " TRUE, expected FALSE\n")
204 #define ok_eq_bool(value, expected) ok((value) == (expected), #value " = %s, expected %s\n", \
205 (value) ? "TRUE" : "FALSE", \
206 (expected) ? "TRUE" : "FALSE")
207 #define ok_eq_str(value, expected) ok(!strcmp(value, expected), #value " = \"%s\", expected \"%s\"\n", value, expected)
208 #define ok_eq_wstr(value, expected) ok(!wcscmp(value, expected), #value " = \"%ls\", expected \"%ls\"\n", value, expected)
209 #define ok_eq_tag(value, expected) ok_eq_print(value, expected, "0x%08lx")
210
211 #define KMT_MAKE_CODE(ControlCode) CTL_CODE(FILE_DEVICE_UNKNOWN, \
212 0xC00 + (ControlCode), \
213 METHOD_BUFFERED, \
214 FILE_ANY_ACCESS)
215
216 #define MICROSECOND 10
217 #define MILLISECOND (1000 * MICROSECOND)
218 #define SECOND (1000 * MILLISECOND)
219
220 #define KmtInvalidPointer ((PVOID)0x5555555555555555ULL)
221
222 #define KmtStartSeh() \
223 ExceptionStatus = STATUS_SUCCESS; \
224 _SEH2_TRY \
225 {
226 #define KmtEndSeh(ExpectedStatus) \
227 } \
228 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) \
229 { \
230 ExceptionStatus = _SEH2_GetExceptionCode(); \
231 } _SEH2_END; \
232 ok_eq_hex(ExceptionStatus, ExpectedStatus)
233
234 #if defined KMT_DEFINE_TEST_FUNCTIONS
235
236 #if defined KMT_KERNEL_MODE
237 BOOLEAN KmtIsCheckedBuild;
238 BOOLEAN KmtIsMultiProcessorBuild;
239 PCSTR KmtMajorFunctionNames[] =
240 {
241 "Create",
242 "CreateNamedPipe",
243 "Close",
244 "Read",
245 "Write",
246 "QueryInformation",
247 "SetInformation",
248 "QueryEa",
249 "SetEa",
250 "FlushBuffers",
251 "QueryVolumeInformation",
252 "SetVolumeInformation",
253 "DirectoryControl",
254 "FileSystemControl",
255 "DeviceControl",
256 "InternalDeviceControl/Scsi",
257 "Shutdown",
258 "LockControl",
259 "Cleanup",
260 "CreateMailslot",
261 "QuerySecurity",
262 "SetSecurity",
263 "Power",
264 "SystemControl",
265 "DeviceChange",
266 "QueryQuota",
267 "SetQuota",
268 "Pnp/PnpPower"
269 };
270
271 VOID KmtSetIrql(IN KIRQL NewIrql)
272 {
273 KIRQL Irql = KeGetCurrentIrql();
274 if (Irql > NewIrql)
275 KeLowerIrql(NewIrql);
276 else if (Irql < NewIrql)
277 KeRaiseIrql(NewIrql, &Irql);
278 }
279
280 BOOLEAN KmtAreInterruptsEnabled(VOID)
281 {
282 return (__readeflags() & (1 << 9)) != 0;
283 }
284
285 typedef struct _POOL_HEADER
286 {
287 union
288 {
289 struct
290 {
291 #ifdef _M_AMD64
292 USHORT PreviousSize:8;
293 USHORT PoolIndex:8;
294 USHORT BlockSize:8;
295 USHORT PoolType:8;
296 #else
297 USHORT PreviousSize:9;
298 USHORT PoolIndex:7;
299 USHORT BlockSize:9;
300 USHORT PoolType:7;
301 #endif
302 };
303 ULONG Ulong1;
304 };
305 #ifdef _M_AMD64
306 ULONG PoolTag;
307 #endif
308 union
309 {
310 #ifdef _M_AMD64
311 PEPROCESS ProcessBilled;
312 #else
313 ULONG PoolTag;
314 #endif
315 struct
316 {
317 USHORT AllocatorBackTraceIndex;
318 USHORT PoolTagHash;
319 };
320 };
321 } POOL_HEADER, *PPOOL_HEADER;
322
323 ULONG KmtGetPoolTag(PVOID Memory)
324 {
325 PPOOL_HEADER Header;
326
327 /* it's not so easy for allocations of PAGE_SIZE */
328 if (((ULONG_PTR)Memory & (PAGE_SIZE - 1)) == 0)
329 return 'TooL';
330
331 Header = Memory;
332 Header--;
333
334 return Header->PoolTag;
335 }
336
337 INT __cdecl KmtVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
338 #elif defined KMT_USER_MODE
339 static PKMT_RESULTBUFFER KmtAllocateResultBuffer(SIZE_T ResultBufferSize)
340 {
341 PKMT_RESULTBUFFER Buffer = HeapAlloc(GetProcessHeap(), 0, ResultBufferSize);
342 if (!Buffer)
343 return NULL;
344
345 Buffer->Successes = 0;
346 Buffer->Failures = 0;
347 Buffer->Skipped = 0;
348 Buffer->LogBufferLength = 0;
349 Buffer->LogBufferMaxLength = (ULONG)ResultBufferSize - FIELD_OFFSET(KMT_RESULTBUFFER, LogBuffer);
350
351 return Buffer;
352 }
353
354 static VOID KmtFreeResultBuffer(PKMT_RESULTBUFFER Buffer)
355 {
356 HeapFree(GetProcessHeap(), 0, Buffer);
357 }
358
359 #define KmtVSNPrintF vsnprintf
360 #endif /* defined KMT_USER_MODE */
361
362 PKMT_RESULTBUFFER ResultBuffer = NULL;
363
364 static VOID KmtAddToLogBuffer(PKMT_RESULTBUFFER Buffer, PCSTR String, SIZE_T Length)
365 {
366 LONG OldLength;
367 LONG NewLength;
368
369 if (!Buffer)
370 return;
371
372 do
373 {
374 OldLength = Buffer->LogBufferLength;
375 NewLength = OldLength + (ULONG)Length;
376 if (NewLength > Buffer->LogBufferMaxLength)
377 return;
378 } while (InterlockedCompareExchange(&Buffer->LogBufferLength, NewLength, OldLength) != OldLength);
379
380 memcpy(&Buffer->LogBuffer[OldLength], String, Length);
381 }
382
383 KMT_FORMAT(ms_printf, 5, 0)
384 static SIZE_T KmtXVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, va_list Arguments)
385 {
386 SIZE_T BufferLength = 0;
387 SIZE_T Length;
388
389 if (FileAndLine)
390 {
391 PCSTR Slash;
392 Slash = strrchr(FileAndLine, '\\');
393 if (Slash)
394 FileAndLine = Slash + 1;
395 Slash = strrchr(FileAndLine, '/');
396 if (Slash)
397 FileAndLine = Slash + 1;
398
399 Length = min(BufferMaxLength, strlen(FileAndLine));
400 memcpy(Buffer, FileAndLine, Length);
401 Buffer += Length;
402 BufferLength += Length;
403 BufferMaxLength -= Length;
404 }
405 if (Prepend)
406 {
407 Length = min(BufferMaxLength, strlen(Prepend));
408 memcpy(Buffer, Prepend, Length);
409 Buffer += Length;
410 BufferLength += Length;
411 BufferMaxLength -= Length;
412 }
413 if (Format)
414 {
415 Length = KmtVSNPrintF(Buffer, BufferMaxLength, Format, Arguments);
416 /* vsnprintf can return more than maxLength, we don't want to do that */
417 BufferLength += min(Length, BufferMaxLength);
418 }
419 return BufferLength;
420 }
421
422 KMT_FORMAT(ms_printf, 5, 6)
423 static SIZE_T KmtXSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, ...)
424 {
425 SIZE_T BufferLength;
426 va_list Arguments;
427 va_start(Arguments, Format);
428 BufferLength = KmtXVSNPrintF(Buffer, BufferMaxLength, FileAndLine, Prepend, Format, Arguments);
429 va_end(Arguments);
430 return BufferLength;
431 }
432
433 VOID KmtFinishTest(PCSTR TestName)
434 {
435 CHAR MessageBuffer[512];
436 SIZE_T MessageLength;
437
438 if (!ResultBuffer)
439 return;
440
441 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, NULL, NULL,
442 "%s: %ld tests executed (0 marked as todo, %ld failures), %ld skipped.\n",
443 TestName,
444 ResultBuffer->Successes + ResultBuffer->Failures,
445 ResultBuffer->Failures,
446 ResultBuffer->Skipped);
447 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
448 }
449
450 BOOLEAN KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
451 {
452 CHAR MessageBuffer[512];
453 SIZE_T MessageLength;
454
455 if (!ResultBuffer)
456 return Condition != 0;
457
458 if (Condition)
459 {
460 InterlockedIncrement(&ResultBuffer->Successes);
461
462 if (0/*KmtReportSuccess*/)
463 {
464 MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test succeeded\n", NULL);
465 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
466 }
467 }
468 else
469 {
470 InterlockedIncrement(&ResultBuffer->Failures);
471 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test failed: ", Format, Arguments);
472 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
473 }
474
475 return Condition != 0;
476 }
477
478 BOOLEAN KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
479 {
480 BOOLEAN Ret;
481 va_list Arguments;
482 va_start(Arguments, Format);
483 Ret = KmtVOk(Condition, FileAndLine, Format, Arguments);
484 va_end(Arguments);
485 return Ret;
486 }
487
488 VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments)
489 {
490 CHAR MessageBuffer[512];
491 SIZE_T MessageLength;
492
493 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": ", Format, Arguments);
494 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
495 }
496
497 VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...)
498 {
499 va_list Arguments;
500 va_start(Arguments, Format);
501 KmtVTrace(FileAndLine, Format, Arguments);
502 va_end(Arguments);
503 }
504
505 BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
506 {
507 CHAR MessageBuffer[512];
508 SIZE_T MessageLength;
509
510 if (!ResultBuffer)
511 return !Condition;
512
513 if (!Condition)
514 {
515 InterlockedIncrement(&ResultBuffer->Skipped);
516 MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Tests skipped: ", Format, Arguments);
517 KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
518 }
519
520 return !Condition;
521 }
522
523 BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
524 {
525 BOOLEAN Ret;
526 va_list Arguments;
527 va_start(Arguments, Format);
528 Ret = KmtVSkip(Condition, FileAndLine, Format, Arguments);
529 va_end(Arguments);
530 return Ret;
531 }
532
533 PVOID KmtAllocateGuarded(SIZE_T SizeRequested)
534 {
535 NTSTATUS Status;
536 SIZE_T Size = PAGE_ROUND_UP(SizeRequested + PAGE_SIZE);
537 PVOID VirtualMemory = NULL;
538 PCHAR StartOfBuffer;
539
540 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory, 0, &Size, MEM_RESERVE, PAGE_NOACCESS);
541
542 if (!NT_SUCCESS(Status))
543 return NULL;
544
545 Size -= PAGE_SIZE;
546 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory, 0, &Size, MEM_COMMIT, PAGE_READWRITE);
547 if (!NT_SUCCESS(Status))
548 {
549 Size = 0;
550 Status = ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
551 ok_eq_hex(Status, STATUS_SUCCESS);
552 return NULL;
553 }
554
555 StartOfBuffer = VirtualMemory;
556 StartOfBuffer += Size - SizeRequested;
557
558 return StartOfBuffer;
559 }
560
561 VOID KmtFreeGuarded(PVOID Pointer)
562 {
563 NTSTATUS Status;
564 PVOID VirtualMemory = (PVOID)PAGE_ROUND_DOWN((SIZE_T)Pointer);
565 SIZE_T Size = 0;
566
567 Status = ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
568 ok_eq_hex(Status, STATUS_SUCCESS);
569 }
570
571 #endif /* defined KMT_DEFINE_TEST_FUNCTIONS */
572
573 #endif /* !defined _KMTEST_TEST_H_ */