Visual Studio 2008-vftable指针不正确?调试模式崩溃,发布即可

Visual Studio 2008 - vftable pointer incorrect? Debug mode crashes, Release is fine

本文关键字:崩溃 模式 布即可 调试 Studio 2008-vftable 指针 不正确 Visual      更新时间:2023-10-16

我当前面临VS08的问题。我得到了以下(简化的)类结构:

class CBase
{
    public:
    virtual void Func() = 0;
};
class CDerived : public CBase
{
public:
    void Func();
};

这段代码在发布模式下运行良好,但当我尝试运行调试构建时,它会在new CDerived上立即崩溃。

进一步的分析使我找到了坠机地点。它在CBase::CBase(编译器生成的构造函数)上崩溃。更确切地说,它在04AE46C6 mov dword ptr [eax],offset CBase:: vftable"(505C2CCh)"处崩溃。

有线索吗?发布模式很好,但我不能用它正确调试。

释放模式良好

没有,看起来很好。我的猜测是,在调试中,内存被某种方式覆盖了。由于无法仅从您发布的代码中判断,以下是您可以做的。

我假设你在某个地方创建了一个对象:

CBase* p = new CDerived;

或类似的。在调试模式下,在p的位置设置内存断点。您可以将其设置为监视4个字节。Visual C++(像大多数编译器一样)将把vfptr作为类中的第一件事,因此这个断点将跟踪该位置是否被覆盖。如果在调用崩溃的函数之前遇到了断点,那么这就是问题所在(调用堆栈将显示它被覆盖的原因)。

这可能有很多原因——你可能会占用一些内存并覆盖对象(正如Erik所建议的)——发布版本可能会直接解析调用,以防止动态调度的开销,这也解释了为什么它没有崩溃。

也可能是您在对象上调用delete,而调试版本实际上会将内存清零,而发布版本则不会。没有办法从中辨别。

Necro在这里发布了一些帖子,但我想为未来的访客指出一点。。。

正如其他人所说,这可能是内存损坏或免费+重用问题。您不应该仅仅因为能够通过更改编译器设置或重新排列代码来消除崩溃就认为这是一个编译器错误。如果这是一个损坏错误,您可能会将损坏移到一些不会导致程序崩溃的内存中——而不是在您当前的构建中,在您当前OS&无论如何,架构。

简单地达到不崩溃的地步可能已经足够满足你的即时需求了,但与此同时,你没有学会避免最初导致你编写错误的任何练习。工程师中有一句由来已久的谚语,可能还有相当多的其他学科:

"自行消失的东西可以自行回来。"

这可能是任何形式的工程中最真实、最重要的谚语之一。如果你没有亲眼看到虫子死去,你应该一直为此感到焦虑。它会深深地困扰你。这个bug可能仍然存在,等待你下一个里程碑的夜晚,然后再重新抬头。

Luchian Grigore就找到内存断点的真正问题给出了很好的建议。