Windows dll 插件加载时崩溃
crash in Windows dll plugin on load
在加载 dll 时寻找有关在 Windows 中导致此类崩溃的原因的一些建议。
我正在用 C++ 编写 Windows VST3 .dll 插件,但在加载我的 .dll 时遇到启动崩溃。当 运行 主机应用程序和插件通过 Visual Studio 2019 调试器时,我得到上面显示的 Access violation executing location ...
对话框,调用堆栈是空的,让我觉得内存已完全损坏。
这可能是由于 link我在构建 .dll 时需要调整选项造成的?
以下是一些事实:
- 插件本身工作正常。当所有第 3 方 API 调用都被注释掉时,我可以毫无问题地加载和卸载它。
- 如果我 link 将一些第 3 方库添加到我的插件中,那么一切正常。
- 一旦我调用了那些第 3 方库中的 any,就会导致启动时出现段错误。
- 插件是使用 /MD 构建的,但我也尝试了 /MT 并看到了相同的行为。
- 我正在使用 JUCE C++ 获取 VST3 框架和 GUI 组件。
- 我 link 反对并试图调用的第 3 方库之一的示例是 SuperpoweredSDK C++ 库。但是我已经尝试过其他库,并且我看到每个库都有相同的行为。
不幸的是,将整个空白的 VST3 插件放在一起对于 Whosebug 问题中的 post 来说代码太多了。但是,如果我注释掉对第 3 方库的所有调用,我可以让插件工作,我不认为代码本身是问题,我认为 dll (.vst3) 文件的构建方式是问题。
构建 .vst3 dll 文件的 CMakeLists.txt
文件的关键部分如下所示:
FIND_LIBRARY ( SuperpoweredSDK NAMES SuperpoweredWin141_Debug_MD_x64.lib PATHS ${SUPERPOWERED_DIR}/libWindows )
SET ( TEST_EXTERNAL_DEPS PRIVATE Threads::Threads ${SuperpoweredSDK} )
FILE ( GLOB JUCE_SOURCE ${CMAKE_HOME_DIRECTORY}/JuceLibraryCode/*.cpp )
LIST ( FILTER JUCE_SOURCE EXCLUDE REGEX ".+/JuceLibraryCode/include_juce_audio_plugin_client_[^u].+" )
FILE ( GLOB PLUGIN_SOURCE *.cpp )
ADD_LIBRARY ( TestVST3 SHARED ${JUCE_SOURCE} ${PLUGIN_SOURCE} ${CMAKE_HOME_DIRECTORY}/JuceLibraryCode/include_juce_audio_plugin_client_VST3.cpp )
SET_TARGET_PROPERTIES ( TestVST3 PROPERTIES OUTPUT_NAME "Test" SUFFIX ".vst3" )
TARGET_LINK_LIBRARIES ( TestVST3 PUBLIC ${TEST_EXTERNAL_DEPS} )
what can cause a crash of this type in Windows when loading a dll
典型的原因是某些全局变量的初始值设定项。加载 DLL 时会崩溃的示例代码:
class C
{
public:
C() { __debugbreak(); } // Compiles into `int 3` interrupt, will definitely crash
};
static C g_c;
当您 link 一个外部库但不调用它时,linker 的死代码消除功能通常会删除完整的 .obj 文件,这些文件是 link 编辑但未使用的。这也会将变量连同它们的构造函数一起放到那里。
一种调试方法,在 DllMain 上设置断点。但不是您代码中的 DllMain
,而是另一个实际导出的代码。在 VC++ 2017 CRT 中,一个叫做 dllmain_dispatch
,它的源文件在 VC++ 运行时,crt\src\vcruntime\dll_dllmain.cpp
。 dllmain_dispatch 在调用你的 DllMain
之前调用了几个函数,其中一个 dllmain_crt_process_attach
调用了 _initterm
并且那个函数实际上调用了所有全局内容的构造函数。在你的情况下,至少有一个失败了。
P.S。像这样的崩溃的一个可能原因是,您的第三方库正在尝试使用 COM,而调用 LoadLibrary 的线程从未调用 CoInitialize()。
我们最终确实找到了这次崩溃的原因。对于 VST3 文件,DAW 加载每个 .dll(或 .vst3),查询功能,然后立即再次卸载 dll。然后它移动到下一个文件,整个过程重新开始,直到所有插件都被查询过。
在这种情况下,我使用的第 3 方库之一 (SuperpoweredSDK) 启动了一个后台线程,以根据某处的 Web 服务器验证许可证。这没有记录在案。随着后台线程的启动,DAW 不知不觉地继续卸载 DLL,使线程挂在那里 运行 不再存在的代码!因此,没有任何调用堆栈的崩溃。
几种可能的解决方案:
- 将 SuperpoweredSDK 初始化代码移到以后真正需要的时候。
- 在未来尚未发布的 SuperpoweredSDK 版本中(当前版本为 2.0.1),他们显然添加了一个 API 调用来关闭 Superpowered,并且该关闭调用将等到所有后台线程已完成 运行。确保将此命名为新的 API.
在加载 dll 时寻找有关在 Windows 中导致此类崩溃的原因的一些建议。
我正在用 C++ 编写 Windows VST3 .dll 插件,但在加载我的 .dll 时遇到启动崩溃。当 运行 主机应用程序和插件通过 Visual Studio 2019 调试器时,我得到上面显示的 Access violation executing location ...
对话框,调用堆栈是空的,让我觉得内存已完全损坏。
这可能是由于 link我在构建 .dll 时需要调整选项造成的?
以下是一些事实:
- 插件本身工作正常。当所有第 3 方 API 调用都被注释掉时,我可以毫无问题地加载和卸载它。
- 如果我 link 将一些第 3 方库添加到我的插件中,那么一切正常。
- 一旦我调用了那些第 3 方库中的 any,就会导致启动时出现段错误。
- 插件是使用 /MD 构建的,但我也尝试了 /MT 并看到了相同的行为。
- 我正在使用 JUCE C++ 获取 VST3 框架和 GUI 组件。
- 我 link 反对并试图调用的第 3 方库之一的示例是 SuperpoweredSDK C++ 库。但是我已经尝试过其他库,并且我看到每个库都有相同的行为。
不幸的是,将整个空白的 VST3 插件放在一起对于 Whosebug 问题中的 post 来说代码太多了。但是,如果我注释掉对第 3 方库的所有调用,我可以让插件工作,我不认为代码本身是问题,我认为 dll (.vst3) 文件的构建方式是问题。
构建 .vst3 dll 文件的 CMakeLists.txt
文件的关键部分如下所示:
FIND_LIBRARY ( SuperpoweredSDK NAMES SuperpoweredWin141_Debug_MD_x64.lib PATHS ${SUPERPOWERED_DIR}/libWindows )
SET ( TEST_EXTERNAL_DEPS PRIVATE Threads::Threads ${SuperpoweredSDK} )
FILE ( GLOB JUCE_SOURCE ${CMAKE_HOME_DIRECTORY}/JuceLibraryCode/*.cpp )
LIST ( FILTER JUCE_SOURCE EXCLUDE REGEX ".+/JuceLibraryCode/include_juce_audio_plugin_client_[^u].+" )
FILE ( GLOB PLUGIN_SOURCE *.cpp )
ADD_LIBRARY ( TestVST3 SHARED ${JUCE_SOURCE} ${PLUGIN_SOURCE} ${CMAKE_HOME_DIRECTORY}/JuceLibraryCode/include_juce_audio_plugin_client_VST3.cpp )
SET_TARGET_PROPERTIES ( TestVST3 PROPERTIES OUTPUT_NAME "Test" SUFFIX ".vst3" )
TARGET_LINK_LIBRARIES ( TestVST3 PUBLIC ${TEST_EXTERNAL_DEPS} )
what can cause a crash of this type in Windows when loading a dll
典型的原因是某些全局变量的初始值设定项。加载 DLL 时会崩溃的示例代码:
class C
{
public:
C() { __debugbreak(); } // Compiles into `int 3` interrupt, will definitely crash
};
static C g_c;
当您 link 一个外部库但不调用它时,linker 的死代码消除功能通常会删除完整的 .obj 文件,这些文件是 link 编辑但未使用的。这也会将变量连同它们的构造函数一起放到那里。
一种调试方法,在 DllMain 上设置断点。但不是您代码中的 DllMain
,而是另一个实际导出的代码。在 VC++ 2017 CRT 中,一个叫做 dllmain_dispatch
,它的源文件在 VC++ 运行时,crt\src\vcruntime\dll_dllmain.cpp
。 dllmain_dispatch 在调用你的 DllMain
之前调用了几个函数,其中一个 dllmain_crt_process_attach
调用了 _initterm
并且那个函数实际上调用了所有全局内容的构造函数。在你的情况下,至少有一个失败了。
P.S。像这样的崩溃的一个可能原因是,您的第三方库正在尝试使用 COM,而调用 LoadLibrary 的线程从未调用 CoInitialize()。
我们最终确实找到了这次崩溃的原因。对于 VST3 文件,DAW 加载每个 .dll(或 .vst3),查询功能,然后立即再次卸载 dll。然后它移动到下一个文件,整个过程重新开始,直到所有插件都被查询过。
在这种情况下,我使用的第 3 方库之一 (SuperpoweredSDK) 启动了一个后台线程,以根据某处的 Web 服务器验证许可证。这没有记录在案。随着后台线程的启动,DAW 不知不觉地继续卸载 DLL,使线程挂在那里 运行 不再存在的代码!因此,没有任何调用堆栈的崩溃。
几种可能的解决方案:
- 将 SuperpoweredSDK 初始化代码移到以后真正需要的时候。
- 在未来尚未发布的 SuperpoweredSDK 版本中(当前版本为 2.0.1),他们显然添加了一个 API 调用来关闭 Superpowered,并且该关闭调用将等到所有后台线程已完成 运行。确保将此命名为新的 API.