VST3 SDK:ClassInfo 对象中 std::string 成员的构造有问题,导致程序崩溃

VST3 SDK: Problematic construction of std::string member in ClassInfo object causes program to crash

提问人:Yuwei Xu 提问时间:8/27/2023 最后编辑:Daniel A. WhiteYuwei Xu 更新时间:8/28/2023 访问量:714

问:

问题:

我正在尝试使用 SDK 中包含的 VST Hosting 实用程序来加载插件。代码如下图所示:

#include "vst/v3/Vst3CommonIncludes.h"

int main()
{
    std::string vst3_module_path = R"(C:\Program Files\Common Files\VST3\Kontakt.vst3)";
    std::string error;
    std::shared_ptr<Module> vst_module = Module::create(vst3_module_path, error);
    std::vector<ClassInfo> class_infos = vst_module->getFactory().classInfos();;

    assert(error.empty());
    assert(class_infos.size());

    ClassInfo plugin_info = class_infos[0]; //Crash
    //... load the plugin and do more things
    return 0;
}

其中仅包含 8 和 8 的所有 VST SDK 标头Vst3CommonIncludes.hpluginterfaces/vstpublic.sdk/source/vst

就我而言,SDK 在源代码和 cmake 文件中提供,以将它们构建到静态库中。所以我的代码和 SDK 代码共享同一个编译器。

VST SDK 源自 Steinberg Media


调查完成:

我的调查显示,返回的损坏数据,试图从中分配原因,因为大小无效。PluginFactory::classInfos()std::bad_allocstd::string

VST SDK 中 PluginFactory::classInfos() 的定义:

PluginFactory::ClassInfos PluginFactory::classInfos () const noexcept
{
    auto count = classCount ();
    Optional<FactoryInfo> factoryInfo;
    ClassInfos classes;
    classes.reserve (count);
    auto f3 = Steinberg::FUnknownPtr<Steinberg::IPluginFactory3> (factory);
    auto f2 = Steinberg::FUnknownPtr<Steinberg::IPluginFactory2> (factory);
    Steinberg::PClassInfo ci;
    Steinberg::PClassInfo2 ci2;
    Steinberg::PClassInfoW ci3;
    for (uint32_t i = 0; i < count; ++i)
    {
        if (f3 && f3->getClassInfoUnicode (i, &ci3) == Steinberg::kResultTrue)
//------------Unexpected behaviour here--------------------
            classes.emplace_back (ci3);                //--
//---------------------------------------------------------
        else if (f2 && f2->getClassInfo2 (i, &ci2) == Steinberg::kResultTrue)
            classes.emplace_back (ci2);
        else if (factory->getClassInfo (i, &ci) == Steinberg::kResultTrue)
            classes.emplace_back (ci);
        auto& classInfo = classes.back ();
        if (classInfo.vendor ().empty ())
        {
            if (!factoryInfo)
                factoryInfo = Optional<FactoryInfo> (info ());
            classInfo.get ().vendor = factoryInfo->vendor ();
        }
    }
    return classes;
}

在就地构造新的 ClassInfo 元素后,其他成员(名称、供应商等)将在调试器中读取。ClassInfo::data::categorystd::string<NULL>

单步进入 的构造函数,我发现构造过程中的指针不等于 ,并且偏移了 4 个字节。std::stringthisdata.category&data.category

&data.category = 0x 0000 009b 546f ed14
this (std::string constructor scope) = 0x 0000 009b 546f ed18
//Actual address varies but the offset remains the same

因此,字符串对象已损坏,后来导致程序崩溃。

其他信息:


std::string 相关实验:

此外,在试验及其字符串成员时,我遇到了这种情况:ClassInfo

ClassInfo ci;
ci.get().category = "testCategory";                  //OK
const_cast<string&>(ci.category()) = "testCategory"; //Crash, Access violation at 0xFFFFFFFFFFFFFFFF

我认为这与问题高度相关,但我无法想出一个解释。

C++ 标准一致性:

我还添加了

#if __cplusplus != 201703L
#error
#endif

到每个相关文件,所以我相信它们共享相同的 STL 实现,问题仍然会发生。

重现尝试:

我希望重新创建一个不包括 VST SDK 的最小场景,并且我自己的场景在某些方面类似于原始结构。不会发生此问题。MimicClassInfoClassInfo


编译器和 SDK 信息:

MSVC 14.37.32822,使用 C++17 标准。 VST SDK 3.7.8 build 34 (2023-05-15)

C 可视化 C++ VST

评论

20赞 Adrian Mole 8/27/2023
请注意,这个问题以及已采取的策展行动正在 Meta 上讨论
0赞 273K 8/28/2023
元上有这么多的抱怨和噪音,但它仍然缺乏有关如何构建静态库和代码的信息,以及一个可兼容的最小可重现示例,忽略了缺少的依赖项。为什么不尝试使用启用的地址清理器来构建它们呢?
5赞 273K 8/28/2023
ci.get().category = "testCategory"; //OK- 在这里,你使用在头文件中实现的内联,因此它是在你的代码中编译的。 - 在这里,你调用它不是内联的,而是在库中实现的。这是 ABI 不兼容的明显迹象。也许混合 64 位和 32 位目标文件。get()const_cast<string&>(ci.category()) = "testCategory"; //Crash, Access violation at 0xFFFFFFFFFFFFFFFFcategory()
1赞 Yuwei Xu 8/28/2023
@273K 感谢您的帮助,ABI 的论点让人大吃一惊。我现在正在朝这个方向检查。
3赞 Adrian Mole 8/29/2023
@273K 混合 32 位和 64 位目标文件/库几乎肯定会导致 MSVC 出现链接器错误。不是运行时问题。

答: 暂无答案