Back the VST3 plugin factory by an IPtr

This prevents REAPER from crashing when removing the last instance of a
plugin and then readding it. REAPER doesn't unload the module even after
it removes its last plugin factory instance. This means that before this
the plugin factory would be freed but we still had a seemingly valid
pointer to it that we would try to access.
This commit is contained in:
Robbert van der Helm
2021-01-21 01:51:21 +01:00
parent 4cc44c3cf7
commit 74dc8225d1
4 changed files with 22 additions and 20 deletions
@@ -18,6 +18,7 @@
#include <pluginterfaces/vst/ivstcomponent.h> #include <pluginterfaces/vst/ivstcomponent.h>
#include "../vst3.h"
#include "plugin-proxy.h" #include "plugin-proxy.h"
YaPluginFactoryImpl::YaPluginFactoryImpl(Vst3PluginBridge& bridge, YaPluginFactoryImpl::YaPluginFactoryImpl(Vst3PluginBridge& bridge,
@@ -16,7 +16,11 @@
#pragma once #pragma once
#include "../vst3.h" #include "../../../common/serialization/vst3/plugin-factory.h"
// We need an `IPtr<YaPluginFactoryImpl>` in `Vst3PluginBridge`, so we need to
// declare this slightly differently to avoid circular includes.
class Vst3PluginBridge;
class YaPluginFactoryImpl : public YaPluginFactory { class YaPluginFactoryImpl : public YaPluginFactory {
public: public:
+12 -11
View File
@@ -351,15 +351,12 @@ Vst3PluginBridge::~Vst3PluginBridge() {
} }
Steinberg::IPluginFactory* Vst3PluginBridge::get_plugin_factory() { Steinberg::IPluginFactory* Vst3PluginBridge::get_plugin_factory() {
// Even though we're working with raw pointers here, we should pretend that // This works the same way as the default implementation in
// we're `IPtr<Steinberg::IPluginFactory>` and do the reference counting // `public.sdk/source/main/pluginfactory.h`, with the exception that we back
// ourselves. This should work the same was as the standard implementation // the plugin factory with an `IPtr` ourselves so it cannot be freed before
// in `public.sdk/source/main/pluginfactory.h`. If we were to use an IPtr or // `Vst3PluginBridge` gets freed. This is needed for REAPER as REAPER does
// an STL smart pointer we would get a double free (or rather, a use after // not call `ModuleExit()`.
// free). if (!plugin_factory) {
if (plugin_factory) {
plugin_factory->addRef();
} else {
// Set up the plugin factory, since this is the first thing the host // Set up the plugin factory, since this is the first thing the host
// will request after loading the module. Host callback handlers should // will request after loading the module. Host callback handlers should
// have started before this since the Wine plugin host will request a // have started before this since the Wine plugin host will request a
@@ -368,10 +365,14 @@ Steinberg::IPluginFactory* Vst3PluginBridge::get_plugin_factory() {
sockets.host_vst_control.send_message( sockets.host_vst_control.send_message(
YaPluginFactory::Construct{}, YaPluginFactory::Construct{},
std::pair<Vst3Logger&, bool>(logger, true)); std::pair<Vst3Logger&, bool>(logger, true));
plugin_factory = plugin_factory = Steinberg::owned(
new YaPluginFactoryImpl(*this, std::move(factory_args)); new YaPluginFactoryImpl(*this, std::move(factory_args)));
} }
// Because we're returning a raw pointer, we have to increas the
// reference count ourselves
plugin_factory->addRef();
return plugin_factory; return plugin_factory;
} }
+4 -8
View File
@@ -22,10 +22,8 @@
#include "../../common/communication/vst3.h" #include "../../common/communication/vst3.h"
#include "../../common/logging/vst3.h" #include "../../common/logging/vst3.h"
#include "common.h" #include "common.h"
#include "vst3-impls/plugin-factory.h"
// Forward declarations #include "vst3-impls/plugin-proxy.h"
class Vst3PluginProxyImpl;
class YaPluginFactoryImpl;
/** /**
* This handles the communication between the native host and a VST3 plugin * This handles the communication between the native host and a VST3 plugin
@@ -139,13 +137,11 @@ class Vst3PluginBridge : PluginBridge<Vst3Sockets<std::jthread>> {
* Our plugin factory. All information about the plugin and its supported * Our plugin factory. All information about the plugin and its supported
* classes are copied directly from the Windows VST3 plugin's factory on the * 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 * Wine side, and we'll provide an implementation that can send control
* messages to the Wine plugin host. As explained in `get_plugin_factory()`, * messages to the Wine plugin host.
* this cannot be a smart pointer because the factory is supposed to free
* itself when the host removes its last adopted `IPtr<IpluginFactory>`.
* *
* @related get_plugin_factory * @related get_plugin_factory
*/ */
YaPluginFactoryImpl* plugin_factory = nullptr; Steinberg::IPtr<YaPluginFactoryImpl> plugin_factory = nullptr;
private: private:
/** /**