From 6282fa9f39c115b03fe4e6f539a57ab816afb585 Mon Sep 17 00:00:00 2001 From: Jojakim Stahl Date: Thu, 22 Oct 2026 12:28:54 +0200 Subject: [PATCH] Add FREEIMAGE_WITH_EXTERNAL_PLUGINS option On Windows the library loads every *.fip file found in the directory of the executable or in its "plugins" subdirectory while it is being loaded (DllMain -> FreeImage_Initialise(FALSE)). This can be neither avoided nor controlled by the application, because it happens before any of the application code runs. It means that a DLL placed next to the executable gets loaded into the process, which is unwanted for applications that restrict the code they load. Besides that, the current directory is changed with SetCurrentDirectoryW() while the loader lock is held. On the x64 and ARM64 targets the feature does not even work: the init function is looked up by the name "_Init@8", which exists only in the 32-bit stdcall decoration. So each *.fip is loaded, its DllMain is run, and it is unloaded again without registering anything. Add the CMake option FREEIMAGE_WITH_EXTERNAL_PLUGINS, default ON, which keeps the behaviour as it is. If it is OFF, then DllMain passes load_local_plugins_only = TRUE, and the loading code is not compiled into the library. This does not fix the loader itself. With the option ON the behaviour is unchanged, including the broken _Init@8 lookup on x64/ARM64 described above. Fixing that would require an architecture-dependent entry-point name (undecorated "Init" on x64/ARM64 vs. the stdcall-decorated "_Init@8" on x86), which changes the external-plugin entry-point contract. It is left out here on purpose: I build and ship no *.fip plugins and cannot test such a change. --- Source/CMakeLists.txt | 7 +++++++ Source/FreeImage/FreeImage.cpp | 11 +++++++++-- Source/FreeImage/Plugin.cpp | 4 ++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 1392cec..423bc03 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -62,6 +62,13 @@ else() endif() +# External plugins (*.fip) are loaded from the directory of the executable when the library is initialized. +# Disable it to prevent loading of any code which is not a part of the library itself. +option(FREEIMAGE_WITH_EXTERNAL_PLUGINS "Load external plugins (*.fip) at startup" ON) +if (FREEIMAGE_WITH_EXTERNAL_PLUGINS) + target_compile_definitions(FreeImage PUBLIC "-DFREEIMAGE_WITH_EXTERNAL_PLUGINS=1") +endif() + target_link_libraries(FreeImage PRIVATE LibYato) target_link_libraries(FreeImage PRIVATE LibZLIB) diff --git a/Source/FreeImage/FreeImage.cpp b/Source/FreeImage/FreeImage.cpp index a6a4c0e..efa4a68 100644 --- a/Source/FreeImage/FreeImage.cpp +++ b/Source/FreeImage/FreeImage.cpp @@ -37,6 +37,13 @@ static const char *s_copyright = "This program uses FreeImage, a free, open source image library supporting all common bitmap formats. See http://freeimage.sourceforge.net for details"; +// Loading of the external plugins (*.fip) at the library startup, see FREEIMAGE_WITH_EXTERNAL_PLUGINS in CMake +#if FREEIMAGE_WITH_EXTERNAL_PLUGINS +# define FREEIMAGE_LOAD_LOCAL_PLUGINS_ONLY FALSE +#else +# define FREEIMAGE_LOAD_LOCAL_PLUGINS_ONLY TRUE +#endif + //---------------------------------------------------------------------- #if defined(_WIN32) && !defined(__MINGW32__) @@ -46,7 +53,7 @@ FIBOOL APIENTRY DllMain(HANDLE hModule, uint32_t ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH : - FreeImage_Initialise(FALSE); + FreeImage_Initialise(FREEIMAGE_LOAD_LOCAL_PLUGINS_ONLY); break; case DLL_PROCESS_DETACH : @@ -72,7 +79,7 @@ void FreeImage_SO_Initialise() __attribute__((constructor)); void FreeImage_SO_DeInitialise() __attribute__((destructor)); void FreeImage_SO_Initialise() { - FreeImage_Initialise(FALSE); + FreeImage_Initialise(FREEIMAGE_LOAD_LOCAL_PLUGINS_ONLY); } void FreeImage_SO_DeInitialise() { diff --git a/Source/FreeImage/Plugin.cpp b/Source/FreeImage/Plugin.cpp index d8901be..e0f1c12 100644 --- a/Source/FreeImage/Plugin.cpp +++ b/Source/FreeImage/Plugin.cpp @@ -650,7 +650,7 @@ FreeImage_Initialise(FIBOOL load_local_plugins_only) { auto& plugins = PluginsRegistrySingleton::Instance(); if (plugins.AddRef()) { // external plugin initialization -#ifdef _WIN32 +#if defined(_WIN32) && FREEIMAGE_WITH_EXTERNAL_PLUGINS if (!load_local_plugins_only) { int count = 0; char buffer[MAX_PATH + 200]; @@ -706,7 +706,7 @@ FreeImage_Initialise(FIBOOL load_local_plugins_only) { SetCurrentDirectoryW(current_dir); } } -#endif // _WIN32 +#endif // _WIN32 && FREEIMAGE_WITH_EXTERNAL_PLUGINS } }