Fixes #6626: Throw if Lv2 object CTORs fail (#6951)

On plugin instantiation failure, `Lv2Proc::m_valid` was being set to false. However, `Lv2Proc::run` did not evaluate `m_valid` and still called `lilv_instance_run`, which caused undefined behavior, including crashes.

This bug fixes this by not even create such zombie classes, and instead `throw`s right away. The throws are caught in `lmms_plugin_main`, as suggested in the PR discussion and as the VST3 approach.
This commit is contained in:
Johannes Lorenz
2024-02-18 15:56:45 +01:00
committed by GitHub
parent 99120f567d
commit 34ab5ff730
9 changed files with 37 additions and 69 deletions

View File

@@ -59,7 +59,7 @@ Lv2ControlBase::Lv2ControlBase(Model* that, const QString &uri) :
else
{
qCritical() << "No Lv2 plugin found for URI" << uri;
m_valid = false;
throw std::runtime_error("No Lv2 plugin found for given URI");
}
}
@@ -77,26 +77,14 @@ void Lv2ControlBase::init(Model* meAsModel)
while (channelsLeft > 0)
{
std::unique_ptr<Lv2Proc> newOne = std::make_unique<Lv2Proc>(m_plugin, meAsModel);
if (newOne->isValid())
{
channelsLeft -= std::max(
1 + static_cast<bool>(newOne->inPorts().m_right),
1 + static_cast<bool>(newOne->outPorts().m_right));
Q_ASSERT(channelsLeft >= 0);
m_procs.push_back(std::move(newOne));
}
else
{
qCritical() << "Failed instantiating LV2 processor";
m_valid = false;
channelsLeft = 0;
}
}
if (m_valid)
{
m_channelsPerProc = DEFAULT_CHANNELS / m_procs.size();
linkAllModels();
channelsLeft -= std::max(
1 + static_cast<bool>(newOne->inPorts().m_right),
1 + static_cast<bool>(newOne->outPorts().m_right));
Q_ASSERT(channelsLeft >= 0);
m_procs.push_back(std::move(newOne));
}
m_channelsPerProc = DEFAULT_CHANNELS / m_procs.size();
linkAllModels();
}

View File

@@ -467,7 +467,7 @@ void Lv2Proc::initPlugin()
<< "(URI:"
<< lilv_node_as_uri(lilv_plugin_get_uri(m_plugin))
<< ")";
m_valid = false;
throw std::runtime_error("Failed to create Lv2 processor");
}
}
@@ -476,16 +476,12 @@ void Lv2Proc::initPlugin()
void Lv2Proc::shutdownPlugin()
{
if (m_valid)
{
lilv_instance_deactivate(m_instance);
lilv_instance_free(m_instance);
m_instance = nullptr;
lilv_instance_deactivate(m_instance);
lilv_instance_free(m_instance);
m_instance = nullptr;
m_features.clear();
m_options.clear();
}
m_valid = true;
m_features.clear();
m_options.clear();
}