Skip to content

Duplicate loading of plugins #129

@IlyaSergeevich0

Description

@IlyaSergeevich0

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.dll
  • CorePlugin.dll

Here, ADependantPlugin.dll references code from CorePlugin.dll (the files order matters in this case).

Referencing the code from:

Rocket’s behavior is as follows:

  • It caches the paths to all unique DLLs from Rocket/Libraries and Rocket/Plugins.
  • It starts loading DLLs from Rocket/Plugins sequentially into the game process.
  • It loads ADependantPlugin.dll, which requires CorePlugin.dll.
  • Through OnAssemblyResolve, CorePlugin.dll is loaded using Assembly.Load().
  • Later, CorePlugin.dll is loaded again via Assembly.LoadFile() inside the loop of LoadAssembliesFromDirectory().

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.dll
  • DependantPlugin.dll

Conclusion

Despite the possibility of working around this issue, I believe this kind of hidden bug is extremely problematic.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions