mirror of
https://github.com/reactos/reactos.git
synced 2024-11-05 22:26:39 +00:00
ef0b98d6fb
- Define a new macro function KmtGetSystemOrEmbeddedRoutineAddress() which is to be used to get a function address from Mm if it exists system-wide or to fallback to embedded function if it doesn't exist - Use this mechanism to add tests for the newly implemented FsRtlRemoveDotsFromPath() which is Vista+. That allows, with a single build (and thus, same binaries), testing a function in ReactOS and in Windows. svn path=/trunk/; revision=71046
476 lines
18 KiB
C
476 lines
18 KiB
C
/*
|
|
* PROJECT: ReactOS kernel-mode tests
|
|
* LICENSE: GPLv2+ - See COPYING in the top level directory
|
|
* PURPOSE: Kernel-Mode Test Suite test framework declarations
|
|
* PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
|
|
*/
|
|
|
|
/* Inspired by Wine C unit tests, Copyright (C) 2002 Alexandre Julliard
|
|
* Inspired by ReactOS kernel-mode regression tests,
|
|
* Copyright (C) Aleksey Bragin, Filip Navara
|
|
*/
|
|
|
|
#ifndef _KMTEST_TEST_H_
|
|
#define _KMTEST_TEST_H_
|
|
|
|
#include <kmt_platform.h>
|
|
|
|
typedef VOID KMT_TESTFUNC(VOID);
|
|
typedef KMT_TESTFUNC *PKMT_TESTFUNC;
|
|
|
|
typedef struct
|
|
{
|
|
const char *TestName;
|
|
KMT_TESTFUNC *TestFunction;
|
|
} KMT_TEST, *PKMT_TEST;
|
|
|
|
typedef const KMT_TEST CKMT_TEST, *PCKMT_TEST;
|
|
|
|
extern const KMT_TEST TestList[];
|
|
|
|
typedef struct
|
|
{
|
|
volatile LONG Successes;
|
|
volatile LONG Failures;
|
|
volatile LONG Skipped;
|
|
volatile LONG LogBufferLength;
|
|
LONG LogBufferMaxLength;
|
|
CHAR LogBuffer[ANYSIZE_ARRAY];
|
|
} KMT_RESULTBUFFER, *PKMT_RESULTBUFFER;
|
|
|
|
#ifndef KMT_STANDALONE_DRIVER
|
|
|
|
/* usermode call-back mechanism */
|
|
|
|
/* list of supported operations */
|
|
typedef enum _KMT_CALLBACK_INFORMATION_CLASS
|
|
{
|
|
QueryVirtualMemory
|
|
} KMT_CALLBACK_INFORMATION_CLASS, *PKMT_CALLBACK_INFORMATION_CLASS;
|
|
|
|
/* TODO: "response" is a little generic */
|
|
typedef union _KMT_RESPONSE
|
|
{
|
|
MEMORY_BASIC_INFORMATION MemInfo;
|
|
} KMT_RESPONSE, *PKMT_RESPONSE;
|
|
|
|
/* this struct is sent from driver to usermode */
|
|
typedef struct _KMT_CALLBACK_REQUEST_PACKET
|
|
{
|
|
ULONG RequestId;
|
|
KMT_CALLBACK_INFORMATION_CLASS OperationClass;
|
|
PVOID Parameters;
|
|
} KMT_CALLBACK_REQUEST_PACKET, *PKMT_CALLBACK_REQUEST_PACKET;
|
|
|
|
PKMT_RESPONSE KmtUserModeCallback(KMT_CALLBACK_INFORMATION_CLASS Operation, PVOID Parameters);
|
|
VOID KmtFreeCallbackResponse(PKMT_RESPONSE Response);
|
|
|
|
//macro to simplify using the mechanism
|
|
#define Test_NtQueryVirtualMemory(BaseAddress, Size, AllocationType, ProtectionType) \
|
|
do { \
|
|
PKMT_RESPONSE NtQueryTest = KmtUserModeCallback(QueryVirtualMemory, BaseAddress); \
|
|
if (NtQueryTest != NULL) \
|
|
{ \
|
|
ok_eq_hex(NtQueryTest->MemInfo.Protect, ProtectionType); \
|
|
ok_eq_hex(NtQueryTest->MemInfo.State, AllocationType); \
|
|
ok_eq_size(NtQueryTest->MemInfo.RegionSize, Size); \
|
|
KmtFreeCallbackResponse(NtQueryTest); \
|
|
} \
|
|
} while (0) \
|
|
|
|
#endif
|
|
|
|
#ifdef KMT_STANDALONE_DRIVER
|
|
#define KMT_KERNEL_MODE
|
|
|
|
typedef NTSTATUS (KMT_IRP_HANDLER)(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IoStackLocation);
|
|
typedef KMT_IRP_HANDLER *PKMT_IRP_HANDLER;
|
|
|
|
NTSTATUS KmtRegisterIrpHandler(IN UCHAR MajorFunction, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_IRP_HANDLER IrpHandler);
|
|
NTSTATUS KmtUnregisterIrpHandler(IN UCHAR MajorFunction, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_IRP_HANDLER IrpHandler);
|
|
|
|
typedef NTSTATUS (KMT_MESSAGE_HANDLER)(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN ULONG ControlCode,
|
|
IN PVOID Buffer OPTIONAL,
|
|
IN SIZE_T InLength,
|
|
IN OUT PSIZE_T OutLength);
|
|
typedef KMT_MESSAGE_HANDLER *PKMT_MESSAGE_HANDLER;
|
|
|
|
NTSTATUS KmtRegisterMessageHandler(IN ULONG ControlCode OPTIONAL, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_MESSAGE_HANDLER MessageHandler);
|
|
NTSTATUS KmtUnregisterMessageHandler(IN ULONG ControlCode OPTIONAL, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PKMT_MESSAGE_HANDLER MessageHandler);
|
|
|
|
typedef enum
|
|
{
|
|
TESTENTRY_NO_CREATE_DEVICE = 1,
|
|
TESTENTRY_NO_REGISTER_DISPATCH = 2,
|
|
TESTENTRY_NO_REGISTER_UNLOAD = 4,
|
|
TESTENTRY_NO_EXCLUSIVE_DEVICE = 8,
|
|
TESTENTRY_NO_READONLY_DEVICE = 16,
|
|
TESTENTRY_BUFFERED_IO_DEVICE = 32,
|
|
} KMT_TESTENTRY_FLAGS;
|
|
|
|
NTSTATUS TestEntry(IN PDRIVER_OBJECT DriverObject, IN PCUNICODE_STRING RegistryPath, OUT PCWSTR *DeviceName, IN OUT INT *Flags);
|
|
VOID TestUnload(IN PDRIVER_OBJECT DriverObject);
|
|
#endif /* defined KMT_STANDALONE_DRIVER */
|
|
|
|
#ifdef KMT_KERNEL_MODE
|
|
/* Device Extension layout */
|
|
typedef struct
|
|
{
|
|
PKMT_RESULTBUFFER ResultBuffer;
|
|
PMDL Mdl;
|
|
} KMT_DEVICE_EXTENSION, *PKMT_DEVICE_EXTENSION;
|
|
|
|
extern BOOLEAN KmtIsCheckedBuild;
|
|
extern BOOLEAN KmtIsMultiProcessorBuild;
|
|
extern PCSTR KmtMajorFunctionNames[];
|
|
extern PDRIVER_OBJECT KmtDriverObject;
|
|
|
|
VOID KmtSetIrql(IN KIRQL NewIrql);
|
|
BOOLEAN KmtAreInterruptsEnabled(VOID);
|
|
ULONG KmtGetPoolTag(PVOID Memory);
|
|
USHORT KmtGetPoolType(PVOID Memory);
|
|
PVOID KmtGetSystemRoutineAddress(IN PCWSTR RoutineName);
|
|
PKTHREAD KmtStartThread(IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext OPTIONAL);
|
|
VOID KmtFinishThread(IN PKTHREAD Thread OPTIONAL, IN PKEVENT Event OPTIONAL);
|
|
#elif defined KMT_USER_MODE
|
|
DWORD KmtRunKernelTest(IN PCSTR TestName);
|
|
|
|
VOID KmtLoadDriver(IN PCWSTR ServiceName, IN BOOLEAN RestartIfRunning);
|
|
VOID KmtUnloadDriver(VOID);
|
|
VOID KmtOpenDriver(VOID);
|
|
VOID KmtCloseDriver(VOID);
|
|
|
|
DWORD KmtSendToDriver(IN DWORD ControlCode);
|
|
DWORD KmtSendStringToDriver(IN DWORD ControlCode, IN PCSTR String);
|
|
DWORD KmtSendWStringToDriver(IN DWORD ControlCode, IN PCWSTR String);
|
|
DWORD KmtSendBufferToDriver(IN DWORD ControlCode, IN OUT PVOID Buffer OPTIONAL, IN DWORD InLength, IN OUT PDWORD OutLength);
|
|
#else /* if !defined KMT_KERNEL_MODE && !defined KMT_USER_MODE */
|
|
#error either KMT_KERNEL_MODE or KMT_USER_MODE must be defined
|
|
#endif /* !defined KMT_KERNEL_MODE && !defined KMT_USER_MODE */
|
|
|
|
extern PKMT_RESULTBUFFER ResultBuffer;
|
|
|
|
#ifdef __GNUC__
|
|
/* TODO: GCC doesn't understand %wZ :( */
|
|
#define KMT_FORMAT(type, fmt, first) /*__attribute__((__format__(type, fmt, first)))*/
|
|
#elif !defined __GNUC__
|
|
#define KMT_FORMAT(type, fmt, first)
|
|
#endif /* !defined __GNUC__ */
|
|
|
|
#define START_TEST(name) VOID Test_##name(VOID)
|
|
|
|
#ifndef KMT_STRINGIZE
|
|
#define KMT_STRINGIZE(x) #x
|
|
#endif /* !defined KMT_STRINGIZE */
|
|
#define ok(test, ...) ok_(test, __FILE__, __LINE__, __VA_ARGS__)
|
|
#define trace(...) trace_( __FILE__, __LINE__, __VA_ARGS__)
|
|
#define skip(test, ...) skip_(test, __FILE__, __LINE__, __VA_ARGS__)
|
|
|
|
#define ok_(test, file, line, ...) KmtOk(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
|
|
#define trace_(file, line, ...) KmtTrace( file ":" KMT_STRINGIZE(line), __VA_ARGS__)
|
|
#define skip_(test, file, line, ...) KmtSkip(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
|
|
|
|
BOOLEAN KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
|
|
BOOLEAN KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 3, 4);
|
|
VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 2, 0);
|
|
VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 2, 3);
|
|
BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
|
|
BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...) KMT_FORMAT(ms_printf, 3, 4);
|
|
PVOID KmtAllocateGuarded(SIZE_T SizeRequested);
|
|
VOID KmtFreeGuarded(PVOID Pointer);
|
|
|
|
#ifdef KMT_KERNEL_MODE
|
|
#define ok_irql(irql) ok(KeGetCurrentIrql() == irql, "IRQL is %d, expected %d\n", KeGetCurrentIrql(), irql)
|
|
#endif /* defined KMT_KERNEL_MODE */
|
|
#define ok_eq_print(value, expected, spec) ok((value) == (expected), #value " = " spec ", expected " spec "\n", value, expected)
|
|
#define ok_eq_pointer(value, expected) ok_eq_print(value, expected, "%p")
|
|
#define ok_eq_int(value, expected) ok_eq_print(value, expected, "%d")
|
|
#define ok_eq_uint(value, expected) ok_eq_print(value, expected, "%u")
|
|
#define ok_eq_long(value, expected) ok_eq_print(value, expected, "%ld")
|
|
#define ok_eq_ulong(value, expected) ok_eq_print(value, expected, "%lu")
|
|
#define ok_eq_longlong(value, expected) ok_eq_print(value, expected, "%I64d")
|
|
#define ok_eq_ulonglong(value, expected) ok_eq_print(value, expected, "%I64u")
|
|
#define ok_eq_char(value, expected) ok_eq_print(value, expected, "%c")
|
|
#define ok_eq_wchar(value, expected) ok_eq_print(value, expected, "%C")
|
|
#ifndef _WIN64
|
|
#define ok_eq_size(value, expected) ok_eq_print(value, (SIZE_T)(expected), "%lu")
|
|
#define ok_eq_longptr(value, expected) ok_eq_print(value, (LONG_PTR)(expected), "%ld")
|
|
#define ok_eq_ulongptr(value, expected) ok_eq_print(value, (ULONG_PTR)(expected), "%lu")
|
|
#elif defined _WIN64
|
|
#define ok_eq_size(value, expected) ok_eq_print(value, (SIZE_T)(expected), "%I64u")
|
|
#define ok_eq_longptr(value, expected) ok_eq_print(value, (LONG_PTR)(expected), "%I64d")
|
|
#define ok_eq_ulongptr(value, expected) ok_eq_print(value, (ULONG_PTR)(expected), "%I64u")
|
|
#endif /* defined _WIN64 */
|
|
#define ok_eq_hex(value, expected) ok_eq_print(value, expected, "0x%08lx")
|
|
#define ok_bool_true(value, desc) ok((value) == TRUE, desc " FALSE, expected TRUE\n")
|
|
#define ok_bool_false(value, desc) ok((value) == FALSE, desc " TRUE, expected FALSE\n")
|
|
#define ok_eq_bool(value, expected) ok((value) == (expected), #value " = %s, expected %s\n", \
|
|
(value) ? "TRUE" : "FALSE", \
|
|
(expected) ? "TRUE" : "FALSE")
|
|
#define ok_eq_str(value, expected) ok(!strcmp(value, expected), #value " = \"%s\", expected \"%s\"\n", value, expected)
|
|
#define ok_eq_wstr(value, expected) ok(!wcscmp(value, expected), #value " = \"%ls\", expected \"%ls\"\n", value, expected)
|
|
#define ok_eq_tag(value, expected) ok_eq_print(value, expected, "0x%08lx")
|
|
|
|
#define KMT_MAKE_CODE(ControlCode) CTL_CODE(FILE_DEVICE_UNKNOWN, \
|
|
0xC00 + (ControlCode), \
|
|
METHOD_BUFFERED, \
|
|
FILE_ANY_ACCESS)
|
|
|
|
#define MICROSECOND 10
|
|
#define MILLISECOND (1000 * MICROSECOND)
|
|
#define SECOND (1000 * MILLISECOND)
|
|
|
|
/* See apitests/include/apitest.h */
|
|
#define KmtInvalidPointer ((PVOID)0x5555555555555555ULL)
|
|
|
|
#define KmtStartSeh() \
|
|
{ \
|
|
NTSTATUS ExceptionStatus = STATUS_SUCCESS; \
|
|
_SEH2_TRY \
|
|
{
|
|
|
|
#define KmtEndSeh(ExpectedStatus) \
|
|
} \
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) \
|
|
{ \
|
|
ExceptionStatus = _SEH2_GetExceptionCode(); \
|
|
} \
|
|
_SEH2_END; \
|
|
ok_eq_hex(ExceptionStatus, (ExpectedStatus)); \
|
|
}
|
|
|
|
#define KmtGetSystemOrEmbeddedRoutineAddress(RoutineName) \
|
|
p##RoutineName = KmtGetSystemRoutineAddress(L ## #RoutineName); \
|
|
if (!p##RoutineName) \
|
|
{ \
|
|
p##RoutineName = RoutineName; \
|
|
trace("Using embedded routine for " #RoutineName "\n"); \
|
|
} \
|
|
else \
|
|
trace("Using system routine for " #RoutineName "\n");
|
|
|
|
#if defined KMT_DEFINE_TEST_FUNCTIONS
|
|
|
|
#if defined KMT_KERNEL_MODE
|
|
#include "kmt_test_kernel.h"
|
|
#elif defined KMT_USER_MODE
|
|
#include "kmt_test_user.h"
|
|
#endif /* defined KMT_USER_MODE */
|
|
|
|
PKMT_RESULTBUFFER ResultBuffer = NULL;
|
|
|
|
static VOID KmtAddToLogBuffer(PKMT_RESULTBUFFER Buffer, PCSTR String, SIZE_T Length)
|
|
{
|
|
LONG OldLength;
|
|
LONG NewLength;
|
|
|
|
if (!Buffer)
|
|
return;
|
|
|
|
do
|
|
{
|
|
OldLength = Buffer->LogBufferLength;
|
|
NewLength = OldLength + (ULONG)Length;
|
|
if (NewLength > Buffer->LogBufferMaxLength)
|
|
return;
|
|
} while (InterlockedCompareExchange(&Buffer->LogBufferLength, NewLength, OldLength) != OldLength);
|
|
|
|
memcpy(&Buffer->LogBuffer[OldLength], String, Length);
|
|
}
|
|
|
|
KMT_FORMAT(ms_printf, 5, 0)
|
|
static SIZE_T KmtXVSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, va_list Arguments)
|
|
{
|
|
SIZE_T BufferLength = 0;
|
|
SIZE_T Length;
|
|
|
|
if (FileAndLine)
|
|
{
|
|
PCSTR Slash;
|
|
Slash = strrchr(FileAndLine, '\\');
|
|
if (Slash)
|
|
FileAndLine = Slash + 1;
|
|
Slash = strrchr(FileAndLine, '/');
|
|
if (Slash)
|
|
FileAndLine = Slash + 1;
|
|
|
|
Length = min(BufferMaxLength, strlen(FileAndLine));
|
|
memcpy(Buffer, FileAndLine, Length);
|
|
Buffer += Length;
|
|
BufferLength += Length;
|
|
BufferMaxLength -= Length;
|
|
}
|
|
if (Prepend)
|
|
{
|
|
Length = min(BufferMaxLength, strlen(Prepend));
|
|
memcpy(Buffer, Prepend, Length);
|
|
Buffer += Length;
|
|
BufferLength += Length;
|
|
BufferMaxLength -= Length;
|
|
}
|
|
if (Format)
|
|
{
|
|
Length = KmtVSNPrintF(Buffer, BufferMaxLength, Format, Arguments);
|
|
/* vsnprintf can return more than maxLength, we don't want to do that */
|
|
BufferLength += min(Length, BufferMaxLength);
|
|
}
|
|
return BufferLength;
|
|
}
|
|
|
|
KMT_FORMAT(ms_printf, 5, 6)
|
|
static SIZE_T KmtXSNPrintF(PSTR Buffer, SIZE_T BufferMaxLength, PCSTR FileAndLine, PCSTR Prepend, PCSTR Format, ...)
|
|
{
|
|
SIZE_T BufferLength;
|
|
va_list Arguments;
|
|
va_start(Arguments, Format);
|
|
BufferLength = KmtXVSNPrintF(Buffer, BufferMaxLength, FileAndLine, Prepend, Format, Arguments);
|
|
va_end(Arguments);
|
|
return BufferLength;
|
|
}
|
|
|
|
VOID KmtFinishTest(PCSTR TestName)
|
|
{
|
|
CHAR MessageBuffer[512];
|
|
SIZE_T MessageLength;
|
|
|
|
if (!ResultBuffer)
|
|
return;
|
|
|
|
MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, NULL, NULL,
|
|
"%s: %ld tests executed (0 marked as todo, %ld failures), %ld skipped.\n",
|
|
TestName,
|
|
ResultBuffer->Successes + ResultBuffer->Failures,
|
|
ResultBuffer->Failures,
|
|
ResultBuffer->Skipped);
|
|
KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
|
|
}
|
|
|
|
BOOLEAN KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
|
|
{
|
|
CHAR MessageBuffer[512];
|
|
SIZE_T MessageLength;
|
|
|
|
if (!ResultBuffer)
|
|
return Condition != 0;
|
|
|
|
if (Condition)
|
|
{
|
|
InterlockedIncrement(&ResultBuffer->Successes);
|
|
|
|
if (0/*KmtReportSuccess*/)
|
|
{
|
|
MessageLength = KmtXSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test succeeded\n", NULL);
|
|
KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
InterlockedIncrement(&ResultBuffer->Failures);
|
|
MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Test failed: ", Format, Arguments);
|
|
KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
|
|
}
|
|
|
|
return Condition != 0;
|
|
}
|
|
|
|
BOOLEAN KmtOk(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
|
|
{
|
|
BOOLEAN Ret;
|
|
va_list Arguments;
|
|
va_start(Arguments, Format);
|
|
Ret = KmtVOk(Condition, FileAndLine, Format, Arguments);
|
|
va_end(Arguments);
|
|
return Ret;
|
|
}
|
|
|
|
VOID KmtVTrace(PCSTR FileAndLine, PCSTR Format, va_list Arguments)
|
|
{
|
|
CHAR MessageBuffer[512];
|
|
SIZE_T MessageLength;
|
|
|
|
MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": ", Format, Arguments);
|
|
KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
|
|
}
|
|
|
|
VOID KmtTrace(PCSTR FileAndLine, PCSTR Format, ...)
|
|
{
|
|
va_list Arguments;
|
|
va_start(Arguments, Format);
|
|
KmtVTrace(FileAndLine, Format, Arguments);
|
|
va_end(Arguments);
|
|
}
|
|
|
|
BOOLEAN KmtVSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments)
|
|
{
|
|
CHAR MessageBuffer[512];
|
|
SIZE_T MessageLength;
|
|
|
|
if (!ResultBuffer)
|
|
return !Condition;
|
|
|
|
if (!Condition)
|
|
{
|
|
InterlockedIncrement(&ResultBuffer->Skipped);
|
|
MessageLength = KmtXVSNPrintF(MessageBuffer, sizeof MessageBuffer, FileAndLine, ": Tests skipped: ", Format, Arguments);
|
|
KmtAddToLogBuffer(ResultBuffer, MessageBuffer, MessageLength);
|
|
}
|
|
|
|
return !Condition;
|
|
}
|
|
|
|
BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
|
|
{
|
|
BOOLEAN Ret;
|
|
va_list Arguments;
|
|
va_start(Arguments, Format);
|
|
Ret = KmtVSkip(Condition, FileAndLine, Format, Arguments);
|
|
va_end(Arguments);
|
|
return Ret;
|
|
}
|
|
|
|
PVOID KmtAllocateGuarded(SIZE_T SizeRequested)
|
|
{
|
|
NTSTATUS Status;
|
|
SIZE_T Size = PAGE_ROUND_UP(SizeRequested + PAGE_SIZE);
|
|
PVOID VirtualMemory = NULL;
|
|
PCHAR StartOfBuffer;
|
|
|
|
Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory, 0, &Size, MEM_RESERVE, PAGE_NOACCESS);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
return NULL;
|
|
|
|
Size -= PAGE_SIZE;
|
|
Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &VirtualMemory, 0, &Size, MEM_COMMIT, PAGE_READWRITE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Size = 0;
|
|
Status = ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
|
|
ok_eq_hex(Status, STATUS_SUCCESS);
|
|
return NULL;
|
|
}
|
|
|
|
StartOfBuffer = VirtualMemory;
|
|
StartOfBuffer += Size - SizeRequested;
|
|
|
|
return StartOfBuffer;
|
|
}
|
|
|
|
VOID KmtFreeGuarded(PVOID Pointer)
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID VirtualMemory = (PVOID)PAGE_ROUND_DOWN((SIZE_T)Pointer);
|
|
SIZE_T Size = 0;
|
|
|
|
Status = ZwFreeVirtualMemory(ZwCurrentProcess(), &VirtualMemory, &Size, MEM_RELEASE);
|
|
ok_eq_hex(Status, STATUS_SUCCESS);
|
|
}
|
|
|
|
#endif /* defined KMT_DEFINE_TEST_FUNCTIONS */
|
|
|
|
#endif /* !defined _KMTEST_TEST_H_ */
|