Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com
-- v2: kernel32/tests: Test module refcounting with forwarded exports.
From: Jinoh Kang jinoh.kang.kr@gmail.com
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- dlls/icmp/Makefile.in | 1 + dlls/kernel32/tests/Makefile.in | 14 ++- dlls/kernel32/tests/forward1.c | 19 ++++ dlls/kernel32/tests/forward1.spec | 2 + dlls/kernel32/tests/forward2.c | 9 ++ dlls/kernel32/tests/forward2.spec | 2 + dlls/kernel32/tests/forward3.c | 9 ++ dlls/kernel32/tests/forward3.spec | 2 + dlls/kernel32/tests/loader.c | 177 ++++++++++++++++++++++++++++++ dlls/kernel32/tests/sforward.c | 18 +++ dlls/kernel32/tests/sforward.spec | 1 + 11 files changed, 252 insertions(+), 2 deletions(-) create mode 100644 dlls/kernel32/tests/forward1.c create mode 100644 dlls/kernel32/tests/forward1.spec create mode 100644 dlls/kernel32/tests/forward2.c create mode 100644 dlls/kernel32/tests/forward2.spec create mode 100644 dlls/kernel32/tests/forward3.c create mode 100644 dlls/kernel32/tests/forward3.spec create mode 100644 dlls/kernel32/tests/sforward.c create mode 100644 dlls/kernel32/tests/sforward.spec
diff --git a/dlls/icmp/Makefile.in b/dlls/icmp/Makefile.in index 93213ab130b..c21eac39cf9 100644 --- a/dlls/icmp/Makefile.in +++ b/dlls/icmp/Makefile.in @@ -1,3 +1,4 @@ MODULE = icmp.dll +IMPORTLIB = icmp
EXTRADLLFLAGS = -Wb,--data-only diff --git a/dlls/kernel32/tests/Makefile.in b/dlls/kernel32/tests/Makefile.in index e9516603ce9..67775e78a83 100644 --- a/dlls/kernel32/tests/Makefile.in +++ b/dlls/kernel32/tests/Makefile.in @@ -1,5 +1,7 @@ TESTDLL = kernel32.dll -IMPORTS = user32 advapi32 + +# icmp is for testing export forwarding (to iphlpapi) +IMPORTS = user32 advapi32 icmp
SOURCES = \ actctx.c \ @@ -37,4 +39,12 @@ SOURCES = \ toolhelp.c \ version.c \ virtual.c \ - volume.c + volume.c \ + forward1.c \ + forward1.spec \ + forward2.c \ + forward2.spec \ + forward3.c \ + forward3.spec \ + sforward.c \ + sforward.spec diff --git a/dlls/kernel32/tests/forward1.c b/dlls/kernel32/tests/forward1.c new file mode 100644 index 00000000000..6419d95eaea --- /dev/null +++ b/dlls/kernel32/tests/forward1.c @@ -0,0 +1,19 @@ +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +BOOL WINAPI DllMain(HINSTANCE instance_new, DWORD reason, LPVOID reserved) +{ + if (reason == DLL_PROCESS_ATTACH) + DisableThreadLibraryCalls( instance_new ); + return TRUE; +} + +unsigned long forward_test_func(void) +{ + return 0x00005678UL; +} + +unsigned long forward_test_func2(void) +{ + return 0x12340000UL; +} diff --git a/dlls/kernel32/tests/forward1.spec b/dlls/kernel32/tests/forward1.spec new file mode 100644 index 00000000000..bf19fa7e011 --- /dev/null +++ b/dlls/kernel32/tests/forward1.spec @@ -0,0 +1,2 @@ +1 cdecl forward_test_func() +2 cdecl -noname forward_test_func2() diff --git a/dlls/kernel32/tests/forward2.c b/dlls/kernel32/tests/forward2.c new file mode 100644 index 00000000000..d1e77f45f3c --- /dev/null +++ b/dlls/kernel32/tests/forward2.c @@ -0,0 +1,9 @@ +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +BOOL WINAPI DllMain(HINSTANCE instance_new, DWORD reason, LPVOID reserved) +{ + if (reason == DLL_PROCESS_ATTACH) + DisableThreadLibraryCalls( instance_new ); + return TRUE; +} diff --git a/dlls/kernel32/tests/forward2.spec b/dlls/kernel32/tests/forward2.spec new file mode 100644 index 00000000000..374156d8d06 --- /dev/null +++ b/dlls/kernel32/tests/forward2.spec @@ -0,0 +1,2 @@ +1 cdecl forward_test_func() forward1.forward_test_func +2 cdecl -noname forward_test_func2() forward1.#2 diff --git a/dlls/kernel32/tests/forward3.c b/dlls/kernel32/tests/forward3.c new file mode 100644 index 00000000000..d1e77f45f3c --- /dev/null +++ b/dlls/kernel32/tests/forward3.c @@ -0,0 +1,9 @@ +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +BOOL WINAPI DllMain(HINSTANCE instance_new, DWORD reason, LPVOID reserved) +{ + if (reason == DLL_PROCESS_ATTACH) + DisableThreadLibraryCalls( instance_new ); + return TRUE; +} diff --git a/dlls/kernel32/tests/forward3.spec b/dlls/kernel32/tests/forward3.spec new file mode 100644 index 00000000000..31d019aa071 --- /dev/null +++ b/dlls/kernel32/tests/forward3.spec @@ -0,0 +1,2 @@ +1 cdecl forward_test_func() forward2.forward_test_func +2 cdecl -noname forward_test_func2() forward2.#2 diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index 365f4465fc7..5d8e57141e0 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -1642,6 +1642,180 @@ static void test_ImportDescriptors(void) } }
+static void extract_resource(const char *name, const char *type, const char *path) +{ + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + file = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %lu\n", path, GetLastError()); + + res = FindResourceA(NULL, name, type); + ok( res != 0, "couldn't find resource\n" ); + ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res )); + WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL ); + ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" ); + CloseHandle( file ); +} + +static void test_static_forwarded_import_refs(void) +{ + CHAR temp_path[MAX_PATH], dir_path[MAX_PATH], sforward_path[MAX_PATH]; + HMODULE iphlpapi, icmp, sforward; + FARPROC test_func_stub; + + ok( !GetModuleHandleA( "iphlpapi.dll" ), "iphlpapi.dll shall not have already been loaded\n" ); + ok( !GetModuleHandleA( "icmp.dll" ), "icmp.dll shall not have already been loaded\n" ); + + GetTempPathA( ARRAY_SIZE(temp_path), temp_path ); + GetTempFileNameA( temp_path, "ldr", GetTickCount() | 1UL, dir_path ); + ok( CreateDirectoryA( dir_path, NULL ), "failed to create dir %s, error %lu\n", + dir_path, GetLastError() ); + + snprintf( sforward_path, MAX_PATH, "%s\sforward.dll", dir_path ); + extract_resource( "sforward.dll", "TESTDLL", sforward_path ); + + iphlpapi = LoadLibraryA( "iphlpapi.dll" ); + ok( !!iphlpapi, "couldn't find iphlpapi.dll: %lu\n", GetLastError() ); + icmp = LoadLibraryA( "icmp.dll" ); + ok( !!icmp, "couldn't find icmp.dll: %lu\n", GetLastError() ); + sforward = LoadLibraryA( sforward_path ); + ok( !!sforward, "couldn't find %s: %lu\n", sforward_path, GetLastError() ); + + test_func_stub = GetProcAddress( sforward, "test_func_stub" ); + ok( !!test_func_stub, "sforward!test_func_stub not found\n" ); + + /* When a DLL imports a forwarded export, the loader introduces a module + * dependency from the importer DLL to the target DLL of the forwarded + * export. This keeps iphlpapi and icmp from being unloaded. + */ + FreeLibrary( iphlpapi ); + FreeLibrary( icmp ); + todo_wine + ok( !!GetModuleHandleA( "iphlpapi.dll" ), "iphlpapi.dll unexpectedly unloaded\n" ); + ok( !!GetModuleHandleA( "icmp.dll" ), "icmp.dll unexpectedly unloaded\n" ); + + FreeLibrary( sforward ); + ok( !GetModuleHandleA( "iphlpapi.dll" ), "iphlpapi.dll unexpectedly kept open\n" ); + ok( !GetModuleHandleA( "icmp.dll" ), "icmp.dll unexpectedly kept open\n" ); + ok( !GetModuleHandleA( "sforward.dll" ), "sforward.dll unexpectedly kept open\n" ); + + DeleteFileA( sforward_path ); + RemoveDirectoryA( dir_path ); +} + +static void test_dynamic_forwarded_import_refs(void) +{ + CHAR temp_path[MAX_PATH], dir_path[MAX_PATH]; + CHAR forward1_path[MAX_PATH]; + CHAR forward2_path[MAX_PATH]; + CHAR forward3_path[MAX_PATH]; + HMODULE forward1, forward2, forward3; + FARPROC proc1, proc2, proc3, oproc1, oproc2, oproc3; + + GetTempPathA( ARRAY_SIZE(temp_path), temp_path ); + GetTempFileNameA( temp_path, "ldr", GetTickCount() | 1UL, dir_path ); + ok( CreateDirectoryA( dir_path, NULL ), "failed to create dir %s, error %lu\n", + dir_path, GetLastError() ); + + snprintf( forward1_path, MAX_PATH, "%s\forward1.dll", dir_path ); + snprintf( forward2_path, MAX_PATH, "%s\forward2.dll", dir_path ); + snprintf( forward3_path, MAX_PATH, "%s\forward3.dll", dir_path ); + extract_resource( "forward1.dll", "TESTDLL", forward1_path ); + extract_resource( "forward2.dll", "TESTDLL", forward2_path ); + extract_resource( "forward3.dll", "TESTDLL", forward3_path ); + + forward1 = LoadLibraryA( forward1_path ); + ok( !!forward1, "couldn't find %s: %lu\n", forward1_path, GetLastError() ); + forward2 = LoadLibraryA( forward2_path ); + ok( !!forward2, "couldn't find %s: %lu\n", forward2_path, GetLastError() ); + forward3 = LoadLibraryA( forward3_path ); + ok( !!forward3, "couldn't find %s: %lu\n", forward3_path, GetLastError() ); + + proc1 = GetProcAddress(forward1, "forward_test_func"); + ok( !!proc1, "cannot resolve forward1!forward_test_func\n"); + proc2 = GetProcAddress(forward2, "forward_test_func"); + ok( !!proc2, "cannot resolve forward2!forward_test_func\n"); + proc3 = GetProcAddress(forward3, "forward_test_func"); + ok( !!proc3, "cannot resolve forward3!forward_test_func\n"); + ok( proc1 == proc3, "forward1!forward_test_func is not equal to forward3!forward_test_func\n"); + ok( proc2 == proc3, "forward2!forward_test_func is not equal to forward3!forward_test_func\n"); + + oproc1 = GetProcAddress(forward1, (LPSTR)2); + ok( !!oproc1, "cannot resolve forward1!#2 (forward_test_func2)\n"); + oproc2 = GetProcAddress(forward2, (LPSTR)2); + ok( !!oproc2, "cannot resolve forward2!#2 (forward_test_func2)\n"); + oproc3 = GetProcAddress(forward3, (LPSTR)2); + ok( !!oproc3, "cannot resolve forward3!#2 (forward_test_func2)\n"); + ok( oproc1 == oproc3, "forward1!forward_test_func2 is not equal to forward3!forward_test_func2\n"); + ok( oproc2 == oproc3, "forward2!forward_test_func2 is not equal to forward3!forward_test_func2\n"); + + /* GetProcAddress, when called on a forwarded export, has a side effect of + * introducing a module dependency from the source forwarder DLL to the + * target DLL. This keeps forward1 and forward2 from being unloaded. + */ + FreeLibrary( forward1 ); + FreeLibrary( forward2 ); + todo_wine + ok( !!GetModuleHandleA( "forward1.dll" ), "forward1.dll unexpectedly unloaded\n" ); + todo_wine + ok( !!GetModuleHandleA( "forward2.dll" ), "forward2.dll unexpectedly unloaded\n" ); + + FreeLibrary( forward3 ); + ok( !GetModuleHandleA( "forward1.dll" ), "forward1.dll unexpectedly kept open\n" ); + ok( !GetModuleHandleA( "forward2.dll" ), "forward2.dll unexpectedly kept open\n" ); + ok( !GetModuleHandleA( "forward3.dll" ), "forward3.dll unexpectedly kept open\n" ); + + DeleteFileA( forward1_path ); + DeleteFileA( forward2_path ); + DeleteFileA( forward3_path ); + RemoveDirectoryA( dir_path ); +} + +static void test_dynamic_forward_export_norefs(void) +{ + CHAR temp_path[MAX_PATH], dir_path[MAX_PATH]; + CHAR forward1_path[MAX_PATH]; + CHAR forward2_path[MAX_PATH]; + CHAR forward3_path[MAX_PATH]; + HMODULE forward1, forward2, forward3; + + GetTempPathA( ARRAY_SIZE(temp_path), temp_path ); + GetTempFileNameA( temp_path, "ldr", GetTickCount() | 1UL, dir_path ); + ok( CreateDirectoryA( dir_path, NULL ), "failed to create dir %s, error %lu\n", + dir_path, GetLastError() ); + + snprintf( forward1_path, MAX_PATH, "%s\forward1.dll", dir_path ); + snprintf( forward2_path, MAX_PATH, "%s\forward2.dll", dir_path ); + snprintf( forward3_path, MAX_PATH, "%s\forward3.dll", dir_path ); + extract_resource( "forward1.dll", "TESTDLL", forward1_path ); + extract_resource( "forward2.dll", "TESTDLL", forward2_path ); + extract_resource( "forward3.dll", "TESTDLL", forward3_path ); + + forward1 = LoadLibraryA( forward1_path ); + ok( !!forward1, "couldn't find %s: %lu\n", forward1_path, GetLastError() ); + forward2 = LoadLibraryA( forward2_path ); + ok( !!forward2, "couldn't find %s: %lu\n", forward2_path, GetLastError() ); + forward3 = LoadLibraryA( forward3_path ); + ok( !!forward3, "couldn't find %s: %lu\n", forward3_path, GetLastError() ); + + /* The mere existence of a forwarded export shall not count as a reference by itself. */ + FreeLibrary( forward1 ); + FreeLibrary( forward3 ); + ok( !GetModuleHandleA( "forward1.dll" ), "forward1.dll unexpectedly kept open\n" ); + ok( !GetModuleHandleA( "forward3.dll" ), "forward3.dll unexpectedly kept open\n" ); + + FreeLibrary( forward2 ); + ok( !GetModuleHandleA( "forward2.dll" ), "forward2.dll unexpectedly kept open\n" ); + + DeleteFileA( forward1_path ); + DeleteFileA( forward2_path ); + DeleteFileA( forward3_path ); + RemoveDirectoryA( dir_path ); +} + static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL is_dll) { HANDLE hfile, hmap; @@ -4119,9 +4293,12 @@ START_TEST(loader) return; }
+ test_static_forwarded_import_refs(); /* Must be first; other tests may load iphlpapi.dll */ test_filenames(); test_ResolveDelayLoadedAPI(); test_ImportDescriptors(); + test_dynamic_forwarded_import_refs(); + test_dynamic_forward_export_norefs(); test_section_access(); test_import_resolution(); test_ExitProcess(); diff --git a/dlls/kernel32/tests/sforward.c b/dlls/kernel32/tests/sforward.c new file mode 100644 index 00000000000..e632f69efb1 --- /dev/null +++ b/dlls/kernel32/tests/sforward.c @@ -0,0 +1,18 @@ +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <ws2tcpip.h> +#include <iphlpapi.h> +#include <icmpapi.h> + +void test_func_stub(void) +{ + HANDLE file = IcmpCreateFile(); + if (file != INVALID_HANDLE_VALUE) IcmpCloseHandle( file ); +} + +BOOL WINAPI DllMain(HINSTANCE instance_new, DWORD reason, LPVOID reserved) +{ + if (reason == DLL_PROCESS_ATTACH) + DisableThreadLibraryCalls( instance_new ); + return TRUE; +} diff --git a/dlls/kernel32/tests/sforward.spec b/dlls/kernel32/tests/sforward.spec new file mode 100644 index 00000000000..cb6d4add796 --- /dev/null +++ b/dlls/kernel32/tests/sforward.spec @@ -0,0 +1 @@ +@ cdecl test_func_stub()
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=118094
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
kernel32: debugger.c:1027: Test failed: ole32.dll was not reported
=== w7u_adm (32 bit report) ===
kernel32: debugger.c:1027: Test failed: ole32.dll was not reported
=== w7u_el (32 bit report) ===
kernel32: debugger.c:1027: Test failed: ole32.dll was not reported
=== w1064 (32 bit report) ===
kernel32: debugger.c:447: Test failed: unexpected thread debugger.c:450: Test failed: dwDebugEventCode = 2 debugger.c:451: Test failed: ExceptionCode = 580 debugger.c:453: Test failed: ExceptionAddress != DbgBreakPoint debugger.c:466: Test failed: dwDebugEventCode = 1
=== w10pro64 (32 bit report) ===
kernel32: debugger.c:447: Test failed: unexpected thread debugger.c:450: Test failed: dwDebugEventCode = 2 debugger.c:451: Test failed: ExceptionCode = 5f8 debugger.c:453: Test failed: ExceptionAddress != DbgBreakPoint debugger.c:466: Test failed: dwDebugEventCode = 1 debugger.c:1217: Test failed: dwDebugEventCode = 4 debugger.c:1223: Test failed: dwDebugEventCode = 4 debugger.c:1225: Test failed: ExceptionCode = 0 debugger.c:1244: Test failed: dwDebugEventCode = 1 debugger.c:161: Test failed: wrong size for 'C:\Users\winetest\AppData\Local\Temp\wtBDAD.tmp': read=0 debugger.c:1166: Test failed: unexpected event pid
=== w1064v1809 (32 bit report) ===
kernel32: loader.c:1669: Test failed: iphlpapi.dll shall not have already been loaded loader.c:1701: Test failed: iphlpapi.dll unexpectedly kept open
=== w10pro64_ja (64 bit report) ===
kernel32: loader.c:691: Test failed: 1490: got test dll but expected fallback