commit 542ebcf161c16e8fc6fd922bc7eeb1ece39cd504
parent 77dea31f20ab6f0b39b63dcae397fc596c05533d
Author: falkTX <falktx@falktx.com>
Date: Sat, 2 Oct 2021 16:51:28 +0100
VST3: unref queried host contexts, fixing memory leaks
Signed-off-by: falkTX <falktx@falktx.com>
Diffstat:
2 files changed, 71 insertions(+), 37 deletions(-)
diff --git a/distrho/src/DistrhoPluginVST3.cpp b/distrho/src/DistrhoPluginVST3.cpp
@@ -345,7 +345,7 @@ v3_plugin_view** dpf_plugin_view_create(v3_host_application** host, void* instan
* VST3 DSP class.
*
* All the dynamic things from VST3 get implemented here, free of complex low-level VST3 pointer things.
- * The DSP is created during the "initialise" component event, and destroyed during "terminate".
+ * The DSP is created during the "initialize" component event, and destroyed during "terminate".
*
* The low-level VST3 stuff comes after.
*/
@@ -2478,16 +2478,16 @@ struct dpf_edit_controller : v3_edit_controller_cpp {
bool initialized;
// cached values
v3_component_handler** handler;
- v3_host_application** const originalHostContext;
- v3_plugin_base::v3_funknown** hostContext;
+ v3_host_application** const hostContextFromFactory;
+ v3_host_application** hostContextFromInitialize;
dpf_edit_controller(ScopedPointer<PluginVst3>& v, v3_host_application** const h)
: refcounter(1),
vst3(v),
initialized(false),
handler(nullptr),
- originalHostContext(h),
- hostContext(nullptr)
+ hostContextFromFactory(h),
+ hostContextFromInitialize(nullptr)
{
// v3_funknown, single instance
query_interface = query_interface_edit_controller;
@@ -2579,8 +2579,14 @@ struct dpf_edit_controller : v3_edit_controller_cpp {
const bool initialized = controller->initialized;
DISTRHO_SAFE_ASSERT_RETURN(! initialized, V3_INVALID_ARG);
+ // query for host context
+ v3_host_application** host = nullptr;
+ v3_cpp_obj_query_interface(context, v3_host_application_iid, &host);
+
+ // save it for later so we can unref it
+ controller->hostContextFromInitialize = host;
+
controller->initialized = true;
- controller->hostContext = context;
return V3_OK;
}
@@ -2594,7 +2600,6 @@ struct dpf_edit_controller : v3_edit_controller_cpp {
DISTRHO_SAFE_ASSERT_RETURN(initialized, V3_INVALID_ARG);
controller->initialized = false;
- controller->hostContext = nullptr;
#if DISTRHO_PLUGIN_HAS_UI
// take the chance to do some cleanup if possible (we created the bridge, we need to destroy it)
@@ -2607,6 +2612,12 @@ struct dpf_edit_controller : v3_edit_controller_cpp {
controller->connectionComp = nullptr;
#endif
+ if (controller->hostContextFromInitialize != nullptr)
+ {
+ v3_cpp_obj_unref(controller->hostContextFromInitialize);
+ controller->hostContextFromInitialize = nullptr;
+ }
+
return V3_OK;
}
@@ -2783,15 +2794,10 @@ struct dpf_edit_controller : v3_edit_controller_cpp {
PluginVst3* const vst3 = controller->vst3;
DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, nullptr);
- // we require host context for message creation
- v3_host_application** host = nullptr;
-
- if (controller->hostContext != nullptr)
- v3_cpp_obj_query_interface(controller->hostContext, v3_host_application_iid, &host);
-
- if (host == nullptr)
- host = controller->originalHostContext;
-
+ // we require a host context for message creation
+ v3_host_application** host = controller->hostContextFromInitialize != nullptr
+ ? controller->hostContextFromInitialize
+ : controller->hostContextFromFactory;
DISTRHO_SAFE_ASSERT_RETURN(host != nullptr, nullptr);
// if there is a component connection, we require it to be active
@@ -3088,12 +3094,14 @@ struct dpf_component : v3_component_cpp {
#endif
ScopedPointer<dpf_edit_controller> controller;
ScopedPointer<PluginVst3> vst3;
- v3_host_application** const hostContext;
+ v3_host_application** const hostContextFromFactory;
+ v3_host_application** hostContextFromInitialize;
dpf_component(ScopedPointer<dpf_component>* const s, v3_host_application** const h)
: refcounter(1),
self(s),
- hostContext(h)
+ hostContextFromFactory(h),
+ hostContextFromInitialize(nullptr)
{
// v3_funknown, everything custom
query_interface = query_interface_component;
@@ -3116,6 +3124,19 @@ struct dpf_component : v3_component_cpp {
comp.get_state = get_state;
}
+ void cleanup()
+ {
+ vst3 = nullptr;
+ processor = nullptr;
+#if DISTRHO_PLUGIN_HAS_UI
+ connection = nullptr;
+#endif
+ controller = nullptr;
+
+ if (hostContextFromFactory != nullptr)
+ v3_cpp_obj_unref(hostContextFromFactory);
+ }
+
// ----------------------------------------------------------------------------------------------------------------
// v3_funknown
@@ -3157,7 +3178,7 @@ struct dpf_component : v3_component_cpp {
{
if (component->connection == nullptr)
component->connection = new dpf_dsp_connection_point(kConnectionPointComponent,
- component->vst3);
+ component->vst3);
else
++component->connection->refcounter;
*iface = &component->connection;
@@ -3168,7 +3189,8 @@ struct dpf_component : v3_component_cpp {
if (v3_tuid_match(iid, v3_edit_controller_iid))
{
if (component->controller == nullptr)
- component->controller = new dpf_edit_controller(component->vst3, component->hostContext);
+ component->controller = new dpf_edit_controller(component->vst3,
+ component->hostContextFromFactory);
else
++component->controller->refcounter;
*iface = &component->controller;
@@ -3255,6 +3277,10 @@ struct dpf_component : v3_component_cpp {
return handleUncleanComponent(componentptr);
d_stdout("dpf_component::unref => %p | refcount is zero, deleting everything now!", self);
+
+ if (component->hostContextFromFactory != nullptr)
+ v3_cpp_obj_unref(component->hostContextFromFactory);
+
*(component->self) = nullptr;
delete componentptr;
return 0;
@@ -3268,11 +3294,19 @@ struct dpf_component : v3_component_cpp {
d_stdout("dpf_component::initialize => %p %p", self, context);
dpf_component* const component = *(dpf_component**)self;
DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALIZED);
+ DISTRHO_SAFE_ASSERT_RETURN(component->vst3 == nullptr, V3_INVALID_ARG);
- PluginVst3* const vst3 = component->vst3;
- DISTRHO_SAFE_ASSERT_RETURN(vst3 == nullptr, V3_INVALID_ARG);
+ // query for host context
+ v3_host_application** host = nullptr;
+ if (context != nullptr)
+ v3_cpp_obj_query_interface(context, v3_host_application_iid, &host);
- d_lastCanRequestParameterValueChanges = true;
+ // save it for later so we can unref it
+ component->hostContextFromInitialize = host;
+
+ // provide the factory context to the plugin if this new one is invalid
+ if (host == nullptr)
+ host = component->hostContextFromFactory;
// default early values
if (d_lastBufferSize == 0)
@@ -3280,12 +3314,7 @@ struct dpf_component : v3_component_cpp {
if (d_lastSampleRate <= 0.0)
d_lastSampleRate = 44100.0;
- // query for host context
- v3_host_application** host = nullptr;
- v3_cpp_obj_query_interface(context, v3_host_application_iid, &host);
-
- if (host == nullptr)
- host = component->hostContext;
+ d_lastCanRequestParameterValueChanges = true;
component->vst3 = new PluginVst3(host);
return V3_OK;
@@ -3296,11 +3325,16 @@ struct dpf_component : v3_component_cpp {
d_stdout("dpf_component::terminate => %p", self);
dpf_component* const component = *(dpf_component**)self;
DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALIZED);
-
- PluginVst3* const vst3 = component->vst3;
- DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_INVALID_ARG);
+ DISTRHO_SAFE_ASSERT_RETURN(component->vst3 != nullptr, V3_INVALID_ARG);
component->vst3 = nullptr;
+
+ if (component->hostContextFromInitialize != nullptr)
+ {
+ v3_cpp_obj_unref(component->hostContextFromInitialize);
+ component->hostContextFromInitialize = nullptr;
+ }
+
return V3_OK;
}
@@ -3488,11 +3522,7 @@ struct dpf_factory : v3_plugin_factory_cpp {
{
ScopedPointer<dpf_component>* const componentptr = *it;
dpf_component* const component = *componentptr;
-#if DISTRHO_PLUGIN_HAS_UI
- component->connection = nullptr;
-#endif
- component->processor = nullptr;
- component->controller = nullptr;
+ component->cleanup();
*(component->self) = nullptr;
delete componentptr;
}
diff --git a/distrho/src/DistrhoUIVST3.cpp b/distrho/src/DistrhoUIVST3.cpp
@@ -1032,6 +1032,10 @@ struct dpf_plugin_view : v3_plugin_view_cpp {
{
v3_cpp_obj(runloop)->unregister_timer(runloop, (v3_timer_handler**)&view->timer);
+ // we query it 2 times in total, so lets unref 2 times as well
+ v3_cpp_obj_unref(runloop);
+ v3_cpp_obj_unref(runloop);
+
if (const int refcount = --view->timer->refcounter)
{
view->timer->valid = false;