[SPIGOT-6621] ClassLoader Is Closing Jar Files Too Early (Caused by Auto-Library Change) Created: 03/Jul/21 Updated: 11/Jul/21 |
|
Status: | Open |
Project: | Spigot |
Component/s: | None |
Affects Version/s: | None |
Fix Version/s: | None |
Type: | Bug | Priority: | Minor |
Reporter: | Mick Monkey | Assignee: | Unassigned |
Resolution: | Unresolved | Votes: | 0 |
Labels: | None |
Version: | CraftBukkit version 3168-Spigot-a483d2c-bc00005 (MC: 1.17) (Implementing API version 1.17-R0.1-SNAPSHOT) |
Guidelines Read: | Yes |
Description |
tl;dr: After the "automatic library support" commit to Bukkit, the plugin class loader now completely closes and uncaches all plugins immediately on shutdown, making them inaccessible in onDisable() in places they previously were accessible. The loose summary of how things are laid out is:
On earlier versions (Spigot 1.16.5 builds dated prior to May 14th, or 1.15.2/etc older versions, throughout basically all history back to 2012 Bukkit versions when Citizens was started), this worked as expected. [06:22:01] [Server thread/ERROR]: Error occurred while disabling Citizens v2.0.28-SNAPSHOT (build 2333) (Is it up to date?) General hoped-for solution would be correcting it to not unload plugin jars until after ALL plugins are shutdown, rather than individual unloading each jar as the plugin unloads. |
Comments |
Comment by Jan Boerman [ 11/Jul/21 ] |
Perhaps a good solution here would be introduce an onUnload() method to Plugin.java as a dual of onLoad(). The plugin's lifecycle would then look as follows:
This way Citizens will still be able to access classes from the addons in the onDisable method. Obviously JavaPlugin can implement the onUnload() method using an empty body, or a default method on the Plugin interface could be used. |
Comment by Mick Monkey [ 05/Jul/21 ] |
If Sentinel is disabled outside of a full server shutdown, that is erroneous. Any users that intentionally caused that to happen would be told "yeah obviously that broke it what did you expect". Same for Citizens, same for any&every other Citizens addon (I note, a lot of plugins function in whole or in part as Citizens addons, and they're all broken by this change)... same for most plugins. There's a reason for the giant red warning labels on "/reload", and a reason that plugins like Essentials even actively add extra warning messages when a reload is done. I would be shocked if Citizens was the only case of this change breaking. I know for a fact a lot of plugins have two-way interoperation akin to Citizens. It's a core part of how plugin development works. The PluginDisableEvent wouldn't really help - when Citizens shuts down, it saves all data for each NPC... some of that data is supplied by Sentinel (or whichever addon). It needs to be able to save that data. The only way to use PluginDisableEvent here would be for Citizens to save and shutdown the moment any plugin that depends on Citizens is disabled... which would be an awkward hackaround, not a solution - and likely to create its own new issues. (Individual unhooking doesn't work - everything saves at once into one file, it can't be separated... separating saves per plugin would be a massive scale of rewrite for literally hundreds of developers (Citizens is primarily an API for other plugins to add onto, rather than a full-featured system on its own, and a lot of plugin developers have used it - including a lot of small/individual developers, running their own servers and using Citizens as an API to power things like NPC-driven quests unique to their server... every last one of them would need to build their own systems for separated saving), that would also introduce significant bugs on top of invalidating all the convenience/cleanliness/stability/bug-prevention/etc. benefits of the unified save system). "Plugin jars are still loaded in memory before the shutdown finishes" doesn't seem like it should be undefined behavior - especially for plugins that are explicitly interoperating with each other, and have even marked that via the Depends system. |
Comment by md_5 [ 03/Jul/21 ] |
I disagree this is a bug. There is a reason disables are done in reverse-depend order and we have PluginDisableEvent — so plugins can unhook each other. Right now you are accessing a disabled plugin when you should not be. You can easily see how this would be an issue if you consider the scenario where the server is not reloading or stopping, but merely the Sentinel plugin is disabled — it would be disabled yet you would still be trying to use it during normal server operations. Just because there was some old undefined behaviour for a number of years, doesn't mean it was correct. |
Comment by Black Hole [ 03/Jul/21 ] |
Please consider using https://hub.spigotmc.org/javadocs/spigot/org/bukkit/event/server/PluginDisableEvent.html as a workaround. |