[PATCH v41 0/2] MR10291: Fix GetModuleFileName string termination
After Windows XP the string termination behavior of GetModuleFileName was changed to always terminate the path returned, even if the buffer is insufficient to contain the null terminator. -- v41: kernel32: Fix string termination of GetModuleFileName https://gitlab.winehq.org/wine/wine/-/merge_requests/10291
From: Trent Waddington <trent.waddington@tensorworks.com.au> --- dlls/kernel32/tests/loader.c | 90 ++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index 529b9de870d..8547e79bf26 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -1552,6 +1552,94 @@ static void test_filenames(void) DeleteFileA( long_path ); } +static void test_getmodulefilenamew_string_termination(void) +{ + WCHAR dll_name[MAX_PATH]; + int dll_name_len, dll_name_term; + DWORD rv, err; + HMODULE mod; + + GetModuleFileNameW(NULL, dll_name, MAX_PATH); + err = GetLastError(); + ok(err == ERROR_SUCCESS, "error getting path for NULL module: %d\n", (int)err); + dll_name_len = wcslen(dll_name); + ok(dll_name_len > 0, "can't get path for NULL module\n"); + ok(dll_name_len < MAX_PATH, "unterminated path for NULL module\n"); + + memset(dll_name, '*', sizeof(dll_name)); + rv = GetModuleFileNameW(NULL, dll_name, dll_name_len); + err = GetLastError(); + ok(err == ERROR_INSUFFICIENT_BUFFER, "didn't get expected error getting path for NULL module with short buffer: %d\n", (int)err); + dll_name_term = wcsnlen(dll_name, MAX_PATH); + ok(dll_name_term > 0, "can't get path for NULL module with short buffer, dll_name_term=%d\n", dll_name_term); + ok(dll_name_term < MAX_PATH, "unterminated path for NULL module with short buffer, dll_name_term=%d\n", dll_name_term); + ok(dll_name_term == dll_name_len - 1, "incorrect path termination for NULL module with short buffer. Expected %d got %d. rv=%d\n", dll_name_len - 1, dll_name_term, (int)rv); + + mod = LoadLibraryW( L"user32.dll" ); + ok(mod != NULL, "can't load test dll\n"); + GetModuleFileNameW(mod, dll_name, MAX_PATH); + err = GetLastError(); + ok(err == ERROR_SUCCESS, "error getting path for test module: %d\n", (int)err); + dll_name_len = wcslen(dll_name); + ok(dll_name_len > 0, "can't get path for test module\n"); + ok(dll_name_len < MAX_PATH, "unterminated path for test module\n"); + + memset(dll_name, '*', sizeof(dll_name)); + GetModuleFileNameW(mod, dll_name, dll_name_len); + err = GetLastError(); + ok(err == ERROR_INSUFFICIENT_BUFFER, "didn't get expected error getting path for test module with short buffer: %d\n", (int)err); + dll_name_term = wcsnlen(dll_name, MAX_PATH); + ok(dll_name_term > 0, "can't get path for test module with short buffer, dll_name_term=%d\n", dll_name_term); + ok(dll_name_term < MAX_PATH, "unterminated path for test module with short buffer, dll_name_term=%d\n", dll_name_term); + ok(dll_name_term == dll_name_len - 1, "incorrect path termination for test module with short buffer. Expected %d got %d\n", dll_name_len - 1, dll_name_term); + + FreeLibrary( mod ); +} + +static void test_getmodulefilenamea_string_termination(void) +{ + char dll_name[MAX_PATH]; + int dll_name_len, dll_name_term; + DWORD rv, err; + HMODULE mod; + + GetModuleFileNameA(NULL, dll_name, MAX_PATH); + err = GetLastError(); + ok(err == ERROR_SUCCESS, "error getting path for NULL module: %d\n", (int)err); + dll_name_len = strlen(dll_name); + ok(dll_name_len > 0, "can't get path for NULL module\n"); + ok(dll_name_len < MAX_PATH, "unterminated path for NULL module\n"); + + memset(dll_name, '*', sizeof(dll_name)); + rv = GetModuleFileNameA(NULL, dll_name, dll_name_len); + err = GetLastError(); + ok(err == ERROR_INSUFFICIENT_BUFFER, "didn't get expected error getting path for NULL module with short buffer: %d\n", (int)err); + dll_name_term = strnlen(dll_name, MAX_PATH); + ok(dll_name_term > 0, "can't get path for NULL module with short buffer, dll_name_term=%d\n", dll_name_term); + ok(dll_name_term < MAX_PATH, "unterminated path for NULL module with short buffer, dll_name_term=%d\n", dll_name_term); + ok(dll_name_term == dll_name_len - 1, "incorrect path termination for NULL module with short buffer. Expected %d got %d. rv=%d\n", dll_name_len - 1, dll_name_term, (int)rv); + + mod = LoadLibraryA( "user32.dll" ); + ok(mod != NULL, "can't load test dll\n"); + GetModuleFileNameA(mod, dll_name, MAX_PATH); + err = GetLastError(); + ok(err == ERROR_SUCCESS, "error getting path for test module: %d\n", (int)err); + dll_name_len = strlen(dll_name); + ok(dll_name_len > 0, "can't get path for test module\n"); + ok(dll_name_len < MAX_PATH, "unterminated path for test module\n"); + + memset(dll_name, '*', sizeof(dll_name)); + GetModuleFileNameA(mod, dll_name, dll_name_len); + err = GetLastError(); + ok(err == ERROR_INSUFFICIENT_BUFFER, "didn't get expected error getting path for test module with short buffer: %d\n", (int)err); + dll_name_term = strnlen(dll_name, MAX_PATH); + ok(dll_name_term > 0, "can't get path for test module with short buffer, dll_name_term=%d\n", dll_name_term); + ok(dll_name_term < MAX_PATH, "unterminated path for test module with short buffer, dll_name_term=%d\n", dll_name_term); + ok(dll_name_term == dll_name_len - 1, "incorrect path termination for test module with short buffer. Expected %d got %d\n", dll_name_len - 1, dll_name_term); + + FreeLibrary( mod ); +} + /* Verify linking style of import descriptors */ static void test_ImportDescriptors(void) { @@ -4859,6 +4947,8 @@ START_TEST(loader) } test_filenames(); + test_getmodulefilenamew_string_termination(); + test_getmodulefilenamea_string_termination(); test_ResolveDelayLoadedAPI(); test_ImportDescriptors(); test_section_access(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10291
From: Trent Waddington <trent.waddington@tensorworks.com.au> --- dlls/kernelbase/loader.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dlls/kernelbase/loader.c b/dlls/kernelbase/loader.c index f4e1ca2e23a..e26a08ccca5 100644 --- a/dlls/kernelbase/loader.c +++ b/dlls/kernelbase/loader.c @@ -302,13 +302,12 @@ DWORD WINAPI DECLSPEC_HOTPATCH GetModuleFileNameW( HMODULE module, LPWSTR filena ULONG len = 0; WIN16_SUBSYSTEM_TIB *win16_tib; UNICODE_STRING name; - NTSTATUS status; + NTSTATUS status = 0; if (!module && ((win16_tib = NtCurrentTeb()->Tib.SubSystemTib)) && win16_tib->exe_name) { len = min( size, win16_tib->exe_name->Length / sizeof(WCHAR) ); memcpy( filename, win16_tib->exe_name->Buffer, len * sizeof(WCHAR) ); - if (len < size) filename[len] = 0; goto done; } @@ -319,6 +318,13 @@ DWORD WINAPI DECLSPEC_HOTPATCH GetModuleFileNameW( HMODULE module, LPWSTR filena SetLastError( RtlNtStatusToDosError( status )); done: TRACE( "%s\n", debugstr_wn(filename, len) ); + if (!status || status == STATUS_BUFFER_TOO_SMALL) + { + if (len < size) + filename[len] = 0; + else if (size > 0) + filename[size - 1] = 0; + } return len; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10291
participants (2)
-
Trent Waddington -
Trent Waddington (@trent.waddington)