11

我正在调试一个缺陷,并将其缩小到对象的 vtable 指针0xdddddddd此答案表明 Win32 调试版本通常会将死内存或已删除的内存设置为此特殊值。

请注意,指针本身看起来是有效的,它只是vtable 指针0xdddddddd

这是一段代码:

std::list<IMyObject*>::const_iterator it;
for (it = myObjects.begin(); it != myObjects.end(); ++it)
{
    IMyObject* pMyObject = *it;
    if (pMyObject == 0)
        continue;

    pMyObject->someMethod(); // Access violation     
}

如果我在访问冲突的行中断并观察pMyObject,我可以看到它pMyObject本身有一个有效的地址(0x08ede388)但__vfptr成员是无效的(0xdddddddd)。

一些注意事项:

  • 这是一个单线程应用程序,所以这很可能不是竞争条件或互斥问题。
  • 似乎没有任何明显的问题,例如在访问之前删除调用堆栈中的对象。
  • 这个问题似乎只能在 Windows 2008 服务器上重现,但不能在 Windows 7 上重现。

关于如何进一步调试的任何建议?

4

4 回答 4

12

您在释放指针后使用它。从析构函数的断点获取堆栈跟踪以查看删除它的内容。或者更好的是,使用 shared_ptr<> 来避免这个问题。

于 2011-04-19T07:42:26.057 回答
2

好吧,哇,所以我多年来一直在用 c++ 编程,直到现在才发现这一点……实际上有一些幻数/幻数调试值,您可以在调试时查找原始指针的情况!

请参见此处:在 Visual Studio C++ 中,内存分配表示形式是什么?

在这里:https ://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_debug_values

于 2018-05-28T21:34:37.583 回答
1

如果启动程序,请在创建对象的位置放置一个断点。然后添加一个内存断点。如果您覆盖或删除内存,这将触发。好吧,或者以任何方式改变它。

如果内存没有被覆盖,您的对象将看起来正确,但您的 vtable 可能不取决于编译器的细节。

如果您使用继承,也可能是大小问题。如果您使用任何类型的存储桶内存或通过指针以外的任何方式存储对象。

于 2011-04-19T08:02:32.900 回答
1

如果 pMyObject->someMethod() 最终修改了 myObjects 列表,它将使任何当前迭代器无效。

此外,如果指针数据已被删除,这将触发相同的问题。

于 2013-11-21T00:04:06.890 回答