Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/kernel32/tests/Makefile.in | 2 + dlls/kernel32/tests/actctx.c | 2 +- dlls/kernel32/tests/loader.c | 579 +++++++++++++++++++++++++++ dlls/kernel32/tests/locking_dll.c | 50 +++ dlls/kernel32/tests/locking_dll.spec | 1 + 5 files changed, 633 insertions(+), 1 deletion(-) create mode 100644 dlls/kernel32/tests/locking_dll.c create mode 100644 dlls/kernel32/tests/locking_dll.spec
diff --git a/dlls/kernel32/tests/Makefile.in b/dlls/kernel32/tests/Makefile.in index e9516603ce9..be3a8fc8dfa 100644 --- a/dlls/kernel32/tests/Makefile.in +++ b/dlls/kernel32/tests/Makefile.in @@ -21,6 +21,8 @@ SOURCES = \ heap.c \ loader.c \ locale.c \ + locking_dll.c \ + locking_dll.spec \ mailslot.c \ module.c \ path.c \ diff --git a/dlls/kernel32/tests/actctx.c b/dlls/kernel32/tests/actctx.c index 163ea405222..f37796a6aba 100644 --- a/dlls/kernel32/tests/actctx.c +++ b/dlls/kernel32/tests/actctx.c @@ -2584,7 +2584,7 @@ static void delete_manifest_file(const char *filename) DeleteFileA(path); }
-static void extract_resource(const char *name, const char *type, const char *path) +void extract_resource(const char *name, const char *type, const char *path) { DWORD written; HANDLE file; diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index 4f1b11338a6..df530055db4 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -70,6 +70,10 @@ static NTSTATUS (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG *, ULONG_PTR *); static NTSTATUS (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG_PTR); static NTSTATUS (WINAPI *pLdrLoadDll)(LPCWSTR,DWORD,const UNICODE_STRING *,HMODULE*); static NTSTATUS (WINAPI *pLdrUnloadDll)(HMODULE); + +typedef void (CALLBACK *LDRENUMPROC)(LDR_DATA_TABLE_ENTRY *, void *, BOOLEAN *); +static NTSTATUS (WINAPI *pLdrEnumerateLoadedModules)( void *unknown, LDRENUMPROC callback, void *context ); + static void (WINAPI *pRtlInitUnicodeString)(PUNICODE_STRING,LPCWSTR); static void (WINAPI *pRtlAcquirePebLock)(void); static void (WINAPI *pRtlReleasePebLock)(void); @@ -88,6 +92,8 @@ static BOOL (WINAPI *pWow64DisableWow64FsRedirection)(void **); static BOOL (WINAPI *pWow64RevertWow64FsRedirection)(void *); static HMODULE (WINAPI *pLoadPackagedLibrary)(LPCWSTR lpwLibFileName, DWORD Reserved);
+void extract_resource(const char *name, const char *type, const char *path); + static PVOID RVAToAddr(DWORD_PTR rva, HMODULE module) { if (rva == 0) @@ -4036,6 +4042,574 @@ static void test_Wow64Transition(void) debugstr_wn(name->SectionFileName.Buffer, name->SectionFileName.Length / sizeof(WCHAR))); }
+static BOOL test_loader_lock_repeat_lock; +static DWORD test_loader_lock_expected_wait_result; +static unsigned int test_loader_notification_count; +static unsigned int test_loader_expected_notification_count; +static const WCHAR *ldr_notify_track_dll; +static HMODULE lock_dll_handle; +static HANDLE lock_ready_event, next_test_event; +static BOOL test_loader_lock_test_failed; +static volatile LONG test_loader_lock_timeout_count; + +#define BLOCKING_TESTS_ENABLED 1 + +static void CALLBACK test_loader_lock_module_enum_locking_callback(LDR_DATA_TABLE_ENTRY *mod, + void *context, BOOLEAN *stop) +{ + DWORD *result = context; + + SetEvent(lock_ready_event); + *result = WaitForSingleObject(next_test_event, 3000); + *stop = TRUE; +} + +static void CALLBACK test_loader_lock_dummy_callback(LDR_DATA_TABLE_ENTRY *mod, + void *context, BOOLEAN *stop) +{ + *stop = TRUE; +} + +static void CALLBACK test_loader_lock_ldr_notify_locking(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context) +{ + DWORD *result = context; + NTSTATUS status; + HMODULE hmodule; + void *cookie; + BOOL bret; + + if (reason != LDR_DLL_NOTIFICATION_REASON_UNLOADED) return; + + status = LdrRegisterDllNotification(0, test_loader_lock_ldr_notify_locking, NULL, &cookie); + ok(!status, "Got unexpected status %#x.\n", status); + status = LdrUnregisterDllNotification( cookie ); + ok(!status, "Got unexpected status %#x.\n", status); + + hmodule = LoadLibraryW(L"winmm.dll"); + ok(!!hmodule, "GetModuleHandleW failed, err %u.\n", GetLastError()); + bret = FreeLibrary(hmodule); + ok(bret, "FreeLibrary failed, err %u.\n", GetLastError()); + + bret = GetModuleHandleExW(0, L"lock.dll", &hmodule); + ok(bret, "GetModuleHandleExW failed, err %u.\n", GetLastError()); + ok(!!hmodule, "GetModuleHandleW failed, err %u.\n", GetLastError()); + bret = FreeLibrary(hmodule); + ok(bret, "FreeLibrary failed, err %u.\n", GetLastError()); + + hmodule = LoadLibraryW(L"authz.dll"); + ok(!hmodule, "LoadLibraryW succeeded.\n"); + ok(GetLastError() == ERROR_NOT_FOUND, "Got unexpected error %u.\n", GetLastError()); + + status = pLdrEnumerateLoadedModules(NULL, test_loader_lock_dummy_callback, NULL); + ok(!status, "Got unexpected status %#x.\n", status); + + SetEvent(lock_ready_event); + *result = WaitForSingleObject(next_test_event, 3000); +} + +static DWORD WINAPI test_loader_lock_thread(void *param) +{ + static const WCHAR env_var[] = L"test_wait_reason_value"; + void (WINAPI *p_set_lock_result_addr)( DWORD *addr ); + unsigned int test, iter; + ULONG_PTR magic; + NTSTATUS status; + HMODULE hmodule; + void *cookie; + DWORD result; + WCHAR str[8]; + BOOL bret; + + WaitForSingleObject(next_test_event, INFINITE); + + test = 1; + /* 1. Test with loader lock held. */ + iter = 0; + do + { + status = pLdrLockLoaderLock(0, NULL, &magic); + ok(!status, "Got unexpected status %#x.\n", status); + SetEvent(lock_ready_event); + + result = WaitForSingleObject(next_test_event, 3000); + + if (!iter && result == WAIT_TIMEOUT) + { + /* First test timed out, likely the old loader. */ + test_loader_lock_test_failed = TRUE; + status = pLdrUnlockLoaderLock(0, magic); + ok(!status, "Got unexpected status %#x.\n", status); + SetEvent(lock_ready_event); + return 0; + } + + ok(result == test_loader_lock_expected_wait_result, + "Got unexpected wait result %#x, expected %#x, test %u.%u.\n", + result, test_loader_lock_expected_wait_result, test, iter); + + todo_wine_if(test && iter == 1) + ok(test_loader_notification_count == test_loader_expected_notification_count, + "Got unexpected notification count %u, expected %u, test %u.%u.\n", + test_loader_notification_count, test_loader_expected_notification_count, test, iter); + + status = pLdrUnlockLoaderLock(0, magic); + ok(!status, "Got unexpected status %#x.\n", status); + + if (result == WAIT_TIMEOUT) + WaitForSingleObject(next_test_event, INFINITE); + ++iter; + } while (test_loader_lock_repeat_lock); + + SetEvent(lock_ready_event); + WaitForSingleObject(next_test_event, INFINITE); + /* 2. Test with the thread blocked in DLL entry point during process attach. */ + swprintf(str, ARRAY_SIZE(str), L"%u", DLL_PROCESS_ATTACH); + bret = SetEnvironmentVariableW(env_var, str); + ok(bret, "SetEnvironmentVariableW failed.\n"); + ++test; + iter = 0; + do + { + hmodule = LoadLibraryA("lock.dll"); + ok(!!hmodule, "LoadLibrary failed, err %u.\n", GetLastError()); + p_set_lock_result_addr = (void *)GetProcAddress(hmodule, "set_lock_result_addr"); + p_set_lock_result_addr(&result); + + if (result == WAIT_TIMEOUT) + InterlockedIncrement(&test_loader_lock_timeout_count); + + bret = FreeLibrary(hmodule); + ok(bret, "FreeLibrary failed, err %u.\n", GetLastError()); + + ok(result == test_loader_lock_expected_wait_result, + "Got unexpected wait result %#x, expected %#x, test %u.%u.\n", + result, test_loader_lock_expected_wait_result, test, iter); + + if (result == WAIT_TIMEOUT) + WaitForSingleObject(next_test_event, INFINITE); + ++iter; + } while (test_loader_lock_repeat_lock); + + SetEvent(lock_ready_event); + WaitForSingleObject(next_test_event, INFINITE); + + /* 3. Test with the thread blocked in DLL entry point during process detach. */ + swprintf(str, ARRAY_SIZE(str), L"%u", DLL_PROCESS_DETACH); + bret = SetEnvironmentVariableW(env_var, str); + ok(bret, "SetEnvironmentVariableW failed.\n"); + ++test; + iter = 0; + do + { + lock_dll_handle = hmodule = LoadLibraryA("lock.dll"); + ok(!!hmodule, "LoadLibrary failed, err %u.\n", GetLastError()); + p_set_lock_result_addr = (void *)GetProcAddress(hmodule, "set_lock_result_addr"); + ok(!!p_set_lock_result_addr, "Got NULL p_set_lock_result_addr.\n"); + p_set_lock_result_addr(&result); + bret = FreeLibrary(hmodule); + ok(bret, "FreeLibrary failed, err %u.\n", GetLastError()); + + lock_dll_handle = NULL; + + if (result == WAIT_TIMEOUT) + InterlockedIncrement(&test_loader_lock_timeout_count); + + ok(result == test_loader_lock_expected_wait_result, + "Got unexpected wait result %#x, expected %#x, test %u.%u.\n", + result, test_loader_lock_expected_wait_result, test, iter); + + if (result == WAIT_TIMEOUT) + WaitForSingleObject(next_test_event, INFINITE); + ++iter; + } while (test_loader_lock_repeat_lock); + + SetEvent(lock_ready_event); + WaitForSingleObject(next_test_event, INFINITE); + + /* 4. Test with the thread blocked in LdrEnumerateLoadedModules callback. */ + ++test; + iter = 0; + do + { + pLdrEnumerateLoadedModules(NULL, test_loader_lock_module_enum_locking_callback, &result); + + if (result == WAIT_TIMEOUT) + InterlockedIncrement(&test_loader_lock_timeout_count); + + ok(result == test_loader_lock_expected_wait_result, + "Got unexpected wait result %#x, expected %#x, test %u.%u.\n", + result, test_loader_lock_expected_wait_result, test, iter); + ok(test_loader_notification_count == test_loader_expected_notification_count, + "Got unexpected notification count %u, expected %u, test %u.%u.\n", + test_loader_notification_count, test_loader_expected_notification_count, test, iter); + + if (result == WAIT_TIMEOUT) + WaitForSingleObject(next_test_event, INFINITE); + ++iter; + } while (test_loader_lock_repeat_lock); + + SetEvent(lock_ready_event); + WaitForSingleObject(next_test_event, INFINITE); + + /* 5. Test with the thread blocked in LDR notification callback. */ + LdrRegisterDllNotification(0, test_loader_lock_ldr_notify_locking, &result, &cookie); + /* lock.dll will return FALSE from the DLL entry point. */ + bret = SetEnvironmentVariableW(env_var, L"-1"); + ok(bret, "SetEnvironmentVariableW failed.\n"); + + ++test; + iter = 0; + do + { + hmodule = LoadLibraryA("lock.dll"); + ok(!!hmodule, "LoadLibrary failed, err %u.\n", GetLastError()); + bret = FreeLibrary(hmodule); + ok(bret, "FreeLibrary failed, err %u.\n", GetLastError()); + + if (result == WAIT_TIMEOUT) + InterlockedIncrement(&test_loader_lock_timeout_count); + + ok(result == test_loader_lock_expected_wait_result, + "Got unexpected wait result %#x, expected %#x, test %u.%u.\n", + result, test_loader_lock_expected_wait_result, test, iter); + ok(test_loader_notification_count == test_loader_expected_notification_count, + "Got unexpected notification count %u, expected %u, test %u.%u.\n", + test_loader_notification_count, test_loader_expected_notification_count, test, iter); + + if (result == WAIT_TIMEOUT) + WaitForSingleObject(next_test_event, INFINITE); + ++iter; + } while (test_loader_lock_repeat_lock); + LdrUnregisterDllNotification( cookie ); + SetEvent(lock_ready_event); + return 0; +} + +static void CALLBACK test_loader_lock_ldr_notify(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context) +{ + if (!lstrcmpW(data->Loaded.BaseDllName->Buffer, ldr_notify_track_dll)) + ++test_loader_notification_count; +} + +static void CALLBACK test_loader_lock_enum_callback(LDR_DATA_TABLE_ENTRY *mod, void *context, BOOLEAN *stop) +{ + *stop = TRUE; +} + +static void test_loader_lock(void) +{ +#define CHECK ok(!test_loader_lock_timeout_count, "Got timeout count %d.\n", test_loader_lock_timeout_count) + static const WCHAR not_loaded_dll_name[] = L"authz.dll"; + static const WCHAR preloaded_dll_name[] = L"winmm.dll"; + HMODULE hmodule_preloaded, hmodule; + ULONG_PTR magic; + NTSTATUS status; + HANDLE thread; + void *cookie; + void *proc; + BOOL bret; + + extract_resource("locking_dll.dll", "TESTDLL", "lock.dll"); + + lock_ready_event = CreateEventA(NULL, FALSE, FALSE, "test_lock_ready_event"); + next_test_event = CreateEventA(NULL, FALSE, FALSE, "test_next_test_event"); + + thread = CreateThread(NULL, 0, test_loader_lock_thread, NULL, 0, NULL); + + hmodule_preloaded = LoadLibraryW(preloaded_dll_name); + ok(!!hmodule_preloaded, "LoadLibrary failed, err %u.\n", GetLastError()); + hmodule = GetModuleHandleW(not_loaded_dll_name); + ok(!hmodule, "%s is already loaded.\n", not_loaded_dll_name); + + test_loader_notification_count = 0; + + /* 1. Test with loader lock held. */ + trace("Test 1.\n"); + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + test_loader_lock_expected_wait_result = WAIT_OBJECT_0; + + status = LdrRegisterDllNotification(0, test_loader_lock_ldr_notify, NULL, &cookie); + ok(!status, "Got unexpected status %#x.\n", status); + CHECK; + ldr_notify_track_dll = not_loaded_dll_name; + + bret = GetModuleHandleExW(0, preloaded_dll_name, &hmodule); + ok(bret, "GetModuleHandleEx failed, err %u.\n", GetLastError()); + ok(hmodule == hmodule_preloaded, "Got unexpected hmodule %p, expected %p.\n", hmodule, hmodule_preloaded); + CHECK; + + bret = FreeLibrary(hmodule); + ok(bret, "FreeLibrary failed, err %u.\n", GetLastError()); + CHECK; + + ok(!test_loader_notification_count, "Got unexpected test_loader_notification_count %u.\n", test_loader_notification_count); + + if (BLOCKING_TESTS_ENABLED) + { + CHECK; + test_loader_lock_repeat_lock = TRUE; + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + + if (test_loader_lock_test_failed) + { + win_skip("Old loader, tests skipped.\n"); + goto done; + } + + /* With loader lock held notification callback is called which should mean that: + * - LDR notifications themselves do not wait on loader lock; + * - The library load goes far enough to call the LDR notification until it blocks on the loader lock. + */ + test_loader_expected_notification_count = 1; + test_loader_lock_expected_wait_result = WAIT_TIMEOUT; + hmodule = LoadLibraryW(not_loaded_dll_name); + ok(!!hmodule, "LoadLibrary failed, err %u.\n", GetLastError()); + + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + + test_loader_notification_count = 0; + test_loader_expected_notification_count = 0; + bret = FreeLibrary(hmodule); + ok(bret, "FreeLibrary failed, err %u.\n", GetLastError()); + + ok(test_loader_notification_count == 1, "Got unexpected notification count %u, expected %u.\n", + test_loader_notification_count, 1); + test_loader_notification_count = 0; + test_loader_expected_notification_count = 0; + + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + pLdrEnumerateLoadedModules(NULL, test_loader_lock_enum_callback, NULL); + + test_loader_lock_repeat_lock = FALSE; + } + + LdrUnregisterDllNotification( cookie ); + + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + + if (test_loader_lock_test_failed) + { + win_skip("Old loader, tests skipped.\n"); + goto done; + } + + /* 2. Test with the thread blocked in DLL entry point during process attach. */ + trace("Test 2.\n"); + SetEvent(next_test_event); + + WaitForSingleObject(lock_ready_event, INFINITE); + test_loader_lock_expected_wait_result = WAIT_OBJECT_0; + + status = LdrRegisterDllNotification(0, test_loader_lock_ldr_notify, NULL, &cookie); + ok(!status, "Got unexpected status %#x.\n", status); + CHECK; + + bret = GetModuleHandleExW(0, preloaded_dll_name, &hmodule); + CHECK; + ok(bret, "GetModuleHandleEx failed, err %u.\n", GetLastError()); + ok(hmodule == hmodule_preloaded, "Got unexpected hmodule %p, expected %p.\n", hmodule, hmodule_preloaded); + + proc = GetProcAddress(hmodule, "timeGetTime"); + CHECK; + ok(!!proc, "GetProcAddress failed.\n"); + + bret = FreeLibrary(hmodule); + CHECK; + ok(bret, "FreeLibrary failed, err %u.\n", GetLastError()); + + hmodule = GetModuleHandleA("lock.dll"); + CHECK; + ok(!!hmodule, "GetModuleHandleA failed, err %u.\n", GetLastError()); + + bret = GetModuleHandleExW(0, L"lock.dll", &hmodule); + CHECK; + ok(bret, "GetModuleHandleEx failed, err %u.\n", GetLastError()); + + lock_dll_handle = hmodule; + + status = LdrAddRefDll(0, hmodule); + CHECK; + ok(!status, "Got unexpected status %#x.\n", status); + + bret = FreeLibrary(hmodule); + CHECK; + ok(bret, "FreeLibrary failed, err %u.\n", GetLastError()); + + bret = FreeLibrary(hmodule); + CHECK; + ok(bret, "FreeLibrary failed, err %u.\n", GetLastError()); + + hmodule = LoadLibraryW(preloaded_dll_name); + CHECK; + ok(!!hmodule, "LoadLibrary failed, err %u.\n", GetLastError()); + + bret = FreeLibrary(hmodule); + CHECK; + ok(bret, "FreeLibrary failed, err %u.\n", GetLastError()); + + if (BLOCKING_TESTS_ENABLED) + { + test_loader_lock_repeat_lock = TRUE; + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + + test_loader_lock_expected_wait_result = WAIT_TIMEOUT; + + ok(!!lock_dll_handle, "Got NULL lock_dll_handle.\n"); + proc = GetProcAddress(lock_dll_handle, "unknown"); + ok(!proc, "GetProcAddress succeeded.\n"); + + test_loader_lock_repeat_lock = FALSE; + } + + LdrUnregisterDllNotification( cookie ); + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + /* 3. Test with the thread blocked in DLL entry point during process detach. */ + trace("Test 3.\n"); + + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + test_loader_lock_timeout_count = 0; + test_loader_lock_expected_wait_result = WAIT_OBJECT_0; + + status = LdrRegisterDllNotification(0, test_loader_lock_ldr_notify, NULL, &cookie); + ok(!status, "Got unexpected status %#x.\n", status); + CHECK; + + bret = GetModuleHandleExW(0, preloaded_dll_name, &hmodule); + ok(bret, "GetModuleHandleEx failed, err %u.\n", GetLastError()); + ok(hmodule == hmodule_preloaded, "Got unexpected hmodule %p, expected %p.\n", hmodule, hmodule_preloaded); + CHECK; + + proc = GetProcAddress(hmodule, "timeGetTime"); + ok(!!proc, "GetProcAddress failed.\n"); + CHECK; + + bret = FreeLibrary(hmodule); + ok(bret, "FreeLibrary failed, err %u.\n", GetLastError()); + CHECK; + + ok(!!lock_dll_handle, "Got NULL lock_dll_handle.\n"); + + proc = GetProcAddress(lock_dll_handle, "set_lock_result_addr"); + CHECK; + + ok(!proc, "GetProcAddress failed, err %u.\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Got unexpected error %u.\n", GetLastError()); + + status = LdrAddRefDll(0, lock_dll_handle); + CHECK; + ok(status == STATUS_DLL_NOT_FOUND, "Got unexpected status %#x.\n", status); + + if (BLOCKING_TESTS_ENABLED) + { + test_loader_lock_repeat_lock = TRUE; + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + + test_loader_lock_expected_wait_result = WAIT_TIMEOUT; + hmodule = GetModuleHandleW(L"lock.dll"); + ok(!hmodule, "GetModuleHandleW succeeded.\n", GetLastError()); + ok(GetLastError() == ERROR_MOD_NOT_FOUND, "Got unexpected error %u.\n", GetLastError()); + test_loader_lock_repeat_lock = FALSE; + } + + LdrUnregisterDllNotification( cookie ); + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + + /* 4. Test with the thread blocked in LdrEnumerateLoadedModules callback. */ + trace("Test 4.\n"); + + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + test_loader_lock_timeout_count = 0; + test_loader_lock_expected_wait_result = WAIT_OBJECT_0; + + status = LdrRegisterDllNotification(0, test_loader_lock_ldr_notify, NULL, &cookie); + ok(!status, "Got unexpected status %#x.\n", status); + CHECK; + + hmodule = GetModuleHandleW(preloaded_dll_name); + ok(!!hmodule, "LoadLibrary failed, err %u.\n", GetLastError()); + CHECK; + + if (BLOCKING_TESTS_ENABLED) + { + test_loader_lock_repeat_lock = TRUE; + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + + test_loader_lock_expected_wait_result = WAIT_TIMEOUT; + + status = pLdrLockLoaderLock(0, NULL, &magic); + ok(!status, "Got unexpected status %#x.\n", status); + status = pLdrUnlockLoaderLock(0, magic); + ok(!status, "Got unexpected status %#x.\n", status); + + test_loader_lock_repeat_lock = FALSE; + } + + LdrUnregisterDllNotification( cookie ); + + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + + /* 5. Test with the thread blocked in LDR notification callback. */ + trace("Test 5.\n"); + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + + test_loader_lock_timeout_count = 0; + test_loader_lock_expected_wait_result = WAIT_OBJECT_0; + + hmodule = GetModuleHandleW(preloaded_dll_name); + ok(!!hmodule, "LoadLibrary failed, err %u.\n", GetLastError()); + CHECK; + + if (BLOCKING_TESTS_ENABLED) + { + test_loader_lock_repeat_lock = TRUE; + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + test_loader_lock_expected_wait_result = WAIT_TIMEOUT; + + status = LdrRegisterDllNotification(0, test_loader_lock_ldr_notify, NULL, &cookie); + ok(!status, "Got unexpected status %#x.\n", status); + LdrUnregisterDllNotification( cookie ); + + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + + /* This doesn't block in load notifications on Windows, only unload. */ + status = pLdrLockLoaderLock(0, NULL, &magic); + ok(!status, "Got unexpected status %#x.\n", status); + status = pLdrUnlockLoaderLock(0, magic); + ok(!status, "Got unexpected status %#x.\n", status); + + test_loader_lock_repeat_lock = FALSE; + } + + SetEvent(next_test_event); + WaitForSingleObject(lock_ready_event, INFINITE); + + + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + +done: + DeleteFileA("lock.dll"); + FreeLibrary(hmodule_preloaded); + CloseHandle(lock_ready_event); + CloseHandle(next_test_event); +} + START_TEST(loader) { int argc; @@ -4060,6 +4634,7 @@ START_TEST(loader) pLdrUnlockLoaderLock = (void *)GetProcAddress(ntdll, "LdrUnlockLoaderLock"); pLdrLoadDll = (void *)GetProcAddress(ntdll, "LdrLoadDll"); pLdrUnloadDll = (void *)GetProcAddress(ntdll, "LdrUnloadDll"); + pLdrEnumerateLoadedModules = (void *)GetProcAddress(ntdll, "LdrEnumerateLoadedModules"); pRtlInitUnicodeString = (void *)GetProcAddress(ntdll, "RtlInitUnicodeString"); pRtlAcquirePebLock = (void *)GetProcAddress(ntdll, "RtlAcquirePebLock"); pRtlReleasePebLock = (void *)GetProcAddress(ntdll, "RtlReleasePebLock"); @@ -4099,6 +4674,7 @@ START_TEST(loader) return; }
+if(0){ test_filenames(); test_ResolveDelayLoadedAPI(); test_ImportDescriptors(); @@ -4113,6 +4689,9 @@ START_TEST(loader) test_dll_file( "advapi32.dll" ); test_dll_file( "user32.dll" ); test_Wow64Transition(); +} + test_loader_lock(); +return; /* loader test must be last, it can corrupt the internal loader state on Windows */ test_Loader(); } diff --git a/dlls/kernel32/tests/locking_dll.c b/dlls/kernel32/tests/locking_dll.c new file mode 100644 index 00000000000..31aff05fe84 --- /dev/null +++ b/dlls/kernel32/tests/locking_dll.c @@ -0,0 +1,50 @@ +#include <stdarg.h> +#include <stdlib.h> +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" + +static DWORD last_lock_result, *lock_result_addr; + +BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, LPVOID reserved ) +{ + HANDLE lock_ready_event, next_test_event; + DWORD wait_reason; + NTSTATUS status; + char str[8]; + + GetEnvironmentVariableA("test_wait_reason_value", str, sizeof(str)); + wait_reason = atoi(str); + + if (reason != wait_reason) return TRUE; + + lock_ready_event = OpenEventA(EVENT_ALL_ACCESS, FALSE, "test_lock_ready_event"); + next_test_event = OpenEventA(EVENT_ALL_ACCESS, FALSE, "test_next_test_event"); + + SetEvent( lock_ready_event ); + last_lock_result = WaitForSingleObject(next_test_event, 2000); + + if (0) + { + if (reason == DLL_PROCESS_DETACH) + { + status = LdrAddRefDll(0, instance); + if (status) last_lock_result = ~0u; + status = LdrAddRefDll(LDR_ADDREF_DLL_PIN, instance); + if (status != STATUS_UNSUCCESSFUL) last_lock_result = ~0u - 1; + } + } + if (lock_result_addr) *lock_result_addr = last_lock_result; + + CloseHandle(lock_ready_event); + CloseHandle(next_test_event); + return TRUE; +} + +void WINAPI set_lock_result_addr( DWORD *addr ) +{ + lock_result_addr = addr; + *addr = last_lock_result; +} diff --git a/dlls/kernel32/tests/locking_dll.spec b/dlls/kernel32/tests/locking_dll.spec new file mode 100644 index 00000000000..327515590c3 --- /dev/null +++ b/dlls/kernel32/tests/locking_dll.spec @@ -0,0 +1 @@ +@ stdcall set_lock_result_addr(ptr)