-
Notifications
You must be signed in to change notification settings - Fork 8
Duplicate loading of plugins #129
Description
General
Related to #9
I accidentally came across a problem with undefined static behavior in plugins, which led to a critical bug in Rocket.Core.Plugins.RocketPluginManager.
The core of the issue lies in plugins being loaded into the game process multiple times due to an incorrect DLL loading order.
This behavior completely breaks the Singleton pattern, effectively turning it into a kind of "Dualton".
The problem is easier to illustrate with an example.
Example/Reproduce
The Rocket/Plugins folder contains the following files:
ADependantPlugin.dllCorePlugin.dll
Here, ADependantPlugin.dll references code from CorePlugin.dll (the files order matters in this case).
Referencing the code from:
private void loadPlugins() private Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
Rocket’s behavior is as follows:
- It caches the paths to all unique DLLs from
Rocket/LibrariesandRocket/Plugins. - It starts loading DLLs from
Rocket/Pluginssequentially into the game process. - It loads
ADependantPlugin.dll, which requiresCorePlugin.dll. - Through
OnAssemblyResolve,CorePlugin.dllis loaded usingAssembly.Load(). - Later,
CorePlugin.dllis loaded again viaAssembly.LoadFile()inside the loop ofLoadAssembliesFromDirectory().
As a result, we end up with two identical DLLs loaded into the game. This causes static constructors to be called twice.
So, even if public static CorePlugin Instance { get; private set; } was set during Load() of the CorePlugin, it will be reset to null upon repeated access, throwing an exception.
Note
At the moment, I haven’t had time to create a repository to reproduce the issue, as I discovered it while working on a client project.
However, if a repro repository is needed, feel free to ask and I’ll be happy to provide one.
The issue can be temporarily resolved by renaming ADependantPlugin.dll to DependantPlugin.dll, so it loads after CorePlugin.dll, as the folder content becomes:
CorePlugin.dllDependantPlugin.dll
Conclusion
Despite the possibility of working around this issue, I believe this kind of hidden bug is extremely problematic.