我有继承的代码,如下所示:
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()
。
删除了代码以节省空间。要查看它,请查看编辑历史记录。