Repository navigation
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the CMake option
FREEIMAGE_WITH_EXTERNAL_PLUGINS(defaultON) which controls whether the library loads external*.fipplugins when it is loaded.Motivation
On Windows,
DllMaincallsFreeImage_Initialise(FALSE), which callsLoadLibraryfor every*.fipfile in the directory of the executable and in itsplugins\subdirectory. This happens duringDLL_PROCESS_ATTACH, before any application code runs, so an application cannot opt out. Consequences:*.fip) is loaded into the process. Applications that restrict which code they load cannot use the library without this exception.SetCurrentDirectoryWand loads libraries while the loader lock is held, which is discouraged._Init@8, which is the x86stdcalldecoration. So each*.fipgets loaded, itsDllMainruns, no plugin is registered, and the library is unloaded again. The risk stays, and there is no benefit.See the linked issue for the full background.
Changes
FREEIMAGE_WITH_EXTERNAL_PLUGINS, defaultON. The default behaviour is unchanged. The option definesFREEIMAGE_WITH_EXTERNAL_PLUGINSas 1 or 0 publicly. If the macro is not defined at all (a build outside CMake), the behaviour is the same asON.DllMain(and the shared-object constructor on other platforms) callsFreeImage_Initialise(!FREEIMAGE_WITH_EXTERNAL_PLUGINS). The parameterload_local_plugins_onlyskips the loading of external plugins, so it isTRUEif the option isOFF.OFF, the loading code inFreeImage_Initialiseis not compiled at all. An explicit callFreeImage_Initialise(FALSE)by an application then also loads no external plugins. TheFreeImage_Initialisesignature is unchanged.Scope — what this PR does not change
This PR only makes the external-plugin loader optional. It does not fix the loader itself:
ON(the default), the loader behaves exactly as before, including the broken_Init@8entry-point lookup on x64/ARM64. Nothing in the default build changes._Init@8would mean an arch-aware lookup (the undecoratedIniton x64/ARM64 vs. thestdcall-decorated_Init@8on x86), which changes the external-plugin entry-point contract. I have deliberately left that out of this PR: I build and ship no*.fipplugins, so I cannot test such a fix. I'm happy to open it as a separate PR, or to leave it to you — see the linked issue.Testing
Built with Visual Studio 2026 (v145, x64, RelWithDebInfo) with
FREEIMAGE_BUILD_TESTS=ON, libraries limited to LibJPEG and LibPNG, optionOFF. The resulting DLL does not contain the*.fipsearch pattern. The default build (optionON) still contains the loader.Part of #97.