From 0d3ba090724ee59bb83f4df4092dffd887dd8032 Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Tue, 29 Sep 2020 18:41:00 +0200 Subject: [PATCH] Fix g_module_symbol() under Windows sometimes not succeeding g_module_symbol() internally calls CreateToolhelp32Snapshot() which in some circumstances returns ERROR_BAD_LENGTH and according to the docs should lead to CreateToolhelp32Snapshot() being retried by the caller. This retry logic was missing and for example led to g_module_symbol() not succeeding if another thread happened to call the wrong function at the wrong time. This got noticed in the g-i build of gtk4 where g-i would call g_module_symbol() on all gtk4 _get_type symbols and while inspecting the properties gtk4 would spawn a thread calling SHGetSpecialFolderLocation() somewhere down the line. During the call to SHGetSpecialFolderLocation() CreateToolhelp32Snapshot() would return with ERROR_BAD_LENGTH for a short period of time and make g_module_symbol() fail, which lead to "Invalid GType function" errors in g-i. Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/3213 --- gmodule/gmodule-win32.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/gmodule/gmodule-win32.c b/gmodule/gmodule-win32.c index fef4d893d..2aea8bae9 100644 --- a/gmodule/gmodule-win32.c +++ b/gmodule/gmodule-win32.c @@ -131,7 +131,20 @@ find_in_any_module_using_toolhelp (const gchar *symbol_name) /* Under UWP, Module32Next and Module32First are not available since we're * not allowed to search in the address space of arbitrary loaded DLLs */ #if !defined(G_WINAPI_ONLY_APP) - if ((snapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0)) == (HANDLE) -1) + /* https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot#remarks + * If the function fails with ERROR_BAD_LENGTH, retry the function until it succeeds. */ + while (TRUE) + { + snapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); + if (snapshot == INVALID_HANDLE_VALUE && GetLastError () == ERROR_BAD_LENGTH) + { + g_thread_yield (); + continue; + } + break; + } + + if (snapshot == INVALID_HANDLE_VALUE) return NULL; me32.dwSize = sizeof (me32);