View Issue Details

IDProjectCategoryView StatusLast Update
0001401OpenMPTPlugins / VSTpublic2021-01-10 18:30
Reportermanx Assigned Tomanx  
PriorityhighSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Product VersionOpenMPT 1.30.00.* (current testing) 
Target VersionOpenMPT 1.30 / libopenmpt 0.6 (goals)Fixed in VersionOpenMPT 1.30 / libopenmpt 0.6 (goals) 
Summary0001401: Do not silently ignore crashes in VST plugins by default any more
Description

This had already been discussed before the 1.29 release.

TagsNo tags attached.
Has the bug occurred in previous versions?
Tested code revision (in case you know it)

Relationships

related to 0001291 resolvedmanx Separate plugin bridge versions for legacy / buggy plugins 

Activities

manx

manx

2020-12-22 17:05

administrator   ~0004557

vst-seh-v10.patch (24,641 bytes)   
Index: mptrack/ModDocTemplate.cpp
===================================================================
--- mptrack/ModDocTemplate.cpp	(revision 13970)
+++ mptrack/ModDocTemplate.cpp	(working copy)
@@ -130,7 +130,7 @@
 	if(const auto fileExt = filename.GetFileExt(); !mpt::PathString::CompareNoCase(fileExt, P_(".dll")) || !mpt::PathString::CompareNoCase(fileExt, P_(".vst3")))
 	{
 		CVstPluginManager *pPluginManager = theApp.GetPluginManager();
-		if(pPluginManager && pPluginManager->AddPlugin(filename) != nullptr)
+		if(pPluginManager && pPluginManager->AddPlugin(filename, TrackerSettings::Instance().BrokenPluginsWorkaroundVSTMaskAllCrashes) != nullptr)
 		{
 			return nullptr;
 		}
Index: mptrack/Mptrack.cpp
===================================================================
--- mptrack/Mptrack.cpp	(revision 13970)
+++ mptrack/Mptrack.cpp	(working copy)
@@ -1847,6 +1847,8 @@
 	m_pPluginManager = new CVstPluginManager;
 	const size_t numPlugins = GetSettings().Read<int32>(U_("VST Plugins"), U_("NumPlugins"), 0);
 
+	bool maskCrashes = TrackerSettings::Instance().BrokenPluginsWorkaroundVSTMaskAllCrashes;
+
 	std::vector<VSTPluginLib *> nonFoundPlugs;
 	const mpt::PathString failedPlugin = GetSettings().Read<mpt::PathString>(U_("VST Plugins"), U_("FailedPlugin"), P_(""));
 
@@ -1911,7 +1913,7 @@
 			mpt::ustring plugTags = GetSettings().Read<mpt::ustring>(U_("VST Plugins"), tagFormat(plug), mpt::ustring());
 
 			bool plugFound = true;
-			VSTPluginLib *lib = m_pPluginManager->AddPlugin(plugPath, plugTags, true, &plugFound);
+			VSTPluginLib *lib = m_pPluginManager->AddPlugin(plugPath, maskCrashes, plugTags, true, &plugFound);
 			if(!plugFound && lib != nullptr)
 			{
 				nonFoundPlugs.push_back(lib);
Index: mptrack/SelectPluginDialog.cpp
===================================================================
--- mptrack/SelectPluginDialog.cpp	(revision 13970)
+++ mptrack/SelectPluginDialog.cpp	(working copy)
@@ -658,7 +658,7 @@
 
 	for(const auto &file : dlg.GetFilenames())
 	{
-		VSTPluginLib *lib = plugManager->AddPlugin(file, mpt::ustring(), false);
+		VSTPluginLib *lib = plugManager->AddPlugin(file, TrackerSettings::Instance().BrokenPluginsWorkaroundVSTMaskAllCrashes, mpt::ustring(), false);
 		if(lib != nullptr)
 		{
 			update = true;
@@ -715,6 +715,7 @@
 	pluginScanDlg.ShowWindow(SW_SHOW);
 
 	FolderScanner scan(path, FolderScanner::kOnlyFiles | FolderScanner::kFindInSubDirectories);
+	bool maskCrashes = TrackerSettings::Instance().BrokenPluginsWorkaroundVSTMaskAllCrashes;
 	mpt::PathString fileName;
 	int files = 0;
 	while(scan.Next(fileName) && pluginScanDlg.IsWindowVisible())
@@ -731,7 +732,7 @@
 				::DispatchMessage(&msg);
 			}
 
-			VSTPluginLib *lib = pManager->AddPlugin(fileName, mpt::ustring(), false);
+			VSTPluginLib *lib = pManager->AddPlugin(fileName, maskCrashes, mpt::ustring(), false);
 			if(lib)
 			{
 				update = true;
Index: mptrack/TrackerSettings.cpp
===================================================================
--- mptrack/TrackerSettings.cpp	(revision 13970)
+++ mptrack/TrackerSettings.cpp	(working copy)
@@ -314,6 +314,8 @@
 	, vstHostProductString(conf, U_("VST Plugins"), U_("HostProductString"), "OpenMPT")
 	, vstHostVendorString(conf, U_("VST Plugins"), U_("HostVendorString"), "OpenMPT project")
 	, vstHostVendorVersion(conf, U_("VST Plugins"), U_("HostVendorVersion"), Version::Current().GetRawVersion())
+	// Broken Plugins Workarounds
+	, BrokenPluginsWorkaroundVSTMaskAllCrashes(conf, U_("Broken Plugins Workarounds"), U_("VSTMaskAllCrashes"), true)  // TODO: really should be false
 	// Update
 	, UpdateEnabled(conf, U_("Update"), U_("Enabled"), true)
 	, UpdateInstallAutomatically(conf, U_("Update"), U_("InstallAutomatically"), false)
Index: mptrack/TrackerSettings.h
===================================================================
--- mptrack/TrackerSettings.h	(revision 13970)
+++ mptrack/TrackerSettings.h	(working copy)
@@ -850,6 +850,10 @@
 	CachedSetting<mpt::lstring> vstHostVendorString;
 	CachedSetting<int32> vstHostVendorVersion;
 
+	// Broken Plugins Workarounds
+
+	Setting<bool> BrokenPluginsWorkaroundVSTMaskAllCrashes;
+
 	// Update
 
 	Setting<bool> UpdateEnabled;
Index: mptrack/Vstplug.cpp
===================================================================
--- mptrack/Vstplug.cpp	(revision 13970)
+++ mptrack/Vstplug.cpp	(working copy)
@@ -19,6 +19,7 @@
 #include "AbstractVstEditor.h"
 #include "VSTEditor.h"
 #include "DefaultVstEditor.h"
+#include "ExceptionHandler.h"
 #endif // MODPLUG_TRACKER
 #include "../soundlib/Sndfile.h"
 #include "../soundlib/MIDIEvents.h"
@@ -29,6 +30,7 @@
 #include "../pluginBridge/BridgeOpCodes.h"
 #include "../soundlib/plugins/OpCodes.h"
 #include "../soundlib/plugins/PluginManager.h"
+#include "../common/mptOSException.h"
 
 using namespace Vst;
 DECLARE_FLAGSET(Vst::VstTimeInfoFlags)
@@ -41,55 +43,58 @@
 #define VST_LOG
 #endif
 
-// Try loading the VST library.
-static bool LoadLibrarySEH(const mpt::RawPathString &pluginPath, HMODULE &library)
+
+using VstCrash = Windows::SEH::Code;
+
+
+bool CVstPlugin::MaskCrashes() noexcept
 {
-	__try
-	{
-		library = LoadLibrary(pluginPath.c_str());
-		return true;
-	} __except(EXCEPTION_EXECUTE_HANDLER)
-	{
-		return false;
-	}
+	return m_maskCrashes;
 }
 
 
-static AEffect *CallMainProc(Vst::MainProc pMainProc)
+template <typename Tfn>
+DWORD CVstPlugin::SETryOrError(bool maskCrashes, Tfn fn)
 {
-	__try
+	DWORD exception = 0;
+	if(maskCrashes)
 	{
-		return pMainProc(CVstPlugin::MasterCallBack);
-	} __except(EXCEPTION_EXECUTE_HANDLER)
+		exception = Windows::SEH::TryOrError(fn);
+		if(exception)
+		{
+			ExceptionHandler::TaintProcess(ExceptionHandler::TaintReason::Plugin);
+		}
+	} else
 	{
-		return nullptr;
+		fn();
 	}
+	return exception;
 }
 
 
-// Try loading the VST plugin and retrieve the AEffect structure.
-static AEffect *GetAEffectSEH(HMODULE library)
+template <typename Tfn>
+DWORD CVstPlugin::SETryOrError(Tfn fn)
 {
-	auto pMainProc = (Vst::MainProc)GetProcAddress(library, "VSTPluginMain");
-	if(pMainProc == nullptr)
+	DWORD exception = 0;
+	if(MaskCrashes())
 	{
-		pMainProc = (Vst::MainProc)GetProcAddress(library, "main");
-	}
-
-	if(pMainProc != nullptr)
-	{
-		return CallMainProc(pMainProc);
+		exception = Windows::SEH::TryOrError(fn);
+		if(exception)
+		{
+			ExceptionHandler::TaintProcess(ExceptionHandler::TaintReason::Plugin);
+		}
 	} else
 	{
-#ifdef VST_LOG
-		MPT_LOG(LogDebug, "VST", MPT_UFORMAT("Entry point not found! (handle={})")(mpt::ufmt::PTR(library)));
-#endif // VST_LOG
-		return nullptr;
+#ifdef MODPLUG_TRACKER
+		ExceptionHandler::ContextSetter ectxguard{&m_Ectx};
+#endif // MODPLUG_TRACKER
+		fn();
 	}
+	return exception;
 }
 
 
-AEffect *CVstPlugin::LoadPlugin(VSTPluginLib &plugin, HMODULE &library, bool forceBridge)
+AEffect *CVstPlugin::LoadPlugin(bool maskCrashes, VSTPluginLib &plugin, HMODULE &library, bool forceBridge)
 {
 	const mpt::PathString &pluginPath = plugin.dllPath;
 
@@ -137,9 +142,17 @@
 		plugin.useBridge = false;
 	}
 
-	if(!LoadLibrarySEH(pluginPath.AsNative(), library))
 	{
-		CVstPluginManager::ReportPlugException(MPT_UFORMAT("Exception caught while loading {}")(pluginPath));
+#ifdef MODPLUG_TRACKER
+		ExceptionHandler::Context ectx{ MPT_UFORMAT("VST Plugin: {}")(plugin.dllPath.ToUnicode()) };
+		ExceptionHandler::ContextSetter ectxguard{&ectx};
+#endif // MODPLUG_TRACKER
+		DWORD exception = SETryOrError(maskCrashes, [&](){ library = LoadLibrary(pluginPath.AsNative().c_str()); });
+		if(exception)
+		{
+			CVstPluginManager::ReportPlugException(MPT_UFORMAT("Exception caught while loading {}")(pluginPath));
+			return nullptr;
+		}
 	}
 	if(library == nullptr)
 	{
@@ -167,7 +180,30 @@
 
 	if(library != nullptr && library != INVALID_HANDLE_VALUE)
 	{
-		effect = GetAEffectSEH(library);
+		auto pMainProc = (Vst::MainProc)GetProcAddress(library, "VSTPluginMain");
+		if(pMainProc == nullptr)
+		{
+			pMainProc = (Vst::MainProc)GetProcAddress(library, "main");
+		}
+
+		if(pMainProc != nullptr)
+		{
+#ifdef MODPLUG_TRACKER
+			ExceptionHandler::Context ectx{ MPT_UFORMAT("VST Plugin: {}")(plugin.dllPath.ToUnicode()) };
+			ExceptionHandler::ContextSetter ectxguard{&ectx};
+#endif // MODPLUG_TRACKER
+			DWORD exception = SETryOrError(maskCrashes, [&](){ effect = pMainProc(CVstPlugin::MasterCallBack); });
+			if(exception)
+			{
+				return nullptr;
+			}
+		} else
+		{
+#ifdef VST_LOG
+			MPT_LOG(LogDebug, "VST", MPT_UFORMAT("Entry point not found! (handle={})")(mpt::ufmt::PTR(library)));
+#endif // VST_LOG
+			return nullptr;
+		}
 	}
 
 	return effect;
@@ -809,8 +845,9 @@
 // CVstPlugin
 //
 
-CVstPlugin::CVstPlugin(HMODULE hLibrary, VSTPluginLib &factory, SNDMIXPLUGIN &mixStruct, AEffect &effect, CSoundFile &sndFile)
+CVstPlugin::CVstPlugin(bool maskCrashes, HMODULE hLibrary, VSTPluginLib &factory, SNDMIXPLUGIN &mixStruct, AEffect &effect, CSoundFile &sndFile)
 	: IMidiPlugin(factory, sndFile, &mixStruct)
+	, m_maskCrashes(maskCrashes)
 	, m_Effect(effect)
 	, timeInfo{}
 	, isBridged(!memcmp(&effect.reservedForHost2, "OMPT", 4))
@@ -829,6 +866,9 @@
 
 void CVstPlugin::Initialize()
 {
+
+	m_Ectx = { MPT_UFORMAT("VST Plugin: {}")(m_Factory.dllPath.ToUnicode()) };
+
 	// If filename matched during load but plugin ID didn't, make sure it's updated.
 	m_pMixStruct->Info.dwPluginId1 = m_Factory.pluginId1 = m_Effect.magic;
 	m_pMixStruct->Info.dwPluginId2 = m_Factory.pluginId2 = m_Effect.uniqueID;
@@ -1020,16 +1060,17 @@
 
 
 // Wrapper for VST dispatch call with structured exception handling.
-intptr_t CVstPlugin::DispatchSEH(AEffect *effect, VstOpcodeToPlugin opCode, int32 index, intptr_t value, void *ptr, float opt, unsigned long &exception)
+intptr_t CVstPlugin::DispatchSEH(bool maskCrashes, AEffect *effect, VstOpcodeToPlugin opCode, int32 index, intptr_t value, void *ptr, float opt, unsigned long &exception)
 {
-	__try
+	if(effect->dispatcher != nullptr)
 	{
-		if(effect->dispatcher != nullptr)
+		intptr_t result = 0;
+		DWORD e = SETryOrError(maskCrashes, [&](){ result = effect->dispatcher(effect, opCode, index, value, ptr, opt); });
+		if(e)
 		{
-			return effect->dispatcher(effect, opCode, index, value, ptr, opt);
+			exception = e;
 		}
-	} __except((exception = GetExceptionCode()), EXCEPTION_EXECUTE_HANDLER)
-	{
+		return result;
 	}
 	return 0;
 }
@@ -1037,29 +1078,39 @@
 
 intptr_t CVstPlugin::Dispatch(VstOpcodeToPlugin opCode, int32 index, intptr_t value, void *ptr, float opt)
 {
-	unsigned long exception = 0;
 #ifdef VST_LOG
 	{
 		mpt::ustring codeStr;
 		if(opCode < std::size(VstOpCodes))
+		{
 			codeStr = mpt::ToUnicode(mpt::Charset::ASCII, VstOpCodes[opCode]);
-		else
+		} else
+		{
 			codeStr = mpt::ufmt::val(opCode);
+		}
 		MPT_LOG(LogDebug, "VST", MPT_UFORMAT("About to Dispatch({}) (Plugin=\"{}\"), index: {}, value: {}, ptr: {}, opt: {}!\n")(codeStr, m_Factory.libraryName, index, mpt::ufmt::PTR(value), mpt::ufmt::PTR(ptr), mpt::ufmt::flt(opt, 3)));
 	}
 #endif
-	intptr_t result = DispatchSEH(&m_Effect, opCode, index, value, ptr, opt, exception);
-
-	if(exception)
+	if(!m_Effect.dispatcher)
 	{
-		mpt::ustring codeStr;
-		if(opCode < static_cast<int32>(std::size(VstOpCodes)))
-			codeStr = mpt::ToUnicode(mpt::Charset::ASCII, VstOpCodes[opCode]);
-		else
-			codeStr = mpt::ufmt::val(opCode);
-		ReportPlugException(MPT_UFORMAT("Exception {} in Dispatch({})")(mpt::ufmt::HEX0<8>(exception), codeStr));
+		return 0;
 	}
-
+	intptr_t result = 0;
+	{
+		DWORD exception = SETryOrError([&](){ result = m_Effect.dispatcher(&m_Effect, opCode, index, value, ptr, opt); });
+		if(exception)
+		{
+			mpt::ustring codeStr;
+			if(opCode < std::size(VstOpCodes))
+			{
+				codeStr = mpt::ToUnicode(mpt::Charset::ASCII, VstOpCodes[opCode]);
+			} else
+			{
+				codeStr = mpt::ufmt::val(opCode);
+			}
+			ReportPlugException(MPT_UFORMAT("Exception {} in Dispatch({})")(mpt::ufmt::HEX0<8>(exception), codeStr));
+		}
+	}
 	return result;
 }
 
@@ -1163,11 +1214,9 @@
 	float fResult = 0;
 	if(nIndex < m_Effect.numParams && m_Effect.getParameter != nullptr)
 	{
-		__try
+		DWORD exception = SETryOrError([&](){ fResult = m_Effect.getParameter(&m_Effect, nIndex); });
+		if(exception)
 		{
-			fResult = m_Effect.getParameter(&m_Effect, nIndex);
-		} __except(EXCEPTION_EXECUTE_HANDLER)
-		{
 			//ReportPlugException(U_("Exception in getParameter (Plugin=\"{}\")!\n"), m_Factory.szLibraryName);
 		}
 	}
@@ -1177,16 +1226,15 @@
 
 void CVstPlugin::SetParameter(PlugParamIndex nIndex, PlugParamValue fValue)
 {
-	__try
+	DWORD exception = 0;
+	if(nIndex < m_Effect.numParams && m_Effect.setParameter)
 	{
-		if(nIndex < m_Effect.numParams && m_Effect.setParameter)
-		{
-			m_Effect.setParameter(&m_Effect, nIndex, fValue);
-		}
-		ResetSilence();
-	} __except(EXCEPTION_EXECUTE_HANDLER)
+		exception = SETryOrError([&](){ m_Effect.setParameter(&m_Effect, nIndex, fValue); });
+	}
+	ResetSilence();
+	if(exception)
 	{
-		//ReportPlugException(MPT_UFORMAT("Exception in SetParameter({}, {})!")(nIndex, fValue));
+		//ReportPlugException(mpt::format(U_("Exception in SetParameter({}, {})!"))(nIndex, fValue));
 	}
 }
 
@@ -1273,8 +1321,7 @@
 	// Process VST events
 	if(m_Effect.dispatcher != nullptr && vstEvents.Finalise() > 0)
 	{
-		unsigned long exception = 0;
-		DispatchSEH(&m_Effect, effProcessEvents, 0, 0, &vstEvents, 0, exception);
+		DWORD exception = SETryOrError([&](){ m_Effect.dispatcher(&m_Effect, effProcessEvents, 0, 0, &vstEvents, 0); });
 		ResetSilence();
 		if(exception)
 		{
@@ -1342,18 +1389,6 @@
 }
 
 
-// Wrapper for VST process call with structured exception handling.
-static void ProcessSEH(Vst::ProcessProc processFP, AEffect* effect, float** inputs, float** outputs, int32 sampleFrames, unsigned long &exception)
-{
-	__try
-	{
-		processFP(effect, inputs, outputs, sampleFrames);
-	} __except((exception = GetExceptionCode()), EXCEPTION_EXECUTE_HANDLER)
-	{
-	}
-}
-
-
 void CVstPlugin::Process(float *pOutL, float *pOutR, uint32 numFrames)
 {
 	ProcessVSTEvents();
@@ -1382,14 +1417,15 @@
 		}
 
 		// Do the VST processing magic
-		ASSERT(numFrames <= MIXBUFFERSIZE);
-		unsigned long exception = 0;
-		ProcessSEH(m_pProcessFP, &m_Effect, m_mixBuffer.GetInputBufferArray(), outputBuffers, numFrames, exception);
-		if(exception)
+		MPT_ASSERT(numFrames <= MIXBUFFERSIZE);
 		{
-			Bypass();
-			mpt::ustring processMethod = (m_Effect.flags & effFlagsCanReplacing) ? U_("processReplacing") : U_("process");
-			ReportPlugException(MPT_UFORMAT("The plugin threw an exception ({}) in {}. It has automatically been set to \"Bypass\".")(mpt::ufmt::HEX0<8>(exception), processMethod));
+			DWORD exception = SETryOrError([&](){ m_pProcessFP(&m_Effect, m_mixBuffer.GetInputBufferArray(), outputBuffers, numFrames); });
+			if(exception)
+			{
+				Bypass();
+				mpt::ustring processMethod = (m_Effect.flags & effFlagsCanReplacing) ? U_("processReplacing") : U_("process");
+				ReportPlugException(MPT_UFORMAT("The plugin threw an exception ({}) in {}. It has automatically been set to \"Bypass\".")(mpt::ufmt::HEX0<8>(exception), processMethod));
+			}
 		}
 
 		// Mix outputs of multi-output VSTs:
Index: mptrack/Vstplug.h
===================================================================
--- mptrack/Vstplug.h	(revision 13970)
+++ mptrack/Vstplug.h	(working copy)
@@ -19,7 +19,11 @@
 #include "../soundlib/Mixer.h"
 #include "plugins/VstDefinitions.h"
 #include "plugins/VstEventQueue.h"
+#if defined(MODPLUG_TRACKER)
+#include "ExceptionHandler.h"
+#endif // MODPLUG_TRACKER
 
+
 OPENMPT_NAMESPACE_BEGIN
 
 
@@ -31,6 +35,8 @@
 class CVstPlugin final : public IMidiPlugin
 {
 protected:
+
+	bool m_maskCrashes;
 	HMODULE m_hLibrary;
 	Vst::AEffect &m_Effect;
 	Vst::ProcessProc m_pProcessFP = nullptr; // Function pointer to AEffect processReplacing if supported, else process.
@@ -49,13 +55,29 @@
 	Vst::VstTimeInfo timeInfo;
 
 public:
+
 	const bool isBridged : 1;		// True if our built-in plugin bridge is being used.
 
+private:
+
+#if defined(MODPLUG_TRACKER)
+	ExceptionHandler::Context m_Ectx;
+#endif // MODPLUG_TRACKER
+
 public:
-	CVstPlugin(HMODULE hLibrary, VSTPluginLib &factory, SNDMIXPLUGIN &mixPlugin, Vst::AEffect &effect, CSoundFile &sndFile);
+	bool MaskCrashes() noexcept;
+
+public:
+	template <typename Tfn> static DWORD SETryOrError(bool maskCrashes, Tfn fn);
+
+private:
+	template <typename Tfn> DWORD SETryOrError(Tfn fn);
+
+public:
+	CVstPlugin(bool maskCrashes, HMODULE hLibrary, VSTPluginLib &factory, SNDMIXPLUGIN &mixPlugin, Vst::AEffect &effect, CSoundFile &sndFile);
 	~CVstPlugin();
 
-	static Vst::AEffect *LoadPlugin(VSTPluginLib &plugin, HMODULE &library, bool forceBridge);
+	static Vst::AEffect *LoadPlugin(bool maskCrashes, VSTPluginLib &plugin, HMODULE &library, bool forceBridge);
 
 protected:
 	void Initialize();
@@ -91,7 +113,7 @@
 	CString GetParamLabel(PlugParamIndex param) override { return GetParamPropertyString(param, Vst::effGetParamLabel); };
 	CString GetParamDisplay(PlugParamIndex param) override { return GetParamPropertyString(param, Vst::effGetParamDisplay); };
 
-	static intptr_t DispatchSEH(Vst::AEffect *effect, Vst::VstOpcodeToPlugin opCode, int32 index, intptr_t value, void *ptr, float opt, unsigned long &exception);
+	static intptr_t DispatchSEH(bool maskCrashes, Vst::AEffect *effect, Vst::VstOpcodeToPlugin opCode, int32 index, intptr_t value, void *ptr, float opt, unsigned long &exception);
 	intptr_t Dispatch(Vst::VstOpcodeToPlugin opCode, int32 index, intptr_t value, void *ptr, float opt);
 
 	bool HasEditor() const override { return (m_Effect.flags & Vst::effFlagsHasEditor) != 0; }
Index: soundlib/plugins/PluginManager.cpp
===================================================================
--- soundlib/plugins/PluginManager.cpp	(revision 13970)
+++ soundlib/plugins/PluginManager.cpp	(working copy)
@@ -55,6 +55,7 @@
 #include "../../mptrack/TrackerSettings.h"
 #include "../../mptrack/AbstractVstEditor.h"
 #include "../../soundlib/AudioCriticalSection.h"
+#include "../mptrack/ExceptionHandler.h"
 #include "../common/mptCRC.h"
 #endif // MODPLUG_TRACKER
 
@@ -427,10 +428,10 @@
 
 // Extract instrument and category information from plugin.
 #ifndef NO_VST
-static void GetPluginInformation(Vst::AEffect *effect, VSTPluginLib &library)
+static void GetPluginInformation(bool maskCrashes, Vst::AEffect *effect, VSTPluginLib &library)
 {
 	unsigned long exception = 0;
-	library.category = static_cast<VSTPluginLib::PluginCategory>(CVstPlugin::DispatchSEH(effect, Vst::effGetPlugCategory, 0, 0, nullptr, 0, exception));
+	library.category = static_cast<VSTPluginLib::PluginCategory>(CVstPlugin::DispatchSEH(maskCrashes, effect, Vst::effGetPlugCategory, 0, 0, nullptr, 0, exception));
 	library.isInstrument = ((effect->flags & Vst::effFlagsIsSynth) || !effect->numInputs);
 
 	if(library.isInstrument)
@@ -443,7 +444,7 @@
 
 #ifdef MODPLUG_TRACKER
 	std::vector<char> s(256, 0);
-	CVstPlugin::DispatchSEH(effect, Vst::effGetVendorString, 0, 0, s.data(), 0, exception);
+	CVstPlugin::DispatchSEH(maskCrashes, effect, Vst::effGetVendorString, 0, 0, s.data(), 0, exception);
 	library.vendor = mpt::ToCString(mpt::Charset::Locale, s.data());
 #endif // MODPLUG_TRACKER
 }
@@ -452,7 +453,7 @@
 
 #ifdef MODPLUG_TRACKER
 // Add a plugin to the list of known plugins.
-VSTPluginLib *CVstPluginManager::AddPlugin(const mpt::PathString &dllPath, const mpt::ustring &tags, bool fromCache, bool *fileFound)
+VSTPluginLib *CVstPluginManager::AddPlugin(const mpt::PathString &dllPath, bool maskCrashes, const mpt::ustring &tags, bool fromCache, bool *fileFound)
 {
 	const mpt::PathString fileName = dllPath.GetFileName();
 
@@ -535,32 +536,39 @@
 	unsigned long exception = 0;
 	// Always scan plugins in a separate process
 	HINSTANCE hLib = NULL;
-	Vst::AEffect *pEffect = CVstPlugin::LoadPlugin(*plug, hLib, true);
-
-	if(pEffect != nullptr && pEffect->magic == Vst::kEffectMagic && pEffect->dispatcher != nullptr)
 	{
-		CVstPlugin::DispatchSEH(pEffect, Vst::effOpen, 0, 0, 0, 0, exception);
+#ifdef MODPLUG_TRACKER
+		ExceptionHandler::Context ectx{ MPT_UFORMAT("VST Plugin: {}")(plug->dllPath.ToUnicode()) };
+		ExceptionHandler::ContextSetter ectxguard{&ectx};
+#endif // MODPLUG_TRACKER
 
-		plug->pluginId1 = pEffect->magic;
-		plug->pluginId2 = pEffect->uniqueID;
+		Vst::AEffect *pEffect = CVstPlugin::LoadPlugin(maskCrashes, *plug, hLib, true);
 
-		GetPluginInformation(pEffect, *plug);
+		if(pEffect != nullptr && pEffect->magic == Vst::kEffectMagic && pEffect->dispatcher != nullptr)
+		{
+			CVstPlugin::DispatchSEH(maskCrashes, pEffect, Vst::effOpen, 0, 0, 0, 0, exception);
 
+			plug->pluginId1 = pEffect->magic;
+			plug->pluginId2 = pEffect->uniqueID;
+
+			GetPluginInformation(maskCrashes, pEffect, *plug);
+
 #ifdef VST_LOG
-		intptr_t nver = CVstPlugin::DispatchSEH(pEffect, Vst::effGetVstVersion, 0,0, nullptr, 0, exception);
-		if (!nver) nver = pEffect->version;
-		MPT_LOG(LogDebug, "VST", MPT_UFORMAT("{}: v{}.0, {} in, {} out, {} programs, {} params, flags=0x{} realQ={} offQ={}")(
-			plug->libraryName, nver,
-			pEffect->numInputs, pEffect->numOutputs,
-			mpt::ufmt::dec0<2>(pEffect->numPrograms), mpt::ufmt::dec0<2>(pEffect->numParams),
-			mpt::ufmt::HEX0<4>(static_cast<int32>(pEffect->flags)), pEffect->realQualities, pEffect->offQualities));
+			intptr_t nver = CVstPlugin::DispatchSEH(maskCrashes, pEffect, Vst::effGetVstVersion, 0,0, nullptr, 0, exception);
+			if (!nver) nver = pEffect->version;
+			MPT_LOG(LogDebug, "VST", MPT_UFORMAT("{}: v{}.0, {} in, {} out, {} programs, {} params, flags=0x{} realQ={} offQ={}")(
+				plug->libraryName, nver,
+				pEffect->numInputs, pEffect->numOutputs,
+				mpt::ufmt::dec0<2>(pEffect->numPrograms), mpt::ufmt::dec0<2>(pEffect->numParams),
+				mpt::ufmt::HEX0<4>(static_cast<int32>(pEffect->flags)), pEffect->realQualities, pEffect->offQualities));
 #endif // VST_LOG
 
-		CVstPlugin::DispatchSEH(pEffect, Vst::effClose, 0, 0, 0, 0, exception);
+			CVstPlugin::DispatchSEH(maskCrashes, pEffect, Vst::effClose, 0, 0, 0, 0, exception);
 
-		validPlug = true;
+			validPlug = true;
+		}
+
 	}
-
 	FreeLibrary(hLib);
 	if(exception != 0)
 	{
@@ -672,6 +680,8 @@
 	}
 
 #ifdef MODPLUG_TRACKER
+	bool maskCrashes = TrackerSettings::Instance().BrokenPluginsWorkaroundVSTMaskAllCrashes;
+
 	if(!pFound && (mixPlugin.GetLibraryName() != U_("")))
 	{
 		// Try finding the plugin DLL in the plugin directory or plugin cache instead.
@@ -682,7 +692,7 @@
 		}
 		fullPath += mpt::PathString::FromUnicode(mixPlugin.GetLibraryName()) + P_(".dll");
 
-		pFound = AddPlugin(fullPath);
+		pFound = AddPlugin(fullPath, maskCrashes);
 		if(!pFound)
 		{
 			// Try plugin cache (search for library name)
@@ -696,7 +706,7 @@
 					fullPath = theApp.PathInstallRelativeToAbsolute(fullPath);
 					if(fullPath.IsFile())
 					{
-						pFound = AddPlugin(fullPath);
+						pFound = AddPlugin(fullPath, maskCrashes);
 					}
 				}
 			}
@@ -710,18 +720,18 @@
 		HINSTANCE hLibrary = nullptr;
 		bool validPlugin = false;
 
-		pEffect = CVstPlugin::LoadPlugin(*pFound, hLibrary, TrackerSettings::Instance().bridgeAllPlugins);
+		pEffect = CVstPlugin::LoadPlugin(maskCrashes, *pFound, hLibrary, TrackerSettings::Instance().bridgeAllPlugins);
 
 		if(pEffect != nullptr && pEffect->dispatcher != nullptr && pEffect->magic == Vst::kEffectMagic)
 		{
 			validPlugin = true;
 
-			GetPluginInformation(pEffect, *pFound);
+			GetPluginInformation(maskCrashes, pEffect, *pFound);
 
 			// Update cached information
 			pFound->WriteToCache();
 
-			CVstPlugin *pVstPlug = new (std::nothrow) CVstPlugin(hLibrary, *pFound, mixPlugin, *pEffect, sndFile);
+			CVstPlugin *pVstPlug = new (std::nothrow) CVstPlugin(maskCrashes, hLibrary, *pFound, mixPlugin, *pEffect, sndFile);
 			if(pVstPlug == nullptr)
 			{
 				validPlugin = false;
Index: soundlib/plugins/PluginManager.h
===================================================================
--- soundlib/plugins/PluginManager.h	(revision 13970)
+++ soundlib/plugins/PluginManager.h	(working copy)
@@ -160,7 +160,7 @@
 	size_t size() const { return pluginList.size(); }
 
 	bool IsValidPlugin(const VSTPluginLib *pLib) const;
-	VSTPluginLib *AddPlugin(const mpt::PathString &dllPath, const mpt::ustring &tags = mpt::ustring(), bool fromCache = true, bool *fileFound = nullptr);
+	VSTPluginLib *AddPlugin(const mpt::PathString &dllPath, bool maskCrashes, const mpt::ustring &tags = mpt::ustring(), bool fromCache = true, bool *fileFound = nullptr);
 	bool RemovePlugin(VSTPluginLib *);
 	bool CreateMixPlugin(SNDMIXPLUGIN &, CSoundFile &);
 	void OnIdle();
vst-seh-v10.patch (24,641 bytes)   
manx

manx

2020-12-30 09:22

administrator   ~0004584

Comited as r13996 (1.30.00.23).

manx

manx

2020-12-30 11:04

administrator   ~0004587

Forum thread: https://forum.openmpt.org/index.php?topic=6537.0

Issue History

Date Modified Username Field Change
2020-12-22 17:04 manx New Issue
2020-12-22 17:04 manx Status new => assigned
2020-12-22 17:04 manx Assigned To => manx
2020-12-22 17:04 manx Relationship added related to 0001291
2020-12-22 17:05 manx Note Added: 0004557
2020-12-22 17:05 manx File Added: vst-seh-v10.patch
2020-12-22 17:06 manx Status assigned => feedback
2020-12-30 09:22 manx Note Added: 0004584
2020-12-30 11:04 manx Note Added: 0004587
2021-01-10 18:28 manx Status feedback => resolved
2021-01-10 18:28 manx Resolution open => fixed
2021-01-10 18:28 manx Fixed in Version => OpenMPT 1.30 / libopenmpt 0.6 (goals)