2012-09-11 04:34:03 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS api tests
|
|
|
|
* LICENSE: GPLv2+ - See COPYING in the top level directory
|
|
|
|
* PURPOSE: Test for SetUnhandledExceptionFilter
|
|
|
|
* PROGRAMMER: Mike "tamlin" Nordell
|
|
|
|
*/
|
|
|
|
|
2017-12-13 12:48:26 +00:00
|
|
|
#include "precomp.h"
|
2013-09-22 17:52:42 +00:00
|
|
|
|
2013-04-06 19:15:11 +00:00
|
|
|
#include <xmmintrin.h>
|
2012-09-11 04:34:03 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Keep these returning different values, to prevent compiler folding
|
|
|
|
* them into a single function, thereby voiding the test
|
|
|
|
*/
|
2012-09-11 05:14:33 +00:00
|
|
|
LONG WINAPI Filter1(LPEXCEPTION_POINTERS p) { return 0; }
|
|
|
|
LONG WINAPI Filter2(LPEXCEPTION_POINTERS p) { return 1; }
|
2012-09-11 04:34:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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");
|
2021-04-09 14:50:43 +00:00
|
|
|
|
2013-04-06 19:15:11 +00:00
|
|
|
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;
|
2021-04-09 14:50:43 +00:00
|
|
|
|
2013-04-06 19:15:11 +00:00
|
|
|
trace("Exception raised while using SSE instructions.\n");
|
|
|
|
|
|
|
|
ok(rec->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION, "Exception code is 0x%08x.\n", (unsigned int)rec->ExceptionCode);
|
2021-04-09 14:50:43 +00:00
|
|
|
|
2013-04-06 19:15:11 +00:00
|
|
|
if(rec->ExceptionCode != EXCEPTION_ILLEGAL_INSTRUCTION)
|
|
|
|
{
|
|
|
|
trace("Unexpected exception code, terminating!\n");
|
|
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
|
|
}
|
2021-04-09 14:50:43 +00:00
|
|
|
|
2013-04-06 19:15:11 +00:00
|
|
|
ok((ctx->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL, "Context does not contain control register.\n");
|
2021-04-09 14:50:43 +00:00
|
|
|
|
2019-05-30 15:12:28 +00:00
|
|
|
#ifdef _M_IX86
|
2013-04-06 19:15:11 +00:00
|
|
|
ctx->Eip += 3;
|
2019-05-30 15:12:28 +00:00
|
|
|
#elif defined(_M_AMD64)
|
|
|
|
ctx->Rip += 3;
|
|
|
|
#else
|
|
|
|
#error Architecture not handled
|
|
|
|
#endif
|
2013-04-06 19:15:11 +00:00
|
|
|
|
|
|
|
return EXCEPTION_CONTINUE_EXECUTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL ExceptionCaught = FALSE;
|
|
|
|
|
|
|
|
static LONG WINAPI ExceptionFilterSSEException(LPEXCEPTION_POINTERS exp)
|
|
|
|
{
|
|
|
|
PEXCEPTION_RECORD rec = exp->ExceptionRecord;
|
|
|
|
PCONTEXT ctx = exp->ContextRecord;
|
2019-05-30 15:12:28 +00:00
|
|
|
#ifdef _M_AMD64
|
|
|
|
ULONG ExpectedExceptionCode = STATUS_FLOAT_DIVIDE_BY_ZERO;
|
|
|
|
#else
|
|
|
|
ULONG ExpectedExceptionCode = STATUS_FLOAT_MULTIPLE_TRAPS;
|
|
|
|
#endif
|
2021-04-09 14:50:43 +00:00
|
|
|
|
2013-04-06 19:15:11 +00:00
|
|
|
trace("Exception raised while dividing by 0.\n");
|
2021-04-09 14:50:43 +00:00
|
|
|
|
2019-05-30 15:12:28 +00:00
|
|
|
ok(rec->ExceptionCode == ExpectedExceptionCode, "Exception code is 0x%08x.\n", (unsigned int)rec->ExceptionCode);
|
2021-04-09 14:50:43 +00:00
|
|
|
|
2019-05-30 15:12:28 +00:00
|
|
|
if(rec->ExceptionCode != ExpectedExceptionCode)
|
2013-04-06 19:15:11 +00:00
|
|
|
{
|
|
|
|
trace("Unexpected exception code, terminating!\n");
|
|
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
|
|
}
|
2021-04-09 14:50:43 +00:00
|
|
|
|
2013-04-06 19:15:11 +00:00
|
|
|
ok((ctx->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL, "Context does not contain control register.\n");
|
2021-04-09 14:50:43 +00:00
|
|
|
|
2013-04-06 19:15:11 +00:00
|
|
|
ExceptionCaught = TRUE;
|
2021-04-09 14:50:43 +00:00
|
|
|
|
2019-05-30 15:12:28 +00:00
|
|
|
#ifdef _M_IX86
|
2013-04-06 19:15:11 +00:00
|
|
|
ctx->Eip += 3;
|
2019-05-30 15:12:28 +00:00
|
|
|
#elif defined(_M_AMD64)
|
|
|
|
ctx->Rip += 3;
|
|
|
|
#else
|
|
|
|
#error Architecture not handled
|
|
|
|
#endif
|
2013-04-06 19:15:11 +00:00
|
|
|
|
|
|
|
return EXCEPTION_CONTINUE_EXECUTION;
|
|
|
|
}
|
|
|
|
|
2021-04-09 14:50:43 +00:00
|
|
|
#if defined(__clang__) || defined(__GNUC__)
|
2020-08-15 19:39:34 +00:00
|
|
|
__attribute__((__target__("sse")))
|
|
|
|
#endif
|
2013-04-06 19:15:11 +00:00
|
|
|
static
|
|
|
|
VOID TestSSEExceptions(VOID)
|
|
|
|
{
|
|
|
|
LPTOP_LEVEL_EXCEPTION_FILTER p;
|
|
|
|
unsigned int csr;
|
2021-04-09 14:50:43 +00:00
|
|
|
|
2013-04-06 19:15:11 +00:00
|
|
|
/* Test SSE support for the CPU */
|
|
|
|
p = SetUnhandledExceptionFilter(ExceptionFilterSSESupport);
|
|
|
|
ok(p == NULL, "Previous filter should be NULL\n");
|
2021-04-09 14:50:43 +00:00
|
|
|
|
|
|
|
#if !defined(_M_AMD64)
|
2013-04-06 19:15:11 +00:00
|
|
|
{
|
2021-04-09 14:50:43 +00:00
|
|
|
BOOL supportsSSE = FALSE;
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
__asm
|
|
|
|
{
|
|
|
|
xorps xmm0, xmm0
|
|
|
|
mov supportsSSE, 0x1
|
|
|
|
}
|
2013-04-06 19:15:11 +00:00
|
|
|
#else
|
2021-04-09 14:50:43 +00:00
|
|
|
__asm__(
|
|
|
|
"xorps %%xmm0, %%xmm0\n"
|
|
|
|
"movl $1, %0\n"
|
|
|
|
: "=r"(supportsSSE)
|
|
|
|
);
|
2013-04-06 19:15:11 +00:00
|
|
|
#endif /* _MSC_VER */
|
2021-04-09 14:50:43 +00:00
|
|
|
|
|
|
|
if(!supportsSSE)
|
|
|
|
{
|
|
|
|
skip("CPU doesn't support SSE instructions.\n");
|
|
|
|
SetUnhandledExceptionFilter(NULL);
|
|
|
|
return;
|
|
|
|
}
|
2013-04-06 19:15:11 +00:00
|
|
|
}
|
2021-04-09 14:50:43 +00:00
|
|
|
#endif /* !defined(_M_AMD64) */
|
|
|
|
|
2013-04-06 19:15:11 +00:00
|
|
|
/* Deliberately throw a divide by 0 exception */
|
|
|
|
p = SetUnhandledExceptionFilter(ExceptionFilterSSEException);
|
|
|
|
ok(p == ExceptionFilterSSESupport, "Unexpected old filter : 0x%p", p);
|
2021-04-09 14:50:43 +00:00
|
|
|
|
2013-04-06 19:15:11 +00:00
|
|
|
/* 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)
|
2019-05-30 15:12:28 +00:00
|
|
|
#if defined(_M_AMD64)
|
|
|
|
{
|
|
|
|
__m128 xmm1 = { { 1., 1. } }, xmm2 = { { 0 } };
|
|
|
|
/* Wait, aren't exceptions masked? Yes, but actually no. */
|
|
|
|
xmm1 = _mm_div_ps(xmm1, xmm2);
|
|
|
|
}
|
|
|
|
#else
|
2013-04-06 19:15:11 +00:00
|
|
|
__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
|
|
|
|
}
|
2019-05-30 15:12:28 +00:00
|
|
|
#endif
|
2013-04-06 19:15:11 +00:00
|
|
|
#else
|
2021-04-09 14:50:43 +00:00
|
|
|
ULONG zeros[4] = {0, 0, 0, 0};
|
|
|
|
ULONG ones[4] = {0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000};
|
2013-04-06 19:15:11 +00:00
|
|
|
__asm__ (
|
2021-04-09 14:50:43 +00:00
|
|
|
"movups (%0), %%xmm0\n"
|
|
|
|
"movups (%1), %%xmm1\n"
|
2013-04-06 19:15:11 +00:00
|
|
|
/* Divide by 0 */
|
|
|
|
"divps %%xmm0, %%xmm1\n"
|
|
|
|
|
2021-04-09 14:50:43 +00:00
|
|
|
: : "r"(&zeros), "r"(&ones) : "xmm0", "xmm1"
|
2013-04-06 19:26:35 +00:00
|
|
|
);
|
2013-04-06 19:15:11 +00:00
|
|
|
#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);
|
2012-09-11 04:34:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
START_TEST(SetUnhandledExceptionFilter)
|
|
|
|
{
|
|
|
|
TestSetUnhandledExceptionFilter();
|
2013-04-06 19:15:11 +00:00
|
|
|
TestSSEExceptions();
|
2012-09-11 04:34:03 +00:00
|
|
|
}
|