fix crash when copy'ing latent plugins
[ardour.git] / libs / ardour / control_protocol_manager.cc
index 8f2f026d5542c3c1a1044792fa1f2fa785cf25fc..a0a36c17dd2150480e4262d4caea12dd51a8fa14 100644 (file)
@@ -38,11 +38,27 @@ using namespace ARDOUR;
 using namespace std;
 using namespace PBD;
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 ControlProtocolManager* ControlProtocolManager::_instance = 0;
 const string ControlProtocolManager::state_node_name = X_("ControlProtocols");
 
+
+ControlProtocolInfo::~ControlProtocolInfo ()
+{
+       if (protocol && descriptor) {
+               descriptor->destroy (descriptor, protocol);
+               protocol = 0;
+       }
+
+       delete state; state = 0;
+
+       if (descriptor) {
+               delete (Glib::Module*) descriptor->module;
+               descriptor = 0;
+       }
+}
+
 ControlProtocolManager::ControlProtocolManager ()
 {
 }
@@ -168,7 +184,7 @@ ControlProtocolManager::instantiate (ControlProtocolInfo& cpi)
 
        cpi.descriptor = get_descriptor (cpi.path);
 
-       DEBUG_TRACE (DEBUG::ControlProtocols, string_compose ("instantiating %1\n", cpi.name));
+       DEBUG_TRACE (DEBUG::ControlProtocols, string_compose ("instantiating %1\n", cpi.name));
 
        if (cpi.descriptor == 0) {
                error << string_compose (_("control protocol name \"%1\" has no descriptor"), cpi.name) << endmsg;
@@ -193,6 +209,18 @@ int
 ControlProtocolManager::teardown (ControlProtocolInfo& cpi)
 {
        if (!cpi.protocol) {
+
+               /* we could still have a descriptor even if the protocol was
+                  never instantiated. Close the associated module (shared
+                  object/DLL) and make sure we forget about it.
+               */
+
+               if (cpi.descriptor) {
+                       cerr << "Closing descriptor for CPI anyway\n";
+                       delete (Glib::Module*) cpi.descriptor->module;
+                       cpi.descriptor = 0;
+               }
+
                return 0;
        }
 
@@ -223,9 +251,15 @@ ControlProtocolManager::teardown (ControlProtocolInfo& cpi)
        }
 
        cpi.protocol = 0;
+
        delete cpi.state;
        cpi.state = 0;
-       delete (Glib::Module*)cpi.descriptor->module;
+       delete (Glib::Module*) cpi.descriptor->module;
+       /* cpi->descriptor is now inaccessible since dlclose() or equivalent
+        * has been performed, and the descriptor is (or could be) a static
+        * object made accessible by dlopen().
+        */
+       cpi.descriptor = 0;
 
        ProtocolStatusChange (&cpi);
 
@@ -332,8 +366,6 @@ ControlProtocolManager::control_protocol_discover (string path)
                        DEBUG_TRACE (DEBUG::ControlProtocols,
                                     string_compose(_("Control surface protocol discovered: \"%1\"\n"), cpi->name));
                }
-
-               delete (Glib::Module*)descriptor->module;
        }
 
        return 0;
@@ -365,8 +397,6 @@ ControlProtocolManager::get_descriptor (string path)
 
        if (descriptor) {
                descriptor->module = (void*)module;
-       } else {
-               delete module;
        }
 
        return descriptor;
@@ -396,28 +426,31 @@ ControlProtocolManager::set_state (const XMLNode& node, int /*version*/)
 {
        XMLNodeList clist;
        XMLNodeConstIterator citer;
-       XMLProperty* prop;
+       XMLProperty const * prop;
 
        Glib::Threads::Mutex::Lock lm (protocols_lock);
 
        clist = node.children();
 
        for (citer = clist.begin(); citer != clist.end(); ++citer) {
-               if ((*citer)->name() == X_("Protocol")) {
+               XMLNode const * child = *citer;
+
+               if (child->name() == X_("Protocol")) {
 
-                       if ((prop = (*citer)->property (X_("active"))) == 0) {
+                       if ((prop = child->property (X_("active"))) == 0) {
                                continue;
                        }
 
                        bool active = string_is_affirmative (prop->value());
 
-                       if ((prop = (*citer)->property (X_("name"))) == 0) {
+                       if ((prop = child->property (X_("name"))) == 0) {
                                continue;
                        }
 
                        ControlProtocolInfo* cpi = cpi_by_name (prop->value());
 
                        if (cpi) {
+                               delete cpi->state;
                                cpi->state = new XMLNode (**citer);
 
                                if (active) {