【问题标题】:C++ binary compatible dll POD class member initialization causes crashC++ 二进制兼容 dll POD 类成员初始化导致崩溃
【发布时间】:2013-05-14 05:40:52
【问题描述】:

我正在尝试在使用 mingw 构建的 dll 中创建一个可在 Windows VS 应用程序中使用的相互编译器兼容的类。我的问题是,当从 VS 程序调用函数时,我的类在尝试初始化成员变量时崩溃。使用 STL 或在同一函数中创建局部变量都可以正常工作。

ConsoleApplication2.exe 中 0x6BEC19FE (test.dll) 处未处理的异常:0xC0000005:访问冲突写入位置 0x154EB01E。

简单演示:

dll代码

#include <iostream>

class Tester 
{
public:

    virtual void test() = 0;
};

class TesterImp : public Tester
{
public:
    TesterImp(){}
    ~TesterImp(){}

    virtual void test() { 
        int test = 5; // fine
        m_test = 5; // access violation
    }

private:

    int m_test;

};

    extern "C"
    {
        __declspec (dllexport) Tester* Create()
        {
            return new TesterImp();
        }
    }

加载dll并调用测试函数的主程序:

#include <iostream>
#include <Windows.h> 

class Tester 
{
public:

    virtual void test() = 0;
};

typedef Tester* (*createPtr)();

int main(int argc, const char **argv, char * const *envp) {

  HINSTANCE hGetProcIDDLL = LoadLibraryA("test.dll");

  if (hGetProcIDDLL == NULL) {
    std::cout << "could not load the dynamic library" << std::endl;
    return EXIT_FAILURE;
  }

  createPtr ctr = (createPtr)GetProcAddress(hGetProcIDDLL, "Create");
  if (!ctr) {
    std::cout << "could not locate the function" << std::endl;
    return EXIT_FAILURE;
  }

  std::cout << "dll loading success!" << std::endl;

  Tester* testf = ctr();

  std::cout << "Got test class" << std::endl;

  testf->test(); // crash if the member variable is referenced, fine otherwise with local variable initialization or STL use inside the function

  std::cout << "Running dll functions success!" << std::endl;

  return 0;
}

主程序是用VS2012调试模式编译的,dll是用mingw的g++编译的-

g++ -shared -o test.dll test.cpp

有人可以为我解释一下这种行为吗?

谢谢。

【问题讨论】:

  • 我会首先确保您的调用约定匹配,然后使用调试器进入ctr(),它几乎会立即告诉您问题所在。我也不完全清楚您声称通过抽象基接口使用虚拟方法访问动态分配的派生类在哪里符合 C++ 中的 POD-anything
  • Tester 不是 POD。
  • 我将 int m_test 称为 POD 类成员。
  • 不幸的是,我无法通过 VS 调试该功能,因为 mingw 不会生成 VS 用于调试的符号文件。
  • 好吧,我已经尝试弄乱调用约定但无济于事,看来我可能需要将整个接口编写为导出的 C 样式函数。

标签: c++ visual-studio dll mingw binary-compatibility


【解决方案1】:

您可能使用的是旧版本的 MinGW。直到 4.7.0(我认为),MinGW 在堆栈上传递了 this 指针,这不同于 MSVC 的 thiscall 约定在 this 中传递 this 指针ecx

从 4.7.0 开始,MinGW 使用与 MSVC 相同的 thiscall 调用约定。

我还可以通过在test.cpp 中使用__attribute__((thiscall)) 属性标记Tester::test()TesterImp::test() 来成功地从MSVC 调用示例TesterImp::test() 函数。这适用于 MinGW 4.6.2,如果不使用该属性会导致崩溃。

【讨论】:

  • 你说得对,我刚刚检查了 gcc 版本,它是 4.62(不知道是怎么回事,我从 mingw 站点获得了最新的软件包安装程序)。非常感谢您的宝贵时间,您真的帮助了我!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多