diff --git a/dll/ntdll/ldr/ldrutils.c b/dll/ntdll/ldr/ldrutils.c index 69e2f8c152e..1c67c8dccd4 100644 --- a/dll/ntdll/ldr/ldrutils.c +++ b/dll/ntdll/ldr/ldrutils.c @@ -2455,6 +2455,7 @@ LdrpLoadDll(IN BOOLEAN Redirected, RtlCopyUnicodeString(&RawDllName, DllName); /* Find the extension, if present */ + /* NOTE: Access violation is expected here in some cases (Buffer[-1]) */ p = DllName->Buffer + DllName->Length / sizeof(WCHAR) - 1; GotExtension = FALSE; while (p >= DllName->Buffer) diff --git a/modules/rostests/apitests/ntdll/CMakeLists.txt b/modules/rostests/apitests/ntdll/CMakeLists.txt index abda236e613..cc4adfac82f 100644 --- a/modules/rostests/apitests/ntdll/CMakeLists.txt +++ b/modules/rostests/apitests/ntdll/CMakeLists.txt @@ -7,6 +7,7 @@ spec2def(ntdll_apitest.exe ntdll_apitest.spec) list(APPEND SOURCE LdrEnumResources.c + LdrLoadDll.c load_notifications.c locale.c NtAcceptConnectPort.c diff --git a/modules/rostests/apitests/ntdll/LdrLoadDll.c b/modules/rostests/apitests/ntdll/LdrLoadDll.c new file mode 100644 index 00000000000..a84a5617771 --- /dev/null +++ b/modules/rostests/apitests/ntdll/LdrLoadDll.c @@ -0,0 +1,201 @@ +/* + * PROJECT: ReactOS API Tests + * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) + * PURPOSE: Test for LdrLoadDll + * COPYRIGHT: Copyright 2017 Thomas Faber + * Copyright 2024 Katayama Hirofumi MZ + */ + +#include "precomp.h" + +/* + +NTSTATUS +NTAPI +LdrLoadDll( + IN PWSTR SearchPath OPTIONAL, + IN PULONG DllCharacteristics OPTIONAL, + IN PUNICODE_STRING DllName, + OUT PVOID *BaseAddress +); + +*/ + +START_TEST(LdrLoadDll) +{ + NTSTATUS Status = STATUS_SUCCESS; + UNICODE_STRING DllName; + PVOID BaseAddress, BaseAddress2; + WCHAR szWinDir[MAX_PATH], szSysDir[MAX_PATH], szPath[MAX_PATH]; + WCHAR *pch; + + RtlInitEmptyUnicodeString(&DllName, NULL, 0); + GetWindowsDirectoryW(szWinDir, _countof(szWinDir)); + GetSystemDirectoryW(szSysDir, _countof(szSysDir)); + + Status = 0xDEADFACE; + StartSeh() + Status = LdrLoadDll(NULL, NULL, &DllName, NULL); + EndSeh(STATUS_ACCESS_VIOLATION); + ok_ntstatus(Status, 0xDEADFACE); + + Status = 0xDEADFACE; + BaseAddress = InvalidPointer; + StartSeh() + Status = LdrLoadDll(NULL, NULL, &DllName, &BaseAddress); + EndSeh(STATUS_ACCESS_VIOLATION); + ok_ntstatus(Status, 0xDEADFACE); + ok_ptr(BaseAddress, InvalidPointer); + + Status = 0xDEADFACE; + StartSeh() + Status = LdrLoadDll(L"", NULL, &DllName, NULL); + EndSeh(STATUS_ACCESS_VIOLATION); + ok_ntstatus(Status, 0xDEADFACE); + + Status = 0xDEADFACE; + BaseAddress = InvalidPointer; + StartSeh() + Status = LdrLoadDll(L"", NULL, &DllName, &BaseAddress); + EndSeh(STATUS_ACCESS_VIOLATION); + ok_ntstatus(Status, 0xDEADFACE); + ok_ptr(BaseAddress, InvalidPointer); + + RtlInitUnicodeString(&DllName, L"advapi32.dll"); + + Status = 0xDEADFACE; + BaseAddress = InvalidPointer; + StartSeh() + Status = LdrLoadDll(NULL, NULL, &DllName, NULL); + if (NT_SUCCESS(Status)) + LdrUnloadDll(BaseAddress); + EndSeh(STATUS_ACCESS_VIOLATION); + ok_ntstatus(Status, 0xDEADFACE); + ok_ptr(BaseAddress, InvalidPointer); + + RtlInitUnicodeString(&DllName, L"advapi32.dll"); + Status = 0xDEADFACE; + BaseAddress = InvalidPointer; + StartSeh() + BaseAddress = InvalidPointer; + Status = LdrLoadDll(NULL, NULL, &DllName, &BaseAddress); + ok_ntstatus(Status, STATUS_SUCCESS); + ok(BaseAddress != NULL && BaseAddress != InvalidPointer, "BaseAddress = %p\n", BaseAddress); + if (NT_SUCCESS(Status)) + { + BaseAddress2 = InvalidPointer; + Status = LdrLoadDll(NULL, NULL, &DllName, &BaseAddress2); + ok_ntstatus(Status, STATUS_SUCCESS); + ok_ptr(BaseAddress2, BaseAddress); + LdrUnloadDll(BaseAddress); + } + EndSeh(STATUS_SUCCESS); + ok_ntstatus(Status, STATUS_SUCCESS); + ok(BaseAddress != NULL, "BaseAddress was NULL\n"); + + RtlInitUnicodeString(&DllName, L"advapi32.dll"); + Status = 0xDEADFACE; + BaseAddress = InvalidPointer; + StartSeh() + Status = LdrLoadDll(L"\\SystemRoot\\System32", NULL, &DllName, NULL); + EndSeh(STATUS_ACCESS_VIOLATION); + ok_ntstatus(Status, 0xDEADFACE); + ok_ptr(BaseAddress, InvalidPointer); + + /* Test with only backslashes in path; no file extension */ + StringCchPrintfW(szPath, _countof(szPath), L"%s\\advapi32", szSysDir); + RtlInitUnicodeString(&DllName, szPath); + Status = 0xDEADFACE; + BaseAddress = InvalidPointer; + StartSeh() + Status = LdrLoadDll(szWinDir, NULL, &DllName, &BaseAddress); + ok_ntstatus(Status, STATUS_SUCCESS); + if (NT_SUCCESS(Status)) + LdrUnloadDll(BaseAddress); + EndSeh(STATUS_SUCCESS); + ok_ntstatus(Status, STATUS_SUCCESS); + ok(BaseAddress != NULL, "BaseAddress was NULL\n"); + + /* Test with only backslashes in path; with file extension */ + StringCchPrintfW(szPath, _countof(szPath), L"%s\\advapi32.dll", szSysDir); + RtlInitUnicodeString(&DllName, szPath); + Status = 0xDEADFACE; + BaseAddress = InvalidPointer; + StartSeh() + Status = LdrLoadDll(szWinDir, NULL, &DllName, &BaseAddress); + ok_ntstatus(Status, STATUS_SUCCESS); + if (NT_SUCCESS(Status)) + LdrUnloadDll(BaseAddress); + EndSeh(STATUS_SUCCESS); + ok_ntstatus(Status, STATUS_SUCCESS); + ok(BaseAddress != NULL, "BaseAddress was NULL\n"); + + /* Test with one forward slash in path; no file extension */ + StringCchPrintfW(szPath, _countof(szPath), L"%s/advapi32", szSysDir); + RtlInitUnicodeString(&DllName, szPath); + Status = 0xDEADFACE; + BaseAddress = InvalidPointer; + StartSeh() + Status = LdrLoadDll(szWinDir, NULL, &DllName, &BaseAddress); + ok_ntstatus(Status, STATUS_SUCCESS); + if (NT_SUCCESS(Status)) + LdrUnloadDll(BaseAddress); + EndSeh(STATUS_SUCCESS); + ok_ntstatus(Status, STATUS_SUCCESS); + ok(BaseAddress != NULL, "BaseAddress was NULL\n"); + + /* Test with one forward slash in path; with file extension */ + StringCchPrintfW(szPath, _countof(szPath), L"%s/advapi32.dll", szSysDir); + RtlInitUnicodeString(&DllName, szPath); + Status = 0xDEADFACE; + BaseAddress = InvalidPointer; + StartSeh() + Status = LdrLoadDll(szWinDir, NULL, &DllName, &BaseAddress); + ok_ntstatus(Status, STATUS_SUCCESS); + if (NT_SUCCESS(Status)) + LdrUnloadDll(BaseAddress); + EndSeh(STATUS_SUCCESS); + ok_ntstatus(Status, STATUS_SUCCESS); + ok(BaseAddress != NULL, "BaseAddress was NULL\n"); + + /* Test with only forward slashes in path; no file extension */ + StringCchPrintfW(szPath, _countof(szPath), L"%s\\advapi32", szSysDir); + for (pch = szPath; *pch != UNICODE_NULL; ++pch) + { + if (*pch == L'\\') + *pch = L'/'; + } + + RtlInitUnicodeString(&DllName, szPath); + Status = 0xDEADFACE; + BaseAddress = InvalidPointer; + StartSeh() + Status = LdrLoadDll(szWinDir, NULL, &DllName, &BaseAddress); + ok_ntstatus(Status, STATUS_SUCCESS); + if (NT_SUCCESS(Status)) + LdrUnloadDll(BaseAddress); + EndSeh(STATUS_SUCCESS); + ok_ntstatus(Status, STATUS_SUCCESS); + ok(BaseAddress != NULL, "BaseAddress was NULL\n"); + + /* Test with only forward slashes in path; with file extension */ + /* Test with only forward slashes in path; with file extension */ + StringCchPrintfW(szPath, _countof(szPath), L"%s\\advapi32.dll", szSysDir); + for (pch = szPath; *pch != UNICODE_NULL; ++pch) + { + if (*pch == L'\\') + *pch = L'/'; + } + + RtlInitUnicodeString(&DllName, szPath); + Status = 0xDEADFACE; + BaseAddress = InvalidPointer; + StartSeh() + Status = LdrLoadDll(szWinDir, NULL, &DllName, &BaseAddress); + ok_ntstatus(Status, STATUS_SUCCESS); + if (NT_SUCCESS(Status)) + LdrUnloadDll(BaseAddress); + EndSeh(STATUS_SUCCESS); + ok_ntstatus(Status, STATUS_SUCCESS); + ok(BaseAddress != NULL, "BaseAddress was NULL\n"); +} diff --git a/modules/rostests/apitests/ntdll/testlist.c b/modules/rostests/apitests/ntdll/testlist.c index f837fa29f8f..10cc0d987da 100644 --- a/modules/rostests/apitests/ntdll/testlist.c +++ b/modules/rostests/apitests/ntdll/testlist.c @@ -4,6 +4,7 @@ #include extern void func_LdrEnumResources(void); +extern void func_LdrLoadDll(void); extern void func_load_notifications(void); extern void func_NtAcceptConnectPort(void); extern void func_NtAccessCheck(void); @@ -106,6 +107,7 @@ extern void func_UserModeException(void); const struct test winetest_testlist[] = { { "LdrEnumResources", func_LdrEnumResources }, + { "LdrLoadDll", func_LdrLoadDll }, { "load_notifications", func_load_notifications }, { "NtAcceptConnectPort", func_NtAcceptConnectPort }, { "NtAccessCheck", func_NtAccessCheck },