我的继承代码如下所示:
B
/ \
/ \
/ \
BI D
(template) /
\ /
\ /
DI
(template)
[B]ase
并且[D]erived
是同时包含static
方法的接口,该方法create()
返回相应实现的实例,BaseImpl
或者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
a 是std::unique_ptr<Base>
. 对于那些不知道的人,类方法的调用约定可以是__thiscall,在这种情况下就是这样。这意味着它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()
from的点崩溃invoker->invoke()
。
删除代码以节省空间。要查看它,请检查编辑历史记录。