mirror of
https://github.com/reactos/reactos
synced 2025-10-05 16:02:58 +02:00
[NTDLL_APITEST] Add simple tests for RtlUnhandledExceptionFilter(2) (#8353)
Based on an example from Whindmar Saksit.
This commit is contained in:
@@ -125,6 +125,7 @@ list(APPEND SOURCE
|
||||
RtlQueryTimeZoneInfo.c
|
||||
RtlReAllocateHeap.c
|
||||
RtlRemovePrivileges.c
|
||||
RtlUnhandledExceptionFilter.c
|
||||
RtlUnicodeStringToAnsiString.c
|
||||
RtlUnicodeStringToCountedOemString.c
|
||||
RtlUnicodeToOemN.c
|
||||
|
110
modules/rostests/apitests/ntdll/RtlUnhandledExceptionFilter.c
Normal file
110
modules/rostests/apitests/ntdll/RtlUnhandledExceptionFilter.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* PROJECT: ReactOS API tests
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Tests for RtlUnhandledExceptionFilter(2)
|
||||
* COPYRIGHT: Copyright 2025 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
static NTSTATUS KnownExceptionCodes[] =
|
||||
{
|
||||
/* Well-known exception codes, see include/psdk/minwinbase.h */
|
||||
EXCEPTION_ACCESS_VIOLATION,
|
||||
EXCEPTION_DATATYPE_MISALIGNMENT,
|
||||
EXCEPTION_BREAKPOINT,
|
||||
EXCEPTION_SINGLE_STEP,
|
||||
EXCEPTION_ARRAY_BOUNDS_EXCEEDED,
|
||||
EXCEPTION_FLT_DENORMAL_OPERAND,
|
||||
EXCEPTION_FLT_DIVIDE_BY_ZERO,
|
||||
EXCEPTION_FLT_INEXACT_RESULT,
|
||||
EXCEPTION_FLT_INVALID_OPERATION,
|
||||
EXCEPTION_FLT_OVERFLOW,
|
||||
EXCEPTION_FLT_STACK_CHECK,
|
||||
EXCEPTION_FLT_UNDERFLOW,
|
||||
EXCEPTION_INT_DIVIDE_BY_ZERO,
|
||||
EXCEPTION_INT_OVERFLOW,
|
||||
EXCEPTION_PRIV_INSTRUCTION,
|
||||
EXCEPTION_IN_PAGE_ERROR,
|
||||
EXCEPTION_ILLEGAL_INSTRUCTION,
|
||||
EXCEPTION_NONCONTINUABLE_EXCEPTION,
|
||||
EXCEPTION_STACK_OVERFLOW,
|
||||
EXCEPTION_INVALID_DISPOSITION,
|
||||
EXCEPTION_GUARD_PAGE,
|
||||
EXCEPTION_INVALID_HANDLE,
|
||||
EXCEPTION_POSSIBLE_DEADLOCK,
|
||||
/* Additional ones */
|
||||
STATUS_STACK_BUFFER_OVERRUN,
|
||||
};
|
||||
|
||||
START_TEST(RtlUnhandledExceptionFilter)
|
||||
{
|
||||
LONG (NTAPI* pRtlUnhandledExceptionFilter)(_In_ PEXCEPTION_POINTERS ExceptionInfo);
|
||||
LONG (NTAPI* pRtlUnhandledExceptionFilter2)(_In_ PEXCEPTION_POINTERS ExceptionInfo, _In_ PCSTR Function);
|
||||
PPEB Peb = NtCurrentPeb();
|
||||
CONTEXT ctx = {0};
|
||||
EXCEPTION_RECORD er = {0};
|
||||
EXCEPTION_POINTERS ep = {&er, &ctx};
|
||||
|
||||
/* Load functions */
|
||||
HMODULE hNtDll = GetModuleHandleW(L"ntdll.dll");
|
||||
if (!hNtDll)
|
||||
{
|
||||
skip("GetModuleHandleW(\"ntdll.dll\") failed with 0x%08lX\n", GetLastError());
|
||||
return;
|
||||
}
|
||||
pRtlUnhandledExceptionFilter = (VOID*)GetProcAddress(hNtDll, "RtlUnhandledExceptionFilter");
|
||||
pRtlUnhandledExceptionFilter2 = (VOID*)GetProcAddress(hNtDll, "RtlUnhandledExceptionFilter2");
|
||||
if (!pRtlUnhandledExceptionFilter || !pRtlUnhandledExceptionFilter2)
|
||||
{
|
||||
skip("ntdll!RtlUnhandledExceptionFilter(2) not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Build a dummy context/exception record. Not really valid on self, don't care. */
|
||||
ctx.ContextFlags = CONTEXT_CONTROL;
|
||||
GetThreadContext(GetCurrentThread(), &ctx);
|
||||
|
||||
/* Disable BeingDebugged so that RtlUnhandledExceptionFilter(2) doesn't
|
||||
* unnecessarily break into the debugger with the debugging instructions.
|
||||
* If you want to see them, comment the following line! */
|
||||
Peb->BeingDebugged = FALSE;
|
||||
|
||||
/* Test the filter routine return value under different exception codes */
|
||||
// for (er.ExceptionCode = 0; er.ExceptionCode != ~0; ++er.ExceptionCode)
|
||||
for (UINT i = 0; i < _countof(KnownExceptionCodes); ++i)
|
||||
{
|
||||
LONG r = EXCEPTION_CONTINUE_SEARCH;
|
||||
BOOLEAN fail = TRUE;
|
||||
er.ExceptionCode = KnownExceptionCodes[i];
|
||||
|
||||
/* Skip test if stack overflow code; the filter would invoke another crash handler */
|
||||
if (er.ExceptionCode == STATUS_STACK_BUFFER_OVERRUN)
|
||||
continue;
|
||||
|
||||
_SEH2_TRY
|
||||
{
|
||||
_SEH2_TRY
|
||||
{
|
||||
r = pRtlUnhandledExceptionFilter2(&ep, __FUNCTION__);
|
||||
fail = FALSE;
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
}
|
||||
_SEH2_END;
|
||||
}
|
||||
_SEH2_FINALLY
|
||||
{
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
// trace("%#x ret %lu\n", er.ExceptionCode, r);
|
||||
if (er.ExceptionCode == STATUS_POSSIBLE_DEADLOCK)
|
||||
ok_long(r, EXCEPTION_CONTINUE_EXECUTION);
|
||||
else
|
||||
ok_long(r, EXCEPTION_CONTINUE_SEARCH);
|
||||
if (fail)
|
||||
trace("SEH on %#x\n", er.ExceptionCode);
|
||||
}
|
||||
}
|
@@ -113,6 +113,7 @@ extern void func_RtlpEnsureBufferSize(void);
|
||||
extern void func_RtlQueryTimeZoneInformation(void);
|
||||
extern void func_RtlReAllocateHeap(void);
|
||||
extern void func_RtlRemovePrivileges(void);
|
||||
extern void func_RtlUnhandledExceptionFilter(void);
|
||||
extern void func_RtlUnicodeStringToAnsiString(void);
|
||||
extern void func_RtlUnicodeStringToCountedOemString(void);
|
||||
extern void func_RtlUnicodeToOemN(void);
|
||||
@@ -238,6 +239,7 @@ const struct test winetest_testlist[] =
|
||||
{ "RtlQueryTimeZoneInformation", func_RtlQueryTimeZoneInformation },
|
||||
{ "RtlReAllocateHeap", func_RtlReAllocateHeap },
|
||||
{ "RtlRemovePrivileges", func_RtlRemovePrivileges },
|
||||
{ "RtlUnhandledExceptionFilter", func_RtlUnhandledExceptionFilter },
|
||||
{ "RtlUnicodeStringToAnsiSize", func_RtlxUnicodeStringToAnsiSize }, /* For some reason, starting test name with Rtlx hides it */
|
||||
{ "RtlUnicodeStringToAnsiString", func_RtlUnicodeStringToAnsiString },
|
||||
{ "RtlUnicodeStringToCountedOemString", func_RtlUnicodeStringToCountedOemString },
|
||||
|
Reference in New Issue
Block a user