1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite Hard error message test
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 
10 /* TODO: don't require user interaction, test Io* routines,
11  *       test NTSTATUS values with special handling */
12 
13 static
14 VOID
SetParameters(OUT PULONG_PTR Parameters,IN INT Count,...)15 SetParameters(
16     OUT PULONG_PTR Parameters,
17     IN INT Count,
18     ...)
19 {
20     INT i;
21     va_list Arguments;
22     va_start(Arguments, Count);
23     for (i = 0; i < Count; ++i)
24         Parameters[i] = va_arg(Arguments, ULONG_PTR);
25     va_end(Arguments);
26 }
27 
28 #define NoResponse 27
29 
30 #define CheckHardError(ErrStatus, UnicodeStringMask, ResponseOption,    \
31                         ExpectedStatus, ExpectedResponse,               \
32                         NumberOfParameters, ...) do                     \
33 {                                                                       \
34     SetParameters(HardErrorParameters, NumberOfParameters, __VA_ARGS__);\
35     Response = NoResponse;                                              \
36     _SEH2_TRY {                                                         \
37         Status = ExRaiseHardError(ErrStatus,                            \
38                                   NumberOfParameters,                   \
39                                   UnicodeStringMask,                    \
40                                   HardErrorParameters,                  \
41                                   ResponseOption,                       \
42                                   &Response);                           \
43     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {                         \
44         Status = _SEH2_GetExceptionCode();                              \
45     } _SEH2_END;                                                        \
46     ok_eq_hex(Status, ExpectedStatus);                                  \
47     ok_eq_ulong(Response, (ULONG)ExpectedResponse);                     \
48 } while (0)
49 
50 #define CheckInformationalHardError(ErrStatus, String, Thread,          \
51                                         ExpectedStatus, ExpectedRet) do \
52 {                                                                       \
53     Status = STATUS_SUCCESS;                                            \
54     Ret = !ExpectedRet;                                                 \
55     _SEH2_TRY {                                                         \
56         Ret = IoRaiseInformationalHardError(ErrStatus,                  \
57                                             String,                     \
58                                             Thread);                    \
59     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {                         \
60         Status = _SEH2_GetExceptionCode();                              \
61     } _SEH2_END;                                                        \
62     ok_eq_hex(Status, ExpectedStatus);                                  \
63     ok_eq_bool(Ret, ExpectedRet);                                       \
64 } while (0)
65 
66 static
67 VOID
TestHardError(BOOLEAN InteractivePart1,BOOLEAN InteractivePart2,BOOLEAN InteractivePart3,BOOLEAN InteractivePart4)68 TestHardError(
69     BOOLEAN InteractivePart1,
70     BOOLEAN InteractivePart2,
71     BOOLEAN InteractivePart3,
72     BOOLEAN InteractivePart4)
73 {
74     NTSTATUS Status;
75     ULONG Response;
76     WCHAR StringBuffer1[] = L"Parameter1+Garbage";
77     CHAR StringBuffer1Ansi[] = "Parameter1+Garbage";
78     WCHAR StringBuffer2[] = L"Parameter2+Garbage";
79     UNICODE_STRING String1 = RTL_CONSTANT_STRING(StringBuffer1);
80     ANSI_STRING String1Ansi = RTL_CONSTANT_STRING(StringBuffer1Ansi);
81     UNICODE_STRING String2 = RTL_CONSTANT_STRING(StringBuffer2);
82     ULONG_PTR HardErrorParameters[6];
83     BOOLEAN Ret;
84 
85     String1.Length = sizeof L"Parameter1" - sizeof UNICODE_NULL;
86     String1Ansi.Length = sizeof "Parameter1" - sizeof ANSI_NULL;
87     String2.Length = sizeof L"Parameter2" - sizeof UNICODE_NULL;
88 
89     if (InteractivePart1)
90     {
91     CheckHardError(0x40000000,                  0, OptionOk,                STATUS_SUCCESS,            ResponseOk,             0, 0);                          // outputs a box :|
92     CheckHardError(0x40000001,                  0, OptionOk,                STATUS_SUCCESS,            ResponseOk,             4, 1, 2, 3, 4);                 // outputs a box :|
93     CheckHardError(0x40000002,                  0, OptionOk,                STATUS_SUCCESS,            ResponseOk,             5, 1, 2, 3, 4, 5);              // outputs a box :|
94     CheckHardError(0x40000003,                  0, OptionOk,                STATUS_SUCCESS,            ResponseNotHandled,     6, 1, 2, 3, 4, 5, 6);           // TODO: interactive on ROS
95     }
96 
97     CheckHardError(0x40000004,                  0, OptionShutdownSystem,    STATUS_PRIVILEGE_NOT_HELD, ResponseNotHandled,     0, 0);
98     if (InteractivePart1)
99     {
100     // TODO: these 2 are interactive on ROS
101     CheckHardError(0x40000005,                  0, OptionOkNoWait,          STATUS_SUCCESS,            ResponseOk,             0, 0);                          // outputs a balloon notification
102     CheckHardError(0x4000000f,                  0, OptionOkNoWait,          STATUS_SUCCESS,            ResponseOk,             0, 0);                          // outputs a balloon notification
103     CheckHardError(0x40000006,                  0, OptionAbortRetryIgnore,  STATUS_SUCCESS,            ResponseAbort,          0, 0);                          // outputs a box :|
104     CheckHardError(0x40000006,                  0, OptionAbortRetryIgnore,  STATUS_SUCCESS,            ResponseRetry,          0, 0);                          // outputs a box :|
105     CheckHardError(0x40000006,                  0, OptionAbortRetryIgnore,  STATUS_SUCCESS,            ResponseIgnore,         0, 0);                          // outputs a box :|
106     CheckHardError(0x40000008,                  0, OptionCancelTryContinue, STATUS_SUCCESS,            ResponseCancel,         0, 0);                          // outputs a box :|
107     CheckHardError(0x40000008,                  0, OptionCancelTryContinue, STATUS_SUCCESS,            ResponseTryAgain,       0, 0);                          // outputs a box :|
108     CheckHardError(0x40000008,                  0, OptionCancelTryContinue, STATUS_SUCCESS,            ResponseContinue,       0, 0);                          // outputs a box :|
109     CheckHardError(0x40000010,                  0, OptionOkCancel,          STATUS_SUCCESS,            ResponseOk,             0, 0);                          // outputs a box :|
110     CheckHardError(0x40000010,                  0, OptionOkCancel,          STATUS_SUCCESS,            ResponseCancel,         0, 0);                          // outputs a box :|
111     CheckHardError(0x40000011,                  0, OptionRetryCancel,       STATUS_SUCCESS,            ResponseRetry,          0, 0);                          // outputs a box :|
112     CheckHardError(0x40000011,                  0, OptionRetryCancel,       STATUS_SUCCESS,            ResponseCancel,         0, 0);                          // outputs a box :|
113     CheckHardError(0x40000012,                  0, OptionYesNo,             STATUS_SUCCESS,            ResponseYes,            0, 0);                          // outputs a box :|
114     CheckHardError(0x40000012,                  0, OptionYesNo,             STATUS_SUCCESS,            ResponseNo,             0, 0);                          // outputs a box :|
115     CheckHardError(0x40000013,                  0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            0, 0);                          // outputs a box :|
116     CheckHardError(0x40000013,                  0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNo,             0, 0);                          // outputs a box :|
117     CheckHardError(0x40000013,                  0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         0, 0);                          // outputs a box :|
118     }
119     CheckHardError(0x40000009,                  0, 9,                       STATUS_SUCCESS,            ResponseNotHandled,     0, 0);
120     CheckHardError(0x4000000a,                  0, 10,                      STATUS_SUCCESS,            ResponseNotHandled,     0, 0);
121     CheckHardError(0x4000000b,                  0, 11,                      STATUS_SUCCESS,            ResponseNotHandled,     0, 0);
122     CheckHardError(0x4000000c,                  0, 12,                      STATUS_SUCCESS,            ResponseNotHandled,     0, 0);
123     CheckHardError(0x4000000d,                  0, MAXULONG / 2 + 1,        STATUS_SUCCESS,            ResponseNotHandled,     0, 0);
124     CheckHardError(0x4000000d,                  0, MAXULONG,                STATUS_SUCCESS,            ResponseNotHandled,     0, 0);
125 
126     if (InteractivePart2)
127     {
128     /* try a message with one parameter */
129     CheckHardError(STATUS_DLL_NOT_FOUND,        1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            1, &String1);                   // outputs a box :|
130     CheckHardError(STATUS_DLL_NOT_FOUND,        0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, &String1);                   // outputs a box :|
131     CheckHardError(STATUS_DLL_NOT_FOUND,        1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         0, &String1);                   // outputs a box :|
132     CheckHardError(STATUS_DLL_NOT_FOUND,        0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         0, &String1);                   // outputs a box :|
133     /* give too many parameters */
134     CheckHardError(STATUS_DLL_NOT_FOUND,        1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            2, &String1, &String2);         // outputs a box :|
135     CheckHardError(STATUS_DLL_NOT_FOUND,        2, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         2, &String1, &String2);         // outputs a box :|
136     CheckHardError(STATUS_DLL_NOT_FOUND,        3, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            2, &String1, &String2);         // outputs a box :|
137     CheckHardError(STATUS_DLL_NOT_FOUND,        3, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            4, &String1, &String2, 0, 0);   // outputs a box :|
138     /* try with stuff that's not a UNICODE_STRING */
139     CheckHardError(STATUS_DLL_NOT_FOUND,        1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNo,             1, &String1Ansi);               // outputs a box :|
140     CheckHardError(STATUS_DLL_NOT_FOUND,        1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNo,             1, L"Parameter1");              // outputs a box :|
141     CheckHardError(STATUS_DLL_NOT_FOUND,        1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNo,             1, "Parameter1");               // outputs a box :|
142     CheckHardError(STATUS_DLL_NOT_FOUND,        1, OptionYesNoCancel,       STATUS_ACCESS_VIOLATION,   NoResponse,             1, 1234);                       // outputs a box :|
143     CheckHardError(STATUS_DLL_NOT_FOUND,        1, OptionYesNoCancel,       STATUS_ACCESS_VIOLATION,   NoResponse,             1, NULL);                       // outputs a box :|
144     CheckHardError(STATUS_DLL_NOT_FOUND,        0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, &String1Ansi);               // outputs a box :|
145     CheckHardError(STATUS_DLL_NOT_FOUND,        0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, L"Parameter1");              // outputs a box :|
146     CheckHardError(STATUS_DLL_NOT_FOUND,        0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, "Parameter1");               // outputs a box :|
147     CheckHardError(STATUS_DLL_NOT_FOUND,        0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, 1234);                       // outputs a box :|
148     CheckHardError(STATUS_DLL_NOT_FOUND,        0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, NULL);                       // outputs a box :|
149     }
150     if (InteractivePart3)
151     {
152     /* try a message with one parameter */
153     CheckHardError(STATUS_SERVICE_NOTIFICATION, 1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, &String1);                   // outputs a box :|
154     CheckHardError(STATUS_SERVICE_NOTIFICATION, 0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, &String1);                   // outputs a box :|
155     CheckHardError(STATUS_SERVICE_NOTIFICATION, 1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     0, &String1);                   // outputs a box :|
156     CheckHardError(STATUS_SERVICE_NOTIFICATION, 0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     0, &String1);                   // outputs a box :|
157     /* give too many parameters */
158     CheckHardError(STATUS_SERVICE_NOTIFICATION, 1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     2, &String1, &String2);         // outputs a box :|
159     CheckHardError(STATUS_SERVICE_NOTIFICATION, 2, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     2, &String1, &String2);         // outputs a box :|
160     CheckHardError(STATUS_SERVICE_NOTIFICATION, 3, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     2, &String1, &String2);         // outputs a box :|
161     CheckHardError(STATUS_SERVICE_NOTIFICATION, 3, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseOk,             3, &String1, &String2, 0);      // outputs a box :|
162     CheckHardError(STATUS_SERVICE_NOTIFICATION, 3, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseOk,             4, &String1, &String2, 0, 0);   // outputs a box :|
163     CheckHardError(STATUS_SERVICE_NOTIFICATION, 3, OptionOkNoWait,          STATUS_SUCCESS,            ResponseOk,             4, &String1, &String2, 0, 0);   // outputs a balloon notification
164     /* try with stuff that's not a UNICODE_STRING */
165     CheckHardError(STATUS_SERVICE_NOTIFICATION, 1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, &String1Ansi);               // outputs a box :|
166     CheckHardError(STATUS_SERVICE_NOTIFICATION, 1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, L"Parameter1");              // outputs a box :|
167     CheckHardError(STATUS_SERVICE_NOTIFICATION, 1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, "Parameter1");               // outputs a box :|
168     CheckHardError(STATUS_SERVICE_NOTIFICATION, 1, OptionYesNoCancel,       STATUS_ACCESS_VIOLATION,   NoResponse,             1, 1234);                       // outputs a box :|
169     CheckHardError(STATUS_SERVICE_NOTIFICATION, 1, OptionYesNoCancel,       STATUS_ACCESS_VIOLATION,   NoResponse,             1, NULL);                       // outputs a box :|
170     CheckHardError(STATUS_SERVICE_NOTIFICATION, 0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, &String1Ansi);               // outputs a box :|
171     CheckHardError(STATUS_SERVICE_NOTIFICATION, 0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, L"Parameter1");              // outputs a box :|
172     CheckHardError(STATUS_SERVICE_NOTIFICATION, 0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, "Parameter1");               // outputs a box :|
173     CheckHardError(STATUS_SERVICE_NOTIFICATION, 0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, 1234);                       // outputs a box :|
174     CheckHardError(STATUS_SERVICE_NOTIFICATION, 0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNotHandled,     1, NULL);                       // outputs a box :|
175     }
176     if (InteractivePart4)
177     {
178     /* try a message with one parameter */
179     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            1, &String1);                   // outputs a box :|
180     CheckHardError(STATUS_FATAL_APP_EXIT,       0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, &String1);                   // outputs a box :|
181     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         0, &String1);                   // outputs a box :|
182     CheckHardError(STATUS_FATAL_APP_EXIT,       0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         0, &String1);                   // outputs a box :|
183     /* give too many parameters */
184     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            2, &String1, &String2);         // outputs a box :|
185     CheckHardError(STATUS_FATAL_APP_EXIT,       2, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         2, &String1, &String2);         // outputs a box :|
186     CheckHardError(STATUS_FATAL_APP_EXIT,       3, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            2, &String1, &String2);         // outputs a box :|
187     CheckHardError(STATUS_FATAL_APP_EXIT,       3, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseYes,            4, &String1, &String2, 0, 0);   // outputs a box :|
188     /* try with stuff that's not a UNICODE_STRING */
189     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNo,             1, &String1Ansi);               // outputs a box :|
190     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNo,             1, L"Parameter1");              // outputs a box :|
191     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseNo,             1, "Parameter1");               // outputs a box :|
192     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_ACCESS_VIOLATION,   NoResponse,             1, 1234);                       // outputs a box :|
193     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_ACCESS_VIOLATION,   NoResponse,             1, NULL);                       // outputs a box :|
194     CheckHardError(STATUS_FATAL_APP_EXIT,       0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, &String1Ansi);               // outputs a box :|
195     CheckHardError(STATUS_FATAL_APP_EXIT,       0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, L"Parameter1");              // outputs a box :|
196     CheckHardError(STATUS_FATAL_APP_EXIT,       0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, "Parameter1");               // outputs a box :|
197     CheckHardError(STATUS_FATAL_APP_EXIT,       0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, 1234);                       // outputs a box :|
198     CheckHardError(STATUS_FATAL_APP_EXIT,       0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseCancel,         1, NULL);                       // outputs a box :|
199 
200     // TODO: these 3 are interactive on ROS
201     CheckInformationalHardError(STATUS_WAIT_0,               NULL,     NULL, STATUS_SUCCESS, TRUE);                                                            // outputs a balloon notification
202     CheckInformationalHardError(STATUS_DLL_NOT_FOUND,        &String1, NULL, STATUS_SUCCESS, TRUE);                                                            // outputs a balloon notification
203     CheckInformationalHardError(STATUS_DLL_NOT_FOUND,        NULL,     NULL, STATUS_SUCCESS, TRUE);                                                            // outputs a balloon notification
204     }
205     CheckInformationalHardError(STATUS_SERVICE_NOTIFICATION, &String1, NULL, STATUS_SUCCESS, FALSE);
206 
207     ok_bool_true(IoSetThreadHardErrorMode(TRUE), "IoSetThreadHardErrorMode returned");
208     ok_bool_true(IoSetThreadHardErrorMode(FALSE), "IoSetThreadHardErrorMode returned");
209     ok_bool_false(IoSetThreadHardErrorMode(FALSE), "IoSetThreadHardErrorMode returned");
210     CheckHardError(STATUS_FATAL_APP_EXIT,       0, OptionYesNoCancel,       STATUS_SUCCESS,            ResponseReturnToCaller, 0, 0);
211     CheckHardError(STATUS_FATAL_APP_EXIT,       1, OptionYesNoCancel,       STATUS_ACCESS_VIOLATION,   NoResponse,             1, NULL);
212     CheckInformationalHardError(STATUS_WAIT_0,               NULL,     NULL, STATUS_SUCCESS, FALSE);
213     CheckInformationalHardError(STATUS_DLL_NOT_FOUND,        &String1, NULL, STATUS_SUCCESS, FALSE);
214     CheckInformationalHardError(STATUS_DLL_NOT_FOUND,        NULL,     NULL, STATUS_SUCCESS, FALSE);
215     CheckInformationalHardError(STATUS_SERVICE_NOTIFICATION, &String1, NULL, STATUS_SUCCESS, FALSE);
216     ok_bool_false(IoSetThreadHardErrorMode(TRUE), "IoSetThreadHardErrorMode returned");
217 }
218 
START_TEST(ExHardError)219 START_TEST(ExHardError)
220 {
221     TestHardError(FALSE, FALSE, FALSE, FALSE);
222 }
223 
224 /* Here's how to do the interactive test:
225  * - First there will be a few messages random messages. If there's
226  *   multiple options available, the same box will appear multiple times --
227  *   click the buttons in order from left to right
228  * - After that, you must verify the error parameters. You should always
229  *   see Parameter1 or Parameter2 for strings, and 0x12345678 for numbers.
230  *   if there's a message saying an exception occured during processing,
231  *   click cancel. If there's a bad parameter (Parameter1+, Parameter1+Garbage
232  *   or an empty string for example), click no. Otherwise click yes. */
START_TEST(ExHardErrorInteractive)233 START_TEST(ExHardErrorInteractive)
234 {
235     TestHardError(TRUE, TRUE, TRUE, TRUE);
236 }
237