MinGW 4.7.0到4.7.2 bug:使用混合虚拟和非虚拟多重继承时,成员函数中的“this”指针无效

时间:2013-09-29 03:04:23

标签: c++ mingw multiple-inheritance virtual-inheritance

我有继承的代码,如下所示:

        B
       / \
      /   \
     /     \
    BI      D
(template) /
      \   /
       \ /
        DI
    (template)

[B]ase[D]erived是包含static方法create()的接口,它返回相应实现的实例BaseImpl或{{1 }}。 实现是模板,工厂方法选择如何在运行时实例化它们。下面的代码是我程序逻辑的一个工作示例。

问题是,在我的实际代码中,DerivedImpl方法会出现错误的Base指针并且不可避免地会崩溃。我在调用其中一个方法之前检查了汇编代码,这个方法在实例和示例代码中都没有参数,并且发现它有所不同:

工作(示例)代码

this

上述内容转换为call <std::unique_ptr<Base, std::default_delete<Base> >::operator->() const> mov (%eax),%edx add $0x8,%edx mov (%edx),%edx mov %eax,%ecx call *%edx 来电,其中base->method()base。 对于那些不知道的人来说,类方法的调用约定可以是__thiscall,在这种情况下就是{{3}}。这意味着std::unique_ptr<Base>不会在堆栈上传递,而是存储在this中。上面的代码只是将ecx存储到this,然后找到ecx,将其地址存储到method(),然后调用它。一切都按预期工作。

有缺陷的(实际)代码

edx

这是完全相同的call <std::unique_ptr<Base, std::default_delete<Base> >::operator->() const> mov (%eax),%edx add $0x18,%edx mov (%edx),%ebx lea -0x24(%ebp),%edx mov %eax,(%esp) movl $0x9,-0x9c(%ebp) mov %edx,%ecx call *%ebx 电话。这次base->method()的地址存储在method()中。但是,ebx是从堆栈中的任意位置加载的!正如预期的那样,该计划崩溃了。任何人都知道为什么编译器会生成这样的程序集?我还在努力解决这个问题。

代码

示例代码如下。真实代码崩溃的时间类似于示例从this调用base->check()

删除了代码以节省空间。要查看它,请查看编辑历史记录。

1 个答案:

答案 0 :(得分:0)

这是一个错误。 (551735536755453)该错误特定于gcc-i686-mingw个版本4.7.04.7.2

来自55173

  

当对同时使用虚拟和非虚拟继承的对象调用虚拟调用时,虚拟thunk将使用无效的“this”指针离开目标函数。

这基本上就是我在问题中描述的内容。应该保留this的寄存器用于非相关操作。

唯一的解决方案是降级到4.7.0以下或升级到4.7.3或更高。