我有一个让我困惑的崩溃,到目前为止,我发现不可能始终如一地重现。代码使用 Visual Studio 2008 编译。
(当然是简化的)源代码如下所示:
class AbstractParentClass
{
private:
/* data members */
public:
AbstractParentClass();
/*
virtual functions ...
*/
};
class ChildClass : public AbstractParentClass
{
private:
/* data members */
public:
ChildClass();
/*
overridden/implemented virtual functions ...
*/
};
void DifferentClass::func(const char ** strs)
{
ChildClass child_class;
int i = 0;
[...]
}
崩溃转储的反汇编如下所示:
Library!DifferentClass::func:
612cab20 83ec58 sub esp,58h
612cab23 56 push esi
612cab24 57 push edi
612cab25 8bf9 mov edi,ecx
612cab27 8d4c2420 lea ecx,[esp+20h]
612cab2b e8e053403f call a06cff10
612cab30 8b742464 mov esi,dword ptr [esp+64h]
[...]
将 func() 的源映射到反汇编,它最终看起来像这样:
Library!DifferentClass::func:
void DifferentClass::func(const char ** strs)
{
612cab20 83ec58 sub esp,58h
612cab23 56 push esi
612cab24 57 push edi
612cab25 8bf9 mov edi,ecx
ChildClass child_class;
612cab27 8d4c2420 lea ecx,[esp+20h]
612cab2b e8e053403f call a06cff10
int i = 0;
612cab30 8b742464 mov esi,dword ptr [esp+64h]
[...]
}
在成功运行中(不同的机器,即使在同一台机器上,崩溃也不能可靠地重现),反汇编的唯一区别是调用指令,它最终正确映射到 ChildClass 的默认构造函数的地址,如这个:
00404e8b call ChildClass::ChildClass (40a3d0h)
而不是喜欢:
612cab2b call a06cff10
因此,在崩溃运行中,用作调用指令参数的 a06cff10 地址似乎来自谁知道在哪里,并且没有特别映射到任何东西。因此,可以预见的是,尝试访问该地址(以访问 ChildClass 默认构造函数)会导致访问冲突:
EXCEPTION_RECORD: 0012f688 -- (.exr 0x12f688)
ExceptionAddress: a06cff10
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: a06cff10
Attempt to read from address a06cff10
任何在故障转储中查看该地址的尝试确实表明该地址超出了进程的范围。
更新:因此,在阅读了来自 zvrba 的以下响应并进一步查看之后,有问题的调用似乎是静态库中的十几个函数调用中的第一个(这又是由 DLL 加载的),它们都有一个不正确的函数偏移。它们不是同一类中的所有功能。尽管所有类(调用和被调用的)都存在于同一个静态库中,但有三四个不同的类的功能受到影响。在第一个崩溃的调用中,指令是 e8e053403f 并且该指令中的 3F4053E0 偏移量应该偏移量仅为 53E0。所有其他实例都有相同的偏移问题。指令中的偏移量是 3F40XXXX,应该是 XXXX。额外的 3F400000 当然是将东西送到 Never Never Land。到目前为止,我还没有找到关于反汇编中的哪些函数地址有效以及哪些无效的模式。库中 DifferentClass 的一个成员函数将对 ChildClass 的所有调用都视为错误,而另一个成员函数 DifferentClass 将对 ChildClass 进行不同的调用看起来很好。
有没有人看到过这样的事情/对可能的原因有任何想法?