[PATCH v8 1/2] kernel32/tests: Test module refcounting with forwarded exports.

Jinoh Kang jinoh.kang.kr at gmail.com
Wed Jan 19 11:00:51 CST 2022


Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
---

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

 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    |  16 +++
 dlls/kernel32/tests/sforward.spec |   1 +
 10 files changed, 249 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/kernel32/tests/Makefile.in b/dlls/kernel32/tests/Makefile.in
index e9516603ce9..1f8dd3b86a0 100644
--- a/dlls/kernel32/tests/Makefile.in
+++ b/dlls/kernel32/tests/Makefile.in
@@ -1,5 +1,7 @@
 TESTDLL   = kernel32.dll
-IMPORTS   = user32 advapi32
+
+# shlwapi is for testing export forwarding (to userenv)
+IMPORTS   = user32 advapi32 shlwapi
 
 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 f990d632f73..1efd5a7fa5d 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 %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 userenv, shlwapi, sforward;
+    FARPROC test_func_stub;
+
+    if (GetModuleHandleA( "userenv.dll" ))
+    {
+        skip("cannot test since userenv.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 );
+
+    userenv = LoadLibraryA( "userenv.dll" );
+    ok( !!userenv, "couldn't find userenv.dll: %u\n", GetLastError() );
+    shlwapi = LoadLibraryA( "shlwapi.dll" );
+    ok( !!shlwapi, "couldn't find shlwapi.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( userenv );
+    FreeLibrary( shlwapi );
+
+    todo_wine
+    ok( !!GetModuleHandleA( "userenv.dll" ), "userenv.dll unexpectedly unloaded\n" );
+    ok( !!GetModuleHandleA( "shlwapi.dll" ), "shlwapi.dll unexpectedly unloaded\n" );
+
+    FreeLibrary( sforward );
+
+    ok( !GetModuleHandleA( "userenv.dll" ), "userenv.dll unexpectedly kept open\n" );
+    ok( !GetModuleHandleA( "shlwapi.dll" ), "shlwapi.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 +4293,12 @@ START_TEST(loader)
         return;
     }
 
+    test_static_forwarded_import_refs();  /* Must be first; other tests may load userenv.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..17f79fb5a74
--- /dev/null
+++ b/dlls/kernel32/tests/sforward.c
@@ -0,0 +1,16 @@
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+DECLSPEC_IMPORT BOOL WINAPI SHExpandEnvironmentStringsForUserW(HANDLE,LPCWSTR,LPWSTR,DWORD);
+
+void test_func_stub(void)
+{
+    SHExpandEnvironmentStringsForUserW(NULL, NULL, NULL, 0);
+}
+
+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




More information about the wine-devel mailing list