diff --git a/Source/websocket/JSONRPCLink.cpp b/Source/websocket/JSONRPCLink.cpp index dd006f707..16a9bb3bd 100644 --- a/Source/websocket/JSONRPCLink.cpp +++ b/Source/websocket/JSONRPCLink.cpp @@ -21,6 +21,19 @@ namespace WPEFramework { +namespace JSONRPC { + + // Shared channel map stored in the library's data segment. + // This ensures all DSOs using JSONRPCLink share the same map instance, + // preventing crashes when plugins unload while others still hold references. + Core::ProxyMapType& GetChannelMap() + { + static Core::ProxyMapType channelMap; + return channelMap; + } + +} // namespace JSONRPC + ENUM_CONVERSION_BEGIN(WPEFramework::JSONRPC::JSONPluginState) { WPEFramework::JSONRPC::DEACTIVATED, _TXT("Deactivated") }, diff --git a/Source/websocket/JSONRPCLink.h b/Source/websocket/JSONRPCLink.h index fb7ae08f0..c00882ca8 100644 --- a/Source/websocket/JSONRPCLink.h +++ b/Source/websocket/JSONRPCLink.h @@ -28,12 +28,21 @@ namespace WPEFramework { using namespace Core::TypeTraits; + // Base class for CommunicationChannel to allow shared storage across DSO boundaries + class EXTERNAL CommunicationChannelBase { + public: + virtual ~CommunicationChannelBase() = default; + }; + + // Returns the shared channel map stored in the library's data segment + EXTERNAL Core::ProxyMapType& GetChannelMap(); + template class LinkType { private: typedef std::function CallbackFunction; - class CommunicationChannel { + class CommunicationChannel : public CommunicationChannelBase { private: // ----------------------------------------------------------------------------------------------- // Create a resource allocator for all JSON objects used in these tests @@ -198,14 +207,13 @@ namespace WPEFramework { } public: - virtual ~CommunicationChannel() = default; + ~CommunicationChannel() override = default; static Core::ProxyType Instance(const Core::NodeId& remoteNode, const string& callsign, const string& query) { - static Core::ProxyMapType channelMap; - - string searchLine = remoteNode.HostAddress() + '@' + callsign; + // Use type-discriminated key to prevent collisions between different INTERFACE types + string searchLine = remoteNode.HostAddress() + '@' + callsign + '@' + typeid(INTERFACE).name(); - return (channelMap.template Instance(searchLine, remoteNode, callsign, query)); + return Core::ProxyType(GetChannelMap().template Instance(searchLine, remoteNode, callsign, query)); } public: