1 /*
2 * PROJECT: ReactOS API Tests
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Test for exception behavior in dll notifications
5 * COPYRIGHT: Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
6 */
7
8 #include "precomp.h"
9
10 #include <pseh/pseh2.h>
11
12 WCHAR dllpath[MAX_PATH];
13
14 LONG g_TlsCalled = 0;
15 LONG g_DllMainCalled = 0;
16
17 LONG g_TlsExcept = 0xffffff;
18 LONG g_DllMainExcept = 0xffffff;
19
20 ULONG g_BaseHandlers = 0;
21
22 DWORD g_dwWinVer = 0;
23
CountHandlers(VOID)24 ULONG CountHandlers(VOID)
25 {
26 EXCEPTION_REGISTRATION_RECORD* exc;
27 ULONG Count = 0;
28
29 exc = NtCurrentTeb()->NtTib.ExceptionList;
30
31 while (exc && exc != (EXCEPTION_REGISTRATION_RECORD*)~0)
32 {
33 Count++;
34 exc = exc->Next;
35 }
36
37 return Count;
38 }
39
40 int g_TLS_ATTACH = 4;
41 int g_TLS_DETACH = 3;
42
notify_TlsCallback(IN HINSTANCE hDllHandle,IN DWORD dwReason,IN LPVOID lpvReserved)43 VOID WINAPI notify_TlsCallback(IN HINSTANCE hDllHandle, IN DWORD dwReason, IN LPVOID lpvReserved)
44 {
45 ULONG handlers = CountHandlers() - g_BaseHandlers;
46
47 InterlockedIncrement(&g_TlsCalled);
48 if (dwReason == DLL_PROCESS_ATTACH)
49 {
50 ok_int(handlers, g_TLS_ATTACH);
51 }
52 else
53 {
54 ok_int(handlers, g_TLS_DETACH);
55 }
56
57 if (InterlockedCompareExchange(&g_TlsExcept, 0xffffff, dwReason) == dwReason)
58 {
59 RaiseException(EXCEPTION_DATATYPE_MISALIGNMENT, EXCEPTION_NONCONTINUABLE, 0, NULL);
60 }
61 }
62
63 int g_DLL_ATTACH = 3;
64 int g_DLL_DETACH = 2;
65
notify_DllMain(IN HINSTANCE hDllHandle,IN DWORD dwReason,IN LPVOID lpvReserved)66 BOOL WINAPI notify_DllMain(IN HINSTANCE hDllHandle, IN DWORD dwReason, IN LPVOID lpvReserved)
67 {
68 ULONG handlers = CountHandlers() - g_BaseHandlers;
69
70 InterlockedIncrement(&g_DllMainCalled);
71 if (dwReason == DLL_PROCESS_ATTACH)
72 {
73 ok_int(handlers, g_DLL_ATTACH);
74 }
75 else
76 {
77 ok_int(handlers, g_DLL_DETACH); // For failures, see https://jira.reactos.org/browse/CORE-14857
78 }
79
80 if (InterlockedCompareExchange(&g_DllMainExcept, 0xffffff, dwReason) == dwReason)
81 {
82 RaiseException(EXCEPTION_DATATYPE_MISALIGNMENT, EXCEPTION_NONCONTINUABLE, 0, NULL);
83 }
84 return TRUE;
85 }
86
87
execute_test(void)88 static void execute_test(void)
89 {
90 HMODULE mod;
91 DWORD dwErr;
92 _SEH2_TRY
93 {
94 g_TlsExcept = 0xffffff;
95 g_DllMainExcept = 0xffffff;
96 g_DllMainCalled = 0;
97 g_TlsCalled = 0;
98 g_BaseHandlers = CountHandlers();
99 mod = LoadLibraryW(dllpath);
100 dwErr = GetLastError();
101 ok(GetModuleHandleW(dllpath) != NULL, "Unable to load module (0x%lx)\n", dwErr);
102 ok_hex(g_DllMainCalled, 1);
103 if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
104 ok_hex(g_TlsCalled, 1);
105 if (g_TlsCalled == 0)
106 trace("Tls not active\n");
107 g_BaseHandlers = CountHandlers();
108 FreeLibrary(mod);
109 dwErr = GetLastError();
110 ok(GetModuleHandleW(dllpath) == NULL, "Unable to unload module (0x%lx)\n", dwErr);
111 ok_hex(g_DllMainCalled, 2);
112 if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
113 ok_hex(g_TlsCalled, 2);
114 }
115 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
116 {
117 ok(0, "Unable to load it normally\n");
118 }
119 _SEH2_END;
120
121
122 _SEH2_TRY
123 {
124 g_TlsExcept = 0xffffff;
125 g_DllMainExcept = DLL_PROCESS_ATTACH;
126 g_DllMainCalled = 0;
127 g_TlsCalled = 0;
128 g_BaseHandlers = CountHandlers();
129 mod = LoadLibraryW(dllpath);
130 dwErr = GetLastError();
131 ok(GetModuleHandleW(dllpath) == NULL, "Module loaded (0x%lx)\n", dwErr);
132 if (g_dwWinVer <= _WIN32_WINNT_WIN7)
133 ok_hex(dwErr, ERROR_NOACCESS);
134 else
135 ok_hex(dwErr, ERROR_DLL_INIT_FAILED);
136 ok_hex(g_DllMainCalled, 1);
137 if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
138 ok_hex(g_TlsCalled, 1);
139 if (mod)
140 {
141 FreeLibrary(mod);
142 dwErr = GetLastError();
143 ok(GetModuleHandleW(dllpath) == NULL, "Unable to unload module (0x%lx)\n", dwErr);
144 ok_hex(g_DllMainCalled, 1);
145 if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
146 ok_hex(g_TlsCalled, 1);
147 }
148 }
149 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
150 {
151 ok(0, "Unable to execute test\n");
152 }
153 _SEH2_END;
154
155 _SEH2_TRY
156 {
157 g_TlsExcept = 0xffffff;
158 g_DllMainExcept = DLL_PROCESS_DETACH;
159 g_DllMainCalled = 0;
160 g_TlsCalled = 0;
161 g_BaseHandlers = CountHandlers();
162 mod = LoadLibraryW(dllpath);
163 dwErr = GetLastError();
164 ok(GetModuleHandleW(dllpath) != NULL, "Unable to load module (0x%lx)\n", dwErr);
165 ok_hex(g_DllMainCalled, 1);
166 if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
167 ok_hex(g_TlsCalled, 1);
168 g_BaseHandlers = CountHandlers();
169 FreeLibrary(mod);
170 dwErr = GetLastError();
171 ok(GetModuleHandleW(dllpath) == NULL, "Unable to unload module (0x%lx)\n", dwErr);
172 ok_hex(g_DllMainCalled, 2);
173 if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
174 ok_hex(g_TlsCalled, 2);
175 }
176 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
177 {
178 ok(0, "Unable to execute test\n");
179 }
180 _SEH2_END;
181
182 _SEH2_TRY
183 {
184 g_TlsExcept = DLL_PROCESS_ATTACH;
185 g_DllMainExcept = 0xffffff;
186 g_DllMainCalled = 0;
187 g_TlsCalled = 0;
188 g_BaseHandlers = CountHandlers();
189 mod = LoadLibraryW(dllpath);
190 dwErr = GetLastError();
191 ok(GetModuleHandleW(dllpath) != NULL, "Unable to load module (0x%lx)\n", dwErr);
192 ok_hex(g_DllMainCalled, 1);
193 if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
194 ok_hex(g_TlsCalled, 1);
195 g_BaseHandlers = CountHandlers();
196 FreeLibrary(mod);
197 dwErr = GetLastError();
198 ok(GetModuleHandleW(dllpath) == NULL, "Unable to unload module (0x%lx)\n", dwErr);
199 ok_hex(g_DllMainCalled, 2);
200 if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
201 ok_hex(g_TlsCalled, 2);
202 }
203 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
204 {
205 ok(0, "Unable to execute test\n");
206 }
207 _SEH2_END;
208
209 _SEH2_TRY
210 {
211 g_TlsExcept = DLL_PROCESS_DETACH;
212 g_DllMainExcept = 0xffffff;
213 g_DllMainCalled = 0;
214 g_TlsCalled = 0;
215 g_BaseHandlers = CountHandlers();
216 mod = LoadLibraryW(dllpath);
217 dwErr = GetLastError();
218 ok(GetModuleHandleW(dllpath) != NULL, "Unable to load module (0x%lx)\n", dwErr);
219 ok_hex(g_DllMainCalled, 1);
220 if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
221 ok_hex(g_TlsCalled, 1);
222 g_BaseHandlers = CountHandlers();
223 FreeLibrary(mod);
224 dwErr = GetLastError();
225 ok(GetModuleHandleW(dllpath) == NULL, "Unable to unload module (0x%lx)\n", dwErr);
226 ok_hex(g_DllMainCalled, 2);
227 if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
228 ok_hex(g_TlsCalled, 2);
229 }
230 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
231 {
232 ok(0, "Unable to execute test\n");
233 }
234 _SEH2_END;
235
236 }
237
238
extract_resource(const WCHAR * Filename,LPCWSTR ResourceName)239 BOOL extract_resource(const WCHAR* Filename, LPCWSTR ResourceName)
240 {
241 BOOL Success;
242 DWORD dwWritten, Size;
243 HGLOBAL hGlobal;
244 LPVOID pData;
245 HANDLE Handle;
246 HRSRC hRsrc = FindResourceW(GetModuleHandleW(NULL), ResourceName, (LPCWSTR)10);
247 ok(!!hRsrc, "Unable to find %s\n", wine_dbgstr_w(ResourceName));
248 if (!hRsrc)
249 return FALSE;
250
251 hGlobal = LoadResource(GetModuleHandleW(NULL), hRsrc);
252 Size = SizeofResource(GetModuleHandleW(NULL), hRsrc);
253 pData = LockResource(hGlobal);
254
255 ok(Size && !!pData, "Unable to load %s\n", wine_dbgstr_w(ResourceName));
256 if (!Size || !pData)
257 return FALSE;
258
259 Handle = CreateFileW(Filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
260
261 if (Handle == INVALID_HANDLE_VALUE)
262 {
263 skip("Failed to create temp file %ls, error %lu\n", Filename, GetLastError());
264 return FALSE;
265 }
266 Success = WriteFile(Handle, pData, Size, &dwWritten, NULL);
267 ok(Success == TRUE, "WriteFile failed with %lu\n", GetLastError());
268 ok(dwWritten == Size, "WriteFile wrote %lu bytes instead of %lu\n", dwWritten, Size);
269 CloseHandle(Handle);
270 Success = Success && (dwWritten == Size);
271
272 UnlockResource(pData);
273 return Success;
274 }
275
276
START_TEST(load_notifications)277 START_TEST(load_notifications)
278 {
279 WCHAR workdir[MAX_PATH];
280 BOOL ret;
281 UINT Length;
282 PPEB Peb = NtCurrentPeb();
283
284 g_dwWinVer = (DWORD)(Peb->OSMajorVersion << 8) | Peb->OSMinorVersion;
285 trace("Winver: 0x%lx\n", g_dwWinVer);
286
287 if (g_dwWinVer <= _WIN32_WINNT_WS03)
288 {
289 g_DLL_ATTACH = 4;
290 g_DLL_DETACH = 1;
291 }
292 else if (g_dwWinVer <= _WIN32_WINNT_WS08)
293 {
294 g_TLS_ATTACH = 5;
295 g_DLL_ATTACH = 4;
296 }
297 else if (g_dwWinVer <= _WIN32_WINNT_WIN7)
298 {
299 g_TLS_ATTACH = 3;
300 g_DLL_ATTACH = 2;
301 }
302 else if (g_dwWinVer <= _WIN32_WINNT_WINBLUE)
303 {
304 g_TLS_DETACH = 5;
305 g_DLL_DETACH = 4;
306 }
307
308 ret = GetTempPathW(_countof(workdir), workdir);
309 ok(ret, "GetTempPathW error: %lu\n", GetLastError());
310
311 Length = GetTempFileNameW(workdir, L"ntdll", 0, dllpath);
312 ok(Length != 0, "GetTempFileNameW failed with %lu\n", GetLastError());
313
314 if (extract_resource(dllpath, (LPCWSTR)101))
315 {
316 _SEH2_TRY
317 {
318 execute_test();
319 }
320 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
321 {
322 ok(0, "Ldr didnt handle exception\n");
323 }
324 _SEH2_END;
325 }
326 else
327 {
328 ok(0, "Failed to extract resource\n");
329 }
330
331 DeleteFileW(dllpath);
332 }
333