Stop the JSON API before plugins delete their resource providers - #366
Stop the JSON API before plugins delete their resource providers#366jolavillette wants to merge 1 commit into
Conversation
|
Heads-up on a deliberate duplication: this same commit is now also proposed on defnax's The reason is merge ordering. RetroShare/RetroShare#3289 no longer restarts the JSON API from This PR stays open as a fallback, so the fix can still reach master on its own if #364 is delayed or dropped. Whichever lands first, the other becomes a no-op: the patch is identical, so git merges it without conflict. I will close this one once #364 is in. Unrelated to the change: the red mark comes from the MINGW64 workflow, which fails at "Checkout submodules" on every branch including master — |
3c29d9a to
46fec64
Compare
rsGlobalShutDown() stopped the JSON API almost last, after stopPlugins(). A plugin that registered a JsonApiResourceProvider deletes it in its stop(), but the running restbed service still holds the restbed::Resource objects that provider returned, and their handlers capture it. Any request served between stopPlugins() and the fullstop at the end of the function therefore dereferences freed memory. The window is not theoretical: everything in between -- UPnP teardown, the auto-proxy shutdown, all registered service threads, the RsServer tick thread and the per-peer streamers -- can take tens of seconds, and a web interface polls throughout. Move the fullstop to the top of the function. It also keeps an API client from touching the configuration after ConfigFinalSave(), and it must stay outside the wasReady branch: retroshare-service and Android start the JSON API before login, so a shutdown from that state has to stop it too. Without this, a plugin has to restart the whole JSON API from its stop() to make deleting its own provider safe, which costs a burst-protection wait and brings the server back up in the middle of teardown.
46fec64 to
1c6fa59
Compare
RsServer::rsGlobalShutDown()stops the JSON API almost last, afterstopPlugins().A plugin that registered a
JsonApiResourceProviderdeletes it in itsstop(), but the running restbed service still holds therestbed::Resourceobjects that provider returned, and their handlers capture it —JsonApiServer::run()publishes them once at thread start and the service keeps them for its whole lifetime. Any request served betweenstopPlugins()and thefullstop()at the end of the function therefore dereferences freed memory.The window is not theoretical. Everything in between — UPnP teardown, the auto-proxy shutdown, all registered service threads, the
RsServertick thread and the per-peer streamers — can take tens of seconds, and a web interface polls throughout.This moves the
fullstop()to the top of the function. Two details worth noting:ConfigFinalSave(), which runs a couple of lines below;wasReadybranch, because retroshare-service and Android start the JSON API before login, so a shutdown from that state has to stop it too. That is why the call cannot simply be hoisted into the existing block.No plugin in the tree registers a resource provider today, so nothing is currently affected. It becomes reachable with #364 and RetroShare/RetroShare#3289, which give plugins access to the JSON API — and without this change, a plugin has to restart the whole JSON API from its
stop()just to make deleting its own provider safe, which costs aRESTART_BURST_PROTECTIONwait and brings the server back up in the middle of the core teardown.Sending it separately since it stands on its own and fixes a latent defect for any future provider-registering plugin.
Not build-tested yet.