reactos/modules/rostests/apitests/kernel32/SetUnhandledExceptionFilter.c
2017-12-13 13:48:26 +01:00

175 lines
4.7 KiB
C

/*
* PROJECT: ReactOS api tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Test for SetUnhandledExceptionFilter
* PROGRAMMER: Mike "tamlin" Nordell
*/
#include "precomp.h"
#include <xmmintrin.h>
/*
* Keep these returning different values, to prevent compiler folding
* them into a single function, thereby voiding the test
*/
LONG WINAPI Filter1(LPEXCEPTION_POINTERS p) { return 0; }
LONG WINAPI Filter2(LPEXCEPTION_POINTERS p) { return 1; }
/*
* Verify that SetUnhandledExceptionFilter actually returns the
* _previous_ handler.
*/
static
VOID
TestSetUnhandledExceptionFilter(VOID)
{
LPTOP_LEVEL_EXCEPTION_FILTER p1, p2;
p1 = SetUnhandledExceptionFilter(Filter1);
p2 = SetUnhandledExceptionFilter(Filter2);
ok(p1 != Filter1, "SetUnhandledExceptionFilter returned what was set, not prev\n");
ok(p2 != Filter2, "SetUnhandledExceptionFilter returned what was set, not prev\n");
ok(p2 == Filter1, "SetUnhandledExceptionFilter didn't return previous filter\n");
ok(p1 != p2, "SetUnhandledExceptionFilter seems to return random stuff\n");
p1 = SetUnhandledExceptionFilter(NULL);
ok(p1 == Filter2, "SetUnhandledExceptionFilter didn't return previous filter\n");
}
static LONG WINAPI ExceptionFilterSSESupport(LPEXCEPTION_POINTERS exp)
{
PEXCEPTION_RECORD rec = exp->ExceptionRecord;
PCONTEXT ctx = exp->ContextRecord;
trace("Exception raised while using SSE instructions.\n");
ok(rec->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION, "Exception code is 0x%08x.\n", (unsigned int)rec->ExceptionCode);
if(rec->ExceptionCode != EXCEPTION_ILLEGAL_INSTRUCTION)
{
trace("Unexpected exception code, terminating!\n");
return EXCEPTION_EXECUTE_HANDLER;
}
ok((ctx->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL, "Context does not contain control register.\n");
ctx->Eip += 3;
return EXCEPTION_CONTINUE_EXECUTION;
}
static BOOL ExceptionCaught = FALSE;
static LONG WINAPI ExceptionFilterSSEException(LPEXCEPTION_POINTERS exp)
{
PEXCEPTION_RECORD rec = exp->ExceptionRecord;
PCONTEXT ctx = exp->ContextRecord;
trace("Exception raised while dividing by 0.\n");
ok(rec->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS, "Exception code is 0x%08x.\n", (unsigned int)rec->ExceptionCode);
if(rec->ExceptionCode != STATUS_FLOAT_MULTIPLE_TRAPS)
{
trace("Unexpected exception code, terminating!\n");
return EXCEPTION_EXECUTE_HANDLER;
}
ok((ctx->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL, "Context does not contain control register.\n");
ExceptionCaught = TRUE;
ctx->Eip += 3;
return EXCEPTION_CONTINUE_EXECUTION;
}
static
VOID TestSSEExceptions(VOID)
{
LPTOP_LEVEL_EXCEPTION_FILTER p;
BOOL supportsSSE = FALSE;
unsigned int csr;
/* Test SSE support for the CPU */
p = SetUnhandledExceptionFilter(ExceptionFilterSSESupport);
ok(p == NULL, "Previous filter should be NULL\n");
#ifdef _MSC_VER
__asm
{
xorps xmm0, xmm0
mov supportsSSE, 0x1
}
#else
__asm__(
"xorps %%xmm0, %%xmm0\n"
"movl $1, %0\n"
: "=r"(supportsSSE)
);
#endif /* _MSC_VER */
if(!supportsSSE)
{
skip("CPU doesn't support SSE instructions.\n");
SetUnhandledExceptionFilter(NULL);
return;
}
/* Deliberately throw a divide by 0 exception */
p = SetUnhandledExceptionFilter(ExceptionFilterSSEException);
ok(p == ExceptionFilterSSESupport, "Unexpected old filter : 0x%p", p);
/* Unmask divide by 0 exception */
csr = _mm_getcsr();
_mm_setcsr(csr & 0xFFFFFDFF);
/* We can't use _mm_div_ps, as it masks the exception before performing anything*/
#if defined(_MSC_VER)
__asm
{
xorps xmm0, xmm0
push 0x3f800000
push 0x3f800000
push 0x3f800000
push 0x3f800000
movups xmm1, [esp]
/* Divide by 0 */
divps xmm1, xmm0
/* Clean up */
add esp, 16
}
#else
__asm__ (
"xorps %%xmm0, %%xmm0\n"
"pushl $0x3f800000\n"
"pushl $0x3f800000\n"
"pushl $0x3f800000\n"
"pushl $0x3f800000\n"
"movups (%%esp), %%xmm1\n"
/* Divide by 0 */
"divps %%xmm0, %%xmm1\n"
/* Clean up */
"addl $16, %%esp\n"
:
);
#endif /* _MSC_VER */
/* Restore mxcsr */
_mm_setcsr(csr);
ok(ExceptionCaught, "The exception was not caught.\n");
p = SetUnhandledExceptionFilter(NULL);
ok(p == ExceptionFilterSSEException, "Unexpected old filter : 0x%p", p);
}
START_TEST(SetUnhandledExceptionFilter)
{
TestSetUnhandledExceptionFilter();
TestSSEExceptions();
}