This serie: - fixes a couple of tests failures on Windows 11 (Note: there are still other issues under Windows 11, mostly addressed by MR!2252) - introduce a couple of helpers to simplify current and yet to come test code - improves some existing tests
From: Eric Pouech eric.pouech@gmail.com
Since this API sporadically fails with STATUS_INFO_LENGTH_MISMATCH as GetLastError() (sic!) on Windows 11, retrying the call let us get the relevant output.
No clear explanation of the cause of the failure, it's maybe generated when modules are still loaded into child process and it detects modification of the modules' list while enumerating all modules.
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/dbghelp/tests/dbghelp.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index 618ee6e8cdb..04833e28dc7 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windows.h" #include "psapi.h" #include "verrsrc.h" @@ -308,6 +310,24 @@ static BOOL CALLBACK nth_module_cb(const char* name, DWORD64 base, void* usr) return FALSE; }
+/* wrapper around EnumerateLoadedModuleW64 which sometimes fails for unknown reasons on Win11, + * with STATUS_INFO_LENGTH_MISMATCH as GetLastError()! + */ +static BOOL wrapper_EnumerateLoadedModulesW64(HANDLE proc, PENUMLOADED_MODULES_CALLBACKW64 cb, void* usr) +{ + BOOL ret; + int retry; + + for (retry = !strcmp(winetest_platform, "wine") ? 1 : 5; retry >= 0; retry--) + { + ret = EnumerateLoadedModulesW64(proc, cb, usr); + if (ret || GetLastError() != STATUS_INFO_LENGTH_MISMATCH) + break; + Sleep(10); + } + return ret; +} + static BOOL test_modules(void) { BOOL ret; @@ -600,7 +620,7 @@ static void test_loaded_modules(void) memset(&aggregation, 0, sizeof(aggregation)); aggregation.proc = pi.hProcess;
- ret = EnumerateLoadedModulesW64(pi.hProcess, aggregate_cb, &aggregation); + ret = wrapper_EnumerateLoadedModulesW64(pi.hProcess, aggregate_cb, &aggregation); ok(ret, "EnumerateLoadedModulesW64 failed: %lu\n", GetLastError());
if (is_win64) @@ -649,7 +669,7 @@ static void test_loaded_modules(void) memset(&aggregation, 0, sizeof(aggregation)); aggregation.proc = pi.hProcess;
- ret = EnumerateLoadedModulesW64(pi.hProcess, aggregate_cb, &aggregation); + ret = wrapper_EnumerateLoadedModulesW64(pi.hProcess, aggregate_cb, &aggregation); ok(ret, "EnumerateLoadedModulesW64 failed: %lu\n", GetLastError());
todo_wine @@ -687,7 +707,7 @@ static void test_loaded_modules(void) ok(ret, "SymInitialize failed: %lu\n", GetLastError()); memset(&aggregation2, 0, sizeof(aggregation2)); aggregation2.proc = pi.hProcess; - ret = EnumerateLoadedModulesW64(pi.hProcess, aggregate_cb, &aggregation2); + ret = wrapper_EnumerateLoadedModulesW64(pi.hProcess, aggregate_cb, &aggregation2); ok(ret, "EnumerateLoadedModulesW64 failed: %lu\n", GetLastError());
ok(aggregation2.count_32bit && aggregation2.count_64bit, "Wrong bitness aggregation count %u %u\n",
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54535 --- dlls/dbghelp/tests/dbghelp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index 04833e28dc7..34df4dd437b 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -285,7 +285,7 @@ struct nth_module { HANDLE proc; unsigned int index; - BOOL will_fail; + BOOL could_fail; IMAGEHLP_MODULE64 module; };
@@ -297,9 +297,10 @@ static BOOL CALLBACK nth_module_cb(const char* name, DWORD64 base, void* usr) if (nth->index--) return TRUE; nth->module.SizeOfStruct = sizeof(nth->module); ret = SymGetModuleInfo64(nth->proc, base, &nth->module); - if (nth->will_fail) + if (nth->could_fail) { - ok(!ret, "SymGetModuleInfo64 should have failed\n"); + /* Windows11 succeeds into loading the overlapped module */ + ok(!ret || broken(base == nth->module.BaseOfImage), "SymGetModuleInfo64 should have failed\n"); nth->module.BaseOfImage = base; } else @@ -497,7 +498,7 @@ static void test_modules_overlap(void) } ok(nth.index == -1, "Expecting more modules\n"); ok(nth.module.BaseOfImage == tests[i].outputs[j].base, "Wrong base\n"); - if (!nth.will_fail) + if (!nth.could_fail) { ok(nth.module.ImageSize == tests[i].outputs[j].size, "Wrong size\n"); ok(!strcasecmp(nth.module.ModuleName, tests[i].outputs[j].name), "Wrong name\n");
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/dbghelp/tests/dbghelp.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index 34df4dd437b..576a25200dd 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -196,6 +196,14 @@ static void test_search_path(void) ok(!strcmp(search_path, "."), "Got search path '%s', expected '.'\n", search_path); }
+static BOOL ends_withW(const WCHAR* str, const WCHAR* suffix) +{ + size_t strlen = wcslen(str); + size_t sfxlen = wcslen(suffix); + + return strlen >= sfxlen && !wcsicmp(str + strlen - sfxlen, suffix); +} + static USHORT get_module_machine(const char* path) { HANDLE hFile, hMap; @@ -541,18 +549,15 @@ static BOOL CALLBACK aggregate_cb(PCWSTR imagename, DWORD64 base, ULONG sz, PVOI { struct loaded_module_aggregation* aggregation = usr; IMAGEHLP_MODULEW64 im; - size_t image_len; BOOL ret, wow64; WCHAR buffer[MAX_PATH];
memset(&im, 0, sizeof(im)); im.SizeOfStruct = sizeof(im);
- image_len = wcslen(imagename); - ret = SymGetModuleInfoW64(aggregation->proc, base, &im); if (ret) - ok(aggregation->count_exe && image_len >= 4 && !wcscmp(imagename + image_len - 4, L".exe"), + ok(aggregation->count_exe && ends_withW(imagename, L".exe"), "%ls shouldn't already be loaded\n", imagename); else { @@ -581,7 +586,7 @@ static BOOL CALLBACK aggregate_cb(PCWSTR imagename, DWORD64 base, ULONG sz, PVOI ok(0, "Unsupported machine %lx\n", im.MachineType); break; } - if (image_len >= 4 && !wcsicmp(imagename + image_len - 4, L".exe")) + if (ends_withW(imagename, L".exe")) aggregation->count_exe++; if (!wcsicmp(im.ModuleName, L"ntdll")) aggregation->count_ntdll++;
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/dbghelp/tests/dbghelp.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index 576a25200dd..0c95a2a6206 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -26,6 +26,8 @@ #include "winternl.h"
static const BOOL is_win64 = sizeof(void*) > sizeof(int); +static WCHAR system_directory[MAX_PATH]; +static WCHAR wow64_directory[MAX_PATH];
#if defined(__i386__) || defined(__x86_64__)
@@ -550,7 +552,6 @@ static BOOL CALLBACK aggregate_cb(PCWSTR imagename, DWORD64 base, ULONG sz, PVOI struct loaded_module_aggregation* aggregation = usr; IMAGEHLP_MODULEW64 im; BOOL ret, wow64; - WCHAR buffer[MAX_PATH];
memset(&im, 0, sizeof(im)); im.SizeOfStruct = sizeof(im); @@ -590,12 +591,10 @@ static BOOL CALLBACK aggregate_cb(PCWSTR imagename, DWORD64 base, ULONG sz, PVOI aggregation->count_exe++; if (!wcsicmp(im.ModuleName, L"ntdll")) aggregation->count_ntdll++; - if (GetSystemDirectoryW(buffer, ARRAY_SIZE(buffer)) && - !wcsnicmp(imagename, buffer, wcslen(buffer))) + if (!wcsnicmp(imagename, system_directory, wcslen(system_directory))) aggregation->count_systemdir++; if (is_win64 && IsWow64Process(aggregation->proc, &wow64) && wow64 && - GetSystemWow64DirectoryW(buffer, ARRAY_SIZE(buffer)) && - !wcsnicmp(imagename, buffer, wcslen(buffer))) + !wcsnicmp(imagename, wow64_directory, wcslen(wow64_directory))) aggregation->count_wowdir++;
return TRUE; @@ -756,6 +755,12 @@ START_TEST(dbghelp) ret = SymCleanup(GetCurrentProcess()); ok(ret, "got error %lu\n", GetLastError());
+ ret = GetSystemDirectoryW(system_directory, ARRAY_SIZE(system_directory)); + ok(ret, "GetSystemDirectoryW failed: %lu\n", GetLastError()); + /* failure happens on a 32bit only wine setup */ + if (!GetSystemWow64DirectoryW(wow64_directory, ARRAY_SIZE(wow64_directory))) + wow64_directory[0] = L'\0'; + if (test_modules()) { test_modules_overlap();
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/dbghelp/tests/dbghelp.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index 0c95a2a6206..c5b04b7dd7f 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -206,6 +206,23 @@ static BOOL ends_withW(const WCHAR* str, const WCHAR* suffix) return strlen >= sfxlen && !wcsicmp(str + strlen - sfxlen, suffix); }
+static unsigned get_machine_bitness(USHORT machine) +{ + switch (machine) + { + case IMAGE_FILE_MACHINE_I386: + case IMAGE_FILE_MACHINE_ARM: + case IMAGE_FILE_MACHINE_ARMNT: + return 32; + case IMAGE_FILE_MACHINE_AMD64: + case IMAGE_FILE_MACHINE_ARM64: + return 64; + default: + ok(0, "Unsupported machine %x\n", machine); + return 0; + } +} + static USHORT get_module_machine(const char* path) { HANDLE hFile, hMap; @@ -570,22 +587,11 @@ static BOOL CALLBACK aggregate_cb(PCWSTR imagename, DWORD64 base, ULONG sz, PVOI ok(ret, "SymGetModuleInfoW64 failed: %lu\n", GetLastError()); }
- switch (im.MachineType) + switch (get_machine_bitness(im.MachineType)) { - case IMAGE_FILE_MACHINE_UNKNOWN: - break; - case IMAGE_FILE_MACHINE_I386: - case IMAGE_FILE_MACHINE_ARM: - case IMAGE_FILE_MACHINE_ARMNT: - aggregation->count_32bit++; - break; - case IMAGE_FILE_MACHINE_AMD64: - case IMAGE_FILE_MACHINE_ARM64: - aggregation->count_64bit++; - break; - default: - ok(0, "Unsupported machine %lx\n", im.MachineType); - break; + case 32: aggregation->count_32bit++; break; + case 64: aggregation->count_64bit++; break; + default: break; } if (ends_withW(imagename, L".exe")) aggregation->count_exe++;
From: Eric Pouech eric.pouech@gmail.com
Introduce get_process_kind() to discriminate configurations.
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/dbghelp/tests/dbghelp.c | 65 +++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 4 deletions(-)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index c5b04b7dd7f..3a0ad20dadd 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -553,6 +553,46 @@ static void test_modules_overlap(void) } }
+enum process_kind +{ + PCSKIND_ERROR, + PCSKIND_64BIT, /* 64 bit process */ + PCSKIND_32BIT, /* 32 bit only configuration (Wine, some Win 7...) */ + PCSKIND_WINE_OLD_WOW64, /* Wine "old" wow64 configuration */ + PCSKIND_WOW64, /* Wine "new" wow64 configuration, and Windows with wow64 support */ +}; + +static enum process_kind get_process_kind(HANDLE process) +{ + const BOOL is_win64 = sizeof(void*) == 8; + USHORT m1, m2; + + if (!IsWow64Process2(process, &m1, &m2)) return PCSKIND_ERROR; + if (m1 == IMAGE_FILE_MACHINE_UNKNOWN && get_machine_bitness(m2) == 32) return PCSKIND_32BIT; + if (m1 == IMAGE_FILE_MACHINE_UNKNOWN && get_machine_bitness(m2) == 64) return PCSKIND_64BIT; + if (get_machine_bitness(m1) == 32 && get_machine_bitness(m2) == 64) + { + enum process_kind pcskind = PCSKIND_WOW64; + if (!strcmp(winetest_platform, "wine")) + { + PROCESS_BASIC_INFORMATION pbi; + PEB32 peb32; + const char* peb_addr; + + if (NtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL)) + return PCSKIND_ERROR; + + peb_addr = (const char*)pbi.PebBaseAddress; + if (is_win64) peb_addr += 0x1000; + if (!ReadProcessMemory(process, peb_addr, &peb32, sizeof(peb32), NULL)) return PCSKIND_ERROR; + if (*(const DWORD*)((const char*)&peb32 + 0x460 /* CloudFileFlags */)) + pcskind = PCSKIND_WINE_OLD_WOW64; + } + return pcskind; + } + return PCSKIND_ERROR; +} + struct loaded_module_aggregation { HANDLE proc; @@ -599,7 +639,7 @@ static BOOL CALLBACK aggregate_cb(PCWSTR imagename, DWORD64 base, ULONG sz, PVOI aggregation->count_ntdll++; if (!wcsnicmp(imagename, system_directory, wcslen(system_directory))) aggregation->count_systemdir++; - if (is_win64 && IsWow64Process(aggregation->proc, &wow64) && wow64 && + if (IsWow64Process(aggregation->proc, &wow64) && wow64 && !wcsnicmp(imagename, wow64_directory, wcslen(wow64_directory))) aggregation->count_wowdir++;
@@ -653,9 +693,26 @@ static void test_loaded_modules(void) aggregation.count_32bit, aggregation.count_64bit); ok(aggregation.count_exe == 1 && aggregation.count_ntdll == 1, "Wrong kind aggregation count %u %u\n", aggregation.count_exe, aggregation.count_ntdll); - todo_wine_if(is_wow64) - ok(aggregation.count_systemdir > 2 && !aggregation.count_wowdir, "Wrong directory aggregation count %u %u\n", - aggregation.count_systemdir, aggregation.count_wowdir); + switch (get_process_kind(pi.hProcess)) + { + case PCSKIND_ERROR: + ok(0, "Unknown process kind\n"); + break; + case PCSKIND_64BIT: + case PCSKIND_WOW64: + todo_wine + ok(aggregation.count_systemdir > 2 && aggregation.count_wowdir == 1, "Wrong directory aggregation count %u %u\n", + aggregation.count_systemdir, aggregation.count_wowdir); + break; + case PCSKIND_32BIT: + ok(aggregation.count_systemdir > 2 && aggregation.count_wowdir == 0, "Wrong directory aggregation count %u %u\n", + aggregation.count_systemdir, aggregation.count_wowdir); + break; + case PCSKIND_WINE_OLD_WOW64: + ok(aggregation.count_systemdir == 1 && aggregation.count_wowdir > 2, "Wrong directory aggregation count %u %u\n", + aggregation.count_systemdir, aggregation.count_wowdir); + break; + } }
SymCleanup(pi.hProcess);