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