From: Jinoh Kang Subject: [PATCH v9 1/2] kernel32/tests: Test module refcounting with forwarded exports. Message-Id: <870cb549-e75e-54d7-7e72-4bcee0765d6c@gmail.com> Date: Mon, 24 Jan 2022 00:22:47 +0900 Signed-off-by: Jinoh Kang --- Notes: v3 -> v4: - iatgas.h - LLVM(Clang), ARM, ARM64 support - Use __ASM_NAME macro - Don't fail test on MSVC - Don't end asm macros with "\n\t" v4 -> v5: - iatgas.h - mark idata sections as RO - loader.c - test for forward export itself v5 -> v6: - loader.c - Fix compilation warning in format string v6 -> v7: - forward4.c - fix building without MinGW v7 -> v8: - Also do GetProcAddress for forwarded ordinal exports - forward[1-3].c - Call DisableThreadLibraryCalls in DllMain - forward4.c: removed - iatgas.h: removed - sforward.c: new file - loader.c - test static forwarded import using shlwapi -> userenv forward v8 -> v9: - Test with iprop (documented as an ole32 forwarder in MSDN [1]) [1] https://docs.microsoft.com/en-us/windows/win32/api/coml2api/nf-coml2api-stgopenpropstg dlls/iprop/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 | 182 ++++++++++++++++++++++++++++++ dlls/kernel32/tests/sforward.c | 16 +++ dlls/kernel32/tests/sforward.spec | 1 + 11 files changed, 255 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/iprop/Makefile.in b/dlls/iprop/Makefile.in index e402cd0d4a9..709aebafe14 100644 --- a/dlls/iprop/Makefile.in +++ b/dlls/iprop/Makefile.in @@ -1 +1,2 @@ MODULE = iprop.dll +IMPORTLIB = iprop diff --git a/dlls/kernel32/tests/Makefile.in b/dlls/kernel32/tests/Makefile.in index e9516603ce9..b453269273f 100644 --- a/dlls/kernel32/tests/Makefile.in +++ b/dlls/kernel32/tests/Makefile.in @@ -1,5 +1,7 @@ TESTDLL = kernel32.dll -IMPORTS = user32 advapi32 + +# iprop is for testing export forwarding (to ole32) +IMPORTS = user32 advapi32 iprop 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 + +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 + +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 + +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 f990d632f73..527f9f5157b 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -1642,6 +1642,185 @@ 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 %d\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 ole32, iprop, sforward; + FARPROC test_func_stub; + + if (GetModuleHandleA( "ole32.dll" )) + { + skip("cannot test since ole32.dll is already loaded\n"); + return; + } + if (GetModuleHandleA( "iprop.dll" )) + { + skip("cannot test since iprop.dll is already loaded\n"); + return; + } + + 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 %u\n", + dir_path, GetLastError() ); + + snprintf( sforward_path, MAX_PATH, "%s\\sforward.dll", dir_path ); + extract_resource( "sforward.dll", "TESTDLL", sforward_path ); + + ole32 = LoadLibraryA( "ole32.dll" ); + ok( !!ole32, "couldn't find ole32.dll: %u\n", GetLastError() ); + iprop = LoadLibraryA( "iprop.dll" ); + ok( !!iprop, "couldn't find iprop.dll: %u\n", GetLastError() ); + sforward = LoadLibraryA( sforward_path ); + ok( !!sforward, "couldn't find %s: %u\n", sforward_path, GetLastError() ); + + test_func_stub = GetProcAddress( sforward, "test_func_stub" ); + ok( !!test_func_stub, "sforward!test_func_stub not found\n" ); + + FreeLibrary( ole32 ); + FreeLibrary( iprop ); + + todo_wine + ok( !!GetModuleHandleA( "ole32.dll" ), "ole32.dll unexpectedly unloaded\n" ); + ok( !!GetModuleHandleA( "iprop.dll" ), "iprop.dll unexpectedly unloaded\n" ); + + FreeLibrary( sforward ); + + ok( !GetModuleHandleA( "ole32.dll" ), "ole32.dll unexpectedly kept open\n" ); + ok( !GetModuleHandleA( "iprop.dll" ), "iprop.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 %u\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: %u\n", forward1_path, GetLastError() ); + forward2 = LoadLibraryA( forward2_path ); + ok( !!forward2, "couldn't find %s: %u\n", forward2_path, GetLastError() ); + forward3 = LoadLibraryA( forward3_path ); + ok( !!forward3, "couldn't find %s: %u\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"); + + 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 %u\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: %u\n", forward1_path, GetLastError() ); + forward2 = LoadLibraryA( forward2_path ); + ok( !!forward2, "couldn't find %s: %u\n", forward2_path, GetLastError() ); + forward3 = LoadLibraryA( forward3_path ); + ok( !!forward3, "couldn't find %s: %u\n", forward3_path, GetLastError() ); + + 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 +4298,12 @@ START_TEST(loader) return; } + test_static_forwarded_import_refs(); /* Must be first; other tests may load ole32.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..91865b4834c --- /dev/null +++ b/dlls/kernel32/tests/sforward.c @@ -0,0 +1,16 @@ +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +void test_func_stub(void) +{ + StgOpenPropStg(NULL, NULL, 0, 0, NULL); +} + +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() -- 2.31.1