From d79bc3b936ae597cbe8a461d0657391bf5a724ed Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Mon, 7 Dec 2020 18:09:49 +0100 Subject: [PATCH] Don't use STL smart pointers with VST3 interfaces This would cause double frees since those objects are supposed to clean up after themselves. --- src/common/serialization/vst3/README.md | 5 ++++- src/plugin/bridges/vst3.cpp | 7 +++++-- src/plugin/bridges/vst3.h | 12 ++++-------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/common/serialization/vst3/README.md b/src/common/serialization/vst3/README.md index 7da78fd6..ab218c5d 100644 --- a/src/common/serialization/vst3/README.md +++ b/src/common/serialization/vst3/README.md @@ -62,4 +62,7 @@ TODO: Explain how we implement `createInstance()` - Since everything behind the scenes makes use of these `addRef()` and `release()` reference counting functions, we can't use the standard library's smart pointers when dealing with objects that are shared with the host or with - the Windows VST3 plugin. + the Windows VST3 plugin. In `IPtr`'s destructor it will call release, and + the objects will clean themselfs up with a `delete this;` when the reference + count reaches 0. Combining this with the STL cmart pointers this would result + in a double free. diff --git a/src/plugin/bridges/vst3.cpp b/src/plugin/bridges/vst3.cpp index 780c199e..66447d9c 100644 --- a/src/plugin/bridges/vst3.cpp +++ b/src/plugin/bridges/vst3.cpp @@ -86,7 +86,10 @@ Vst3PluginBridge::Vst3PluginBridge() Steinberg::IPluginFactory* Vst3PluginBridge::get_plugin_factory() { // Even though we're working with raw pointers here, we should pretend that // we're `IPtr` and do the reference counting - // ourselves because you can't always safely pass those around + // ourselves because you can't always safely pass those around The VST3 + // interface can't pass smart pointers around because of binary + // compatibility, so we'll have to do the reference counting by hand like in + // the implementation in `public.sdk/source/main/pluginfactory.h`. if (plugin_factory) { plugin_factory->addRef(); } else { @@ -94,7 +97,7 @@ Steinberg::IPluginFactory* Vst3PluginBridge::get_plugin_factory() { // will request after loading the module. Host callback handlers should // have started before this since the Wine plugin host will request a // copy of the configuration during its initialization. - plugin_factory = std::make_unique(*this); + plugin_factory = Steinberg::owned(new YaPluginFactoryPluginImpl(*this)); sockets.host_vst_control.receive_into( WantsPluginFactory{}, *plugin_factory, std::pair(logger, true)); diff --git a/src/plugin/bridges/vst3.h b/src/plugin/bridges/vst3.h index 3f036152..056418e6 100644 --- a/src/plugin/bridges/vst3.h +++ b/src/plugin/bridges/vst3.h @@ -80,15 +80,11 @@ class Vst3PluginBridge : PluginBridge> { * Our plugin factory. All information about the plugin and its supported * classes are copied directly from the Windows VST3 plugin's factory on the * Wine side, and we'll provide an implementation that can send control - * messages to the Wine plugin host. Even though we're passign plain - * pointers around, we should pretend that they're wrapped in the VST3 SDK's - * reference counting p pointers so we should do the reference counting - * ourselves. + * messages to the Wine plugin host. The VST3 interface only passes raw + * pointers around and the receiving side should then use `IPtr::adopt()` + * or `owned()` to get back the orignal smart pointer. * * @related get_plugin_factory - * - * FIXME: We can't use `std::unique_ptr` here because that breaks VST3's - * reference counting mechanism. */ - std::unique_ptr plugin_factory; + Steinberg::IPtr plugin_factory; };