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