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 
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 
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 
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 
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 
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 
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