https://git.reactos.org/?p=reactos.git;a=commitdiff;h=86fe412d5c9aa2bee0032…
commit 86fe412d5c9aa2bee0032381401a892319040df1
Author: Mark Jansen <mark.jansen(a)reactos.org>
AuthorDate: Sat Apr 14 21:00:18 2018 +0200
Commit: Mark Jansen <mark.jansen(a)reactos.org>
CommitDate: Mon Aug 13 13:24:12 2018 +0200
[NTDLL_APITEST] Show behavior with exceptions in DllMain.
CORE-14532
---
modules/rostests/apitests/ntdll/CMakeLists.txt | 14 +-
.../rostests/apitests/ntdll/load_notifications.c | 330 +++++++++++++++++++++
.../ntdll/load_notifications/CMakeLists.txt | 6 +
.../ntdll/load_notifications/load_notifications.c | 72 +++++
modules/rostests/apitests/ntdll/ntdll_apitest.spec | 2 +
modules/rostests/apitests/ntdll/testdata.rc | 2 +
modules/rostests/apitests/ntdll/testlist.c | 2 +
7 files changed, 427 insertions(+), 1 deletion(-)
diff --git a/modules/rostests/apitests/ntdll/CMakeLists.txt
b/modules/rostests/apitests/ntdll/CMakeLists.txt
index a7fdc5a2cd..2bb13f2d3e 100644
--- a/modules/rostests/apitests/ntdll/CMakeLists.txt
+++ b/modules/rostests/apitests/ntdll/CMakeLists.txt
@@ -1,6 +1,12 @@
+add_subdirectory(load_notifications)
+
+include_directories($<TARGET_FILE_DIR:load_notifications>)
+spec2def(ntdll_apitest.exe ntdll_apitest.spec)
+
list(APPEND SOURCE
LdrEnumResources.c
+ load_notifications.c
NtAcceptConnectPort.c
NtAllocateVirtualMemory.c
NtApphelpCacheControl.c
@@ -62,7 +68,13 @@ if(ARCH STREQUAL "i386")
add_asm_files(ntdll_apitest_asm i386/NtContinue.S)
endif()
-add_executable(ntdll_apitest ${SOURCE} ${ntdll_apitest_asm} testlist.c)
+add_rc_deps(testdata.rc
${CMAKE_CURRENT_BINARY_DIR}/load_notifications/load_notifications.dll)
+add_executable(ntdll_apitest
+ ${SOURCE}
+ ${ntdll_apitest_asm}
+ testdata.rc
+ ${CMAKE_CURRENT_BINARY_DIR}/ntdll_apitest.def
+ testlist.c)
target_link_libraries(ntdll_apitest wine uuid ${PSEH_LIB})
set_module_type(ntdll_apitest win32cui)
add_importlibs(ntdll_apitest msvcrt advapi32 kernel32 ntdll)
diff --git a/modules/rostests/apitests/ntdll/load_notifications.c
b/modules/rostests/apitests/ntdll/load_notifications.c
new file mode 100644
index 0000000000..430e2fc5cb
--- /dev/null
+++ b/modules/rostests/apitests/ntdll/load_notifications.c
@@ -0,0 +1,330 @@
+/*
+ * PROJECT: ReactOS API Tests
+ * LICENSE: GPL-2.0+ (
https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE: Test for exception behavior in dll notifications
+ * COPYRIGHT: Copyright 2018 Mark Jansen (mark.jansen(a)reactos.org)
+ */
+
+#include "precomp.h"
+
+WCHAR dllpath[MAX_PATH];
+
+LONG g_TlsCalled = 0;
+LONG g_DllMainCalled = 0;
+
+LONG g_TlsExcept = 0xffffff;
+LONG g_DllMainExcept = 0xffffff;
+
+ULONG g_BaseHandlers = 0;
+
+DWORD g_dwWinVer = 0;
+
+ULONG CountHandlers(VOID)
+{
+ EXCEPTION_REGISTRATION_RECORD* exc;
+ ULONG Count = 0;
+
+ exc = NtCurrentTeb()->NtTib.ExceptionList;
+
+ while (exc && exc != (EXCEPTION_REGISTRATION_RECORD*)~0)
+ {
+ Count++;
+ exc = exc->Next;
+ }
+
+ return Count;
+}
+
+int g_TLS_ATTACH = 4;
+int g_TLS_DETACH = 3;
+
+VOID WINAPI notify_TlsCallback(IN HINSTANCE hDllHandle, IN DWORD dwReason, IN LPVOID
lpvReserved)
+{
+ ULONG handlers = CountHandlers() - g_BaseHandlers;
+
+ InterlockedIncrement(&g_TlsCalled);
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ ok_int(handlers, g_TLS_ATTACH);
+ }
+ else
+ {
+ ok_int(handlers, g_TLS_DETACH);
+ }
+
+ if (InterlockedCompareExchange(&g_TlsExcept, 0xffffff, dwReason) == dwReason)
+ {
+ RaiseException(EXCEPTION_DATATYPE_MISALIGNMENT, EXCEPTION_NONCONTINUABLE, 0,
NULL);
+ }
+}
+
+int g_DLL_ATTACH = 3;
+int g_DLL_DETACH = 2;
+
+BOOL WINAPI notify_DllMain(IN HINSTANCE hDllHandle, IN DWORD dwReason, IN LPVOID
lpvReserved)
+{
+ ULONG handlers = CountHandlers() - g_BaseHandlers;
+
+ InterlockedIncrement(&g_DllMainCalled);
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ ok_int(handlers, g_DLL_ATTACH);
+ }
+ else
+ {
+ ok_int(handlers, g_DLL_DETACH);
+ }
+
+ if (InterlockedCompareExchange(&g_DllMainExcept, 0xffffff, dwReason) ==
dwReason)
+ {
+ RaiseException(EXCEPTION_DATATYPE_MISALIGNMENT, EXCEPTION_NONCONTINUABLE, 0,
NULL);
+ }
+ return TRUE;
+}
+
+
+static void execute_test(void)
+{
+ HMODULE mod;
+ DWORD dwErr;
+ _SEH2_TRY
+ {
+ g_TlsExcept = 0xffffff;
+ g_DllMainExcept = 0xffffff;
+ g_DllMainCalled = 0;
+ g_TlsCalled = 0;
+ g_BaseHandlers = CountHandlers();
+ mod = LoadLibraryW(dllpath);
+ dwErr = GetLastError();
+ ok(GetModuleHandleW(dllpath) != NULL, "Unable to load module
(0x%lx)\n", dwErr);
+ ok_hex(g_DllMainCalled, 1);
+ if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
+ ok_hex(g_TlsCalled, 1);
+ if (g_TlsCalled == 0)
+ trace("Tls not active\n");
+ g_BaseHandlers = CountHandlers();
+ FreeLibrary(mod);
+ dwErr = GetLastError();
+ ok(GetModuleHandleW(dllpath) == NULL, "Unable to unload module
(0x%lx)\n", dwErr);
+ ok_hex(g_DllMainCalled, 2);
+ if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
+ ok_hex(g_TlsCalled, 2);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ok(0, "Unable to load it normally\n");
+ }
+ _SEH2_END;
+
+
+ _SEH2_TRY
+ {
+ g_TlsExcept = 0xffffff;
+ g_DllMainExcept = DLL_PROCESS_ATTACH;
+ g_DllMainCalled = 0;
+ g_TlsCalled = 0;
+ g_BaseHandlers = CountHandlers();
+ mod = LoadLibraryW(dllpath);
+ dwErr = GetLastError();
+ ok(GetModuleHandleW(dllpath) == NULL, "Module loaded (0x%lx)\n",
dwErr);
+ if (g_dwWinVer <= _WIN32_WINNT_WIN7)
+ ok_hex(dwErr, ERROR_NOACCESS);
+ else
+ ok_hex(dwErr, ERROR_DLL_INIT_FAILED);
+ ok_hex(g_DllMainCalled, 1);
+ if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
+ ok_hex(g_TlsCalled, 1);
+ if (mod)
+ {
+ FreeLibrary(mod);
+ dwErr = GetLastError();
+ ok(GetModuleHandleW(dllpath) == NULL, "Unable to unload module
(0x%lx)\n", dwErr);
+ ok_hex(g_DllMainCalled, 1);
+ if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
+ ok_hex(g_TlsCalled, 1);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ok(0, "Unable to execute test\n");
+ }
+ _SEH2_END;
+
+ _SEH2_TRY
+ {
+ g_TlsExcept = 0xffffff;
+ g_DllMainExcept = DLL_PROCESS_DETACH;
+ g_DllMainCalled = 0;
+ g_TlsCalled = 0;
+ g_BaseHandlers = CountHandlers();
+ mod = LoadLibraryW(dllpath);
+ dwErr = GetLastError();
+ ok(GetModuleHandleW(dllpath) != NULL, "Unable to load module
(0x%lx)\n", dwErr);
+ ok_hex(g_DllMainCalled, 1);
+ if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
+ ok_hex(g_TlsCalled, 1);
+ g_BaseHandlers = CountHandlers();
+ FreeLibrary(mod);
+ dwErr = GetLastError();
+ ok(GetModuleHandleW(dllpath) == NULL, "Unable to unload module
(0x%lx)\n", dwErr);
+ ok_hex(g_DllMainCalled, 2);
+ if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
+ ok_hex(g_TlsCalled, 2);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ok(0, "Unable to execute test\n");
+ }
+ _SEH2_END;
+
+ _SEH2_TRY
+ {
+ g_TlsExcept = DLL_PROCESS_ATTACH;
+ g_DllMainExcept = 0xffffff;
+ g_DllMainCalled = 0;
+ g_TlsCalled = 0;
+ g_BaseHandlers = CountHandlers();
+ mod = LoadLibraryW(dllpath);
+ dwErr = GetLastError();
+ ok(GetModuleHandleW(dllpath) != NULL, "Unable to load module
(0x%lx)\n", dwErr);
+ ok_hex(g_DllMainCalled, 1);
+ if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
+ ok_hex(g_TlsCalled, 1);
+ g_BaseHandlers = CountHandlers();
+ FreeLibrary(mod);
+ dwErr = GetLastError();
+ ok(GetModuleHandleW(dllpath) == NULL, "Unable to unload module
(0x%lx)\n", dwErr);
+ ok_hex(g_DllMainCalled, 2);
+ if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
+ ok_hex(g_TlsCalled, 2);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ok(0, "Unable to execute test\n");
+ }
+ _SEH2_END;
+
+ _SEH2_TRY
+ {
+ g_TlsExcept = DLL_PROCESS_DETACH;
+ g_DllMainExcept = 0xffffff;
+ g_DllMainCalled = 0;
+ g_TlsCalled = 0;
+ g_BaseHandlers = CountHandlers();
+ mod = LoadLibraryW(dllpath);
+ dwErr = GetLastError();
+ ok(GetModuleHandleW(dllpath) != NULL, "Unable to load module
(0x%lx)\n", dwErr);
+ ok_hex(g_DllMainCalled, 1);
+ if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
+ ok_hex(g_TlsCalled, 1);
+ g_BaseHandlers = CountHandlers();
+ FreeLibrary(mod);
+ dwErr = GetLastError();
+ ok(GetModuleHandleW(dllpath) == NULL, "Unable to unload module
(0x%lx)\n", dwErr);
+ ok_hex(g_DllMainCalled, 2);
+ if (g_dwWinVer > _WIN32_WINNT_WS03 || g_TlsCalled)
+ ok_hex(g_TlsCalled, 2);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ok(0, "Unable to execute test\n");
+ }
+ _SEH2_END;
+
+}
+
+
+BOOL extract_resource(const WCHAR* Filename, LPCWSTR ResourceName)
+{
+ BOOL Success;
+ DWORD dwWritten, Size;
+ HGLOBAL hGlobal;
+ LPVOID pData;
+ HANDLE Handle;
+ HRSRC hRsrc = FindResourceW(GetModuleHandleW(NULL), ResourceName, (LPCWSTR)10);
+ ok(!!hRsrc, "Unable to find %s\n", wine_dbgstr_w(ResourceName));
+ if (!hRsrc)
+ return FALSE;
+
+ hGlobal = LoadResource(GetModuleHandleW(NULL), hRsrc);
+ Size = SizeofResource(GetModuleHandleW(NULL), hRsrc);
+ pData = LockResource(hGlobal);
+
+ ok(Size && !!pData, "Unable to load %s\n",
wine_dbgstr_w(ResourceName));
+ if (!Size || !pData)
+ return FALSE;
+
+ Handle = CreateFileW(Filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (Handle == INVALID_HANDLE_VALUE)
+ {
+ skip("Failed to create temp file %ls, error %lu\n", Filename,
GetLastError());
+ return FALSE;
+ }
+ Success = WriteFile(Handle, pData, Size, &dwWritten, NULL);
+ ok(Success == TRUE, "WriteFile failed with %lu\n", GetLastError());
+ ok(dwWritten == Size, "WriteFile wrote %lu bytes instead of %lu\n",
dwWritten, Size);
+ CloseHandle(Handle);
+ Success = Success && (dwWritten == Size);
+
+ UnlockResource(pData);
+ return Success;
+}
+
+
+START_TEST(load_notifications)
+{
+ WCHAR workdir[MAX_PATH];
+ BOOL ret;
+ UINT Length;
+ PPEB Peb = NtCurrentPeb();
+
+ g_dwWinVer = (DWORD)(Peb->OSMajorVersion << 8) | Peb->OSMinorVersion;
+ trace("Winver: 0x%lx\n", g_dwWinVer);
+
+ if (g_dwWinVer <= _WIN32_WINNT_WS03)
+ {
+ g_DLL_ATTACH = 4;
+ g_DLL_DETACH = 1;
+ }
+ else if (g_dwWinVer <= _WIN32_WINNT_WS08)
+ {
+ g_TLS_ATTACH = 5;
+ g_DLL_ATTACH = 4;
+ }
+ else if (g_dwWinVer <= _WIN32_WINNT_WIN7)
+ {
+ g_TLS_ATTACH = 3;
+ g_DLL_ATTACH = 2;
+ }
+ else if (g_dwWinVer <= _WIN32_WINNT_WINBLUE)
+ {
+ g_TLS_DETACH = 5;
+ g_DLL_DETACH = 4;
+ }
+
+ ret = GetTempPathW(_countof(workdir), workdir);
+ ok(ret, "GetTempPathW error: %lu\n", GetLastError());
+
+ Length = GetTempFileNameW(workdir, L"ntdll", 0, dllpath);
+ ok(Length != 0, "GetTempFileNameW failed with %lu\n", GetLastError());
+
+ if (extract_resource(dllpath, (LPCWSTR)101))
+ {
+ _SEH2_TRY
+ {
+ execute_test();
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ok(0, "Ldr didnt handle exception\n");
+ }
+ _SEH2_END;
+ }
+ else
+ {
+ ok(0, "Failed to extract resource\n");
+ }
+
+ DeleteFileW(dllpath);
+}
diff --git a/modules/rostests/apitests/ntdll/load_notifications/CMakeLists.txt
b/modules/rostests/apitests/ntdll/load_notifications/CMakeLists.txt
new file mode 100644
index 0000000000..75436635e8
--- /dev/null
+++ b/modules/rostests/apitests/ntdll/load_notifications/CMakeLists.txt
@@ -0,0 +1,6 @@
+
+add_library(load_notifications SHARED load_notifications.c)
+set_module_type(load_notifications win32dll ENTRYPOINT DllMain 12)
+add_importlibs(load_notifications kernel32 ntdll)
+add_dependencies(load_notifications psdk)
+add_rostests_file(TARGET load_notifications)
diff --git a/modules/rostests/apitests/ntdll/load_notifications/load_notifications.c
b/modules/rostests/apitests/ntdll/load_notifications/load_notifications.c
new file mode 100644
index 0000000000..04578fbc43
--- /dev/null
+++ b/modules/rostests/apitests/ntdll/load_notifications/load_notifications.c
@@ -0,0 +1,72 @@
+#define WIN32_NO_STATUS
+#define _INC_WINDOWS
+#define COM_NO_WINDOWS_H
+
+#include <windows.h>
+
+
+#if defined(_MSC_VER)
+#define _CRTALLOC(x) __declspec(allocate(x))
+#elif defined(__GNUC__)
+#define _CRTALLOC(x) __attribute__ ((section (x) ))
+#else
+#error Your compiler is not supported.
+#endif
+
+
+static VOID (WINAPI* pTlsCallback)(IN HINSTANCE hDllHandle, IN DWORD dwReason, IN LPVOID
lpvReserved);
+
+VOID WINAPI
+TlsCallback(IN HANDLE hDllHandle,
+ IN DWORD dwReason,
+ IN LPVOID lpvReserved)
+{
+ if (!pTlsCallback)
+ pTlsCallback = (VOID*)GetProcAddress(NULL, "notify_TlsCallback");
+ if (pTlsCallback)
+ {
+ pTlsCallback(hDllHandle, dwReason, lpvReserved);
+ return;
+ }
+ OutputDebugStringA("WARNING: load_notifications.dll loaded from a process
without notify_TlsCallback\n");
+}
+
+/* Tls magic stolen from sdk/lib/crt/startup/tlssup.c */
+
+#if defined(_MSC_VER)
+#pragma section(".rdata$T",long,read)
+#pragma section(".tls",long,read,write)
+#pragma section(".tls$ZZZ",long,read,write)
+#endif
+
+_CRTALLOC(".tls") char _tls_start = 0;
+_CRTALLOC(".tls$ZZZ") char _tls_end = 0;
+
+PIMAGE_TLS_CALLBACK __xl_a[2] = { &TlsCallback, NULL };
+
+ULONG _tls_index = 0;
+
+_CRTALLOC(".rdata$T") const IMAGE_TLS_DIRECTORY _tls_used = {
+ (ULONG_PTR) &_tls_start+1, (ULONG_PTR) &_tls_end,
+ (ULONG_PTR) &_tls_index, (ULONG_PTR) (__xl_a),
+ (ULONG) 0, (ULONG) 0
+};
+
+
+static BOOL (WINAPI* pDllMain)(IN HINSTANCE hDllHandle, IN DWORD dwReason, IN LPVOID
lpvReserved);
+
+
+BOOL WINAPI
+DllMain(IN HINSTANCE hDllHandle,
+ IN DWORD dwReason,
+ IN LPVOID lpvReserved)
+{
+ if (!pDllMain)
+ pDllMain = (VOID*)GetProcAddress(NULL, "notify_DllMain");
+ if (pDllMain)
+ {
+ return pDllMain(hDllHandle, dwReason, lpvReserved);
+ }
+ OutputDebugStringA("WARNING: load_notifications.dll loaded from a process
without notify_DllMain\n");
+ return TRUE;
+}
diff --git a/modules/rostests/apitests/ntdll/ntdll_apitest.spec
b/modules/rostests/apitests/ntdll/ntdll_apitest.spec
new file mode 100644
index 0000000000..7100a7c7ef
--- /dev/null
+++ b/modules/rostests/apitests/ntdll/ntdll_apitest.spec
@@ -0,0 +1,2 @@
+@ stdcall notify_TlsCallback(ptr long ptr)
+@ stdcall notify_DllMain(ptr long ptr)
diff --git a/modules/rostests/apitests/ntdll/testdata.rc
b/modules/rostests/apitests/ntdll/testdata.rc
new file mode 100644
index 0000000000..3c16769902
--- /dev/null
+++ b/modules/rostests/apitests/ntdll/testdata.rc
@@ -0,0 +1,2 @@
+
+101 10 "load_notifications.dll"
diff --git a/modules/rostests/apitests/ntdll/testlist.c
b/modules/rostests/apitests/ntdll/testlist.c
index c6afd1d342..cd96ef8142 100644
--- a/modules/rostests/apitests/ntdll/testlist.c
+++ b/modules/rostests/apitests/ntdll/testlist.c
@@ -4,6 +4,7 @@
#include <apitest.h>
extern void func_LdrEnumResources(void);
+extern void func_load_notifications(void);
extern void func_NtAcceptConnectPort(void);
extern void func_NtAllocateVirtualMemory(void);
extern void func_NtApphelpCacheControl(void);
@@ -63,6 +64,7 @@ extern void func_TimerResolution(void);
const struct test winetest_testlist[] =
{
{ "LdrEnumResources", func_LdrEnumResources },
+ { "load_notifications", func_load_notifications },
{ "NtAcceptConnectPort", func_NtAcceptConnectPort },
{ "NtAllocateVirtualMemory", func_NtAllocateVirtualMemory },
{ "NtApphelpCacheControl", func_NtApphelpCacheControl },