[KERNEL32_APITEST] Add a PCH.
[reactos.git] / modules / rostests / apitests / kernel32 / SetUnhandledExceptionFilter.c
1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for SetUnhandledExceptionFilter
5 * PROGRAMMER: Mike "tamlin" Nordell
6 */
7
8 #include "precomp.h"
9
10 #include <xmmintrin.h>
11
12 /*
13 * Keep these returning different values, to prevent compiler folding
14 * them into a single function, thereby voiding the test
15 */
16 LONG WINAPI Filter1(LPEXCEPTION_POINTERS p) { return 0; }
17 LONG WINAPI Filter2(LPEXCEPTION_POINTERS p) { return 1; }
18
19
20 /*
21 * Verify that SetUnhandledExceptionFilter actually returns the
22 * _previous_ handler.
23 */
24 static
25 VOID
26 TestSetUnhandledExceptionFilter(VOID)
27 {
28 LPTOP_LEVEL_EXCEPTION_FILTER p1, p2;
29 p1 = SetUnhandledExceptionFilter(Filter1);
30 p2 = SetUnhandledExceptionFilter(Filter2);
31 ok(p1 != Filter1, "SetUnhandledExceptionFilter returned what was set, not prev\n");
32 ok(p2 != Filter2, "SetUnhandledExceptionFilter returned what was set, not prev\n");
33 ok(p2 == Filter1, "SetUnhandledExceptionFilter didn't return previous filter\n");
34 ok(p1 != p2, "SetUnhandledExceptionFilter seems to return random stuff\n");
35
36 p1 = SetUnhandledExceptionFilter(NULL);
37 ok(p1 == Filter2, "SetUnhandledExceptionFilter didn't return previous filter\n");
38 }
39
40 static LONG WINAPI ExceptionFilterSSESupport(LPEXCEPTION_POINTERS exp)
41 {
42 PEXCEPTION_RECORD rec = exp->ExceptionRecord;
43 PCONTEXT ctx = exp->ContextRecord;
44
45 trace("Exception raised while using SSE instructions.\n");
46
47 ok(rec->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION, "Exception code is 0x%08x.\n", (unsigned int)rec->ExceptionCode);
48
49 if(rec->ExceptionCode != EXCEPTION_ILLEGAL_INSTRUCTION)
50 {
51 trace("Unexpected exception code, terminating!\n");
52 return EXCEPTION_EXECUTE_HANDLER;
53 }
54
55 ok((ctx->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL, "Context does not contain control register.\n");
56
57 ctx->Eip += 3;
58
59 return EXCEPTION_CONTINUE_EXECUTION;
60 }
61
62 static BOOL ExceptionCaught = FALSE;
63
64 static LONG WINAPI ExceptionFilterSSEException(LPEXCEPTION_POINTERS exp)
65 {
66 PEXCEPTION_RECORD rec = exp->ExceptionRecord;
67 PCONTEXT ctx = exp->ContextRecord;
68
69 trace("Exception raised while dividing by 0.\n");
70
71 ok(rec->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS, "Exception code is 0x%08x.\n", (unsigned int)rec->ExceptionCode);
72
73 if(rec->ExceptionCode != STATUS_FLOAT_MULTIPLE_TRAPS)
74 {
75 trace("Unexpected exception code, terminating!\n");
76 return EXCEPTION_EXECUTE_HANDLER;
77 }
78
79 ok((ctx->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL, "Context does not contain control register.\n");
80
81 ExceptionCaught = TRUE;
82
83 ctx->Eip += 3;
84
85 return EXCEPTION_CONTINUE_EXECUTION;
86 }
87
88 static
89 VOID TestSSEExceptions(VOID)
90 {
91 LPTOP_LEVEL_EXCEPTION_FILTER p;
92 BOOL supportsSSE = FALSE;
93 unsigned int csr;
94
95 /* Test SSE support for the CPU */
96 p = SetUnhandledExceptionFilter(ExceptionFilterSSESupport);
97 ok(p == NULL, "Previous filter should be NULL\n");
98 #ifdef _MSC_VER
99 __asm
100 {
101 xorps xmm0, xmm0
102 mov supportsSSE, 0x1
103 }
104 #else
105 __asm__(
106 "xorps %%xmm0, %%xmm0\n"
107 "movl $1, %0\n"
108 : "=r"(supportsSSE)
109 );
110 #endif /* _MSC_VER */
111 if(!supportsSSE)
112 {
113 skip("CPU doesn't support SSE instructions.\n");
114 SetUnhandledExceptionFilter(NULL);
115 return;
116 }
117 /* Deliberately throw a divide by 0 exception */
118 p = SetUnhandledExceptionFilter(ExceptionFilterSSEException);
119 ok(p == ExceptionFilterSSESupport, "Unexpected old filter : 0x%p", p);
120
121 /* Unmask divide by 0 exception */
122 csr = _mm_getcsr();
123 _mm_setcsr(csr & 0xFFFFFDFF);
124
125 /* We can't use _mm_div_ps, as it masks the exception before performing anything*/
126 #if defined(_MSC_VER)
127 __asm
128 {
129 xorps xmm0, xmm0
130 push 0x3f800000
131 push 0x3f800000
132 push 0x3f800000
133 push 0x3f800000
134
135 movups xmm1, [esp]
136
137 /* Divide by 0 */
138 divps xmm1, xmm0
139
140 /* Clean up */
141 add esp, 16
142 }
143 #else
144 __asm__ (
145 "xorps %%xmm0, %%xmm0\n"
146 "pushl $0x3f800000\n"
147 "pushl $0x3f800000\n"
148 "pushl $0x3f800000\n"
149 "pushl $0x3f800000\n"
150 "movups (%%esp), %%xmm1\n"
151
152 /* Divide by 0 */
153 "divps %%xmm0, %%xmm1\n"
154
155 /* Clean up */
156 "addl $16, %%esp\n"
157 :
158 );
159 #endif /* _MSC_VER */
160
161 /* Restore mxcsr */
162 _mm_setcsr(csr);
163
164 ok(ExceptionCaught, "The exception was not caught.\n");
165
166 p = SetUnhandledExceptionFilter(NULL);
167 ok(p == ExceptionFilterSSEException, "Unexpected old filter : 0x%p", p);
168 }
169
170 START_TEST(SetUnhandledExceptionFilter)
171 {
172 TestSetUnhandledExceptionFilter();
173 TestSSEExceptions();
174 }