我在C ++中使用Visual Studio 2010编写了一个旧的32位MFC应用程序。它运行没有问题。现在我不得不升级到Visual Studio 2017,当我点击树视图窗口时,它经常崩溃。我有一个dmp文件,当我打开它然后我看到它在这里崩溃:
BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
ENSURE(this != NULL);
// it better be in valid memory, at least for CObject size
ASSERT(AfxIsValidAddress(this, sizeof(CObject)));
// simple SI case
CRuntimeClass* pClassThis = GetRuntimeClass(); //---->HERE Crash
ENSURE(pClassThis);
return pClassThis->IsDerivedFrom(pClass);
}
当我回到通话清单然后我在这里结束:
//m_pTheModel is initialized with NULL
if (bValidValue == true)
m_pTheModel = GetModel((WORD)lHint);
if (m_pTheModel == NULL || !AfxIsValidAddress(m_pTheModel, sizeof(m_pTheModel)))
{
lock.Unlock();
return;
}
try
{
if ((m_pTheModel->IsKindOf(RUNTIME_CLASS(CMyClassModel))))
...
}
catch (...)
{
}
m_pTheModel不是NULL但是当我查看调试器中的值时,对于某些值,内存不可读。
问题是什么?随着旧版Visual Studio我没有遇到这个问题。我只重新编译了这个项目,我不得不将目标操作系统设置为Windows XP。
错误消息是“线程试图读取或写入其没有适当访问权限的虚拟地址”。
我也不明白为什么我不能用我的try-catch来捕获这个访问冲突。
更新:我找到了原因。覆盖我的指针是一个strcpy。
使用AfxIsValidAddress
非常令人担忧。
测试任何内存地址以确保它完全包含在程序的内存空间中。
更糟糕的是,它只适用于调试版本。
在非调试版本中,如果lp不为NULL,则为非零;否则为0。
这并不能保证它根本就是你想要的。如果删除一个对象,则内存可能仍在应用程序中,可以重用,而不是返回给操作系统,而AfxIsValidAddress
之类的内容将返回true。更糟糕的是,当你的分配器确实重用了那个内存时,它仍然会返回true,而指针实际上现在指的是一些完全不同的未知对象,导致堆损坏。
这适用于所有类似的功能,如IsBadReadPtr
。 Raymond Chen有一篇微软博客文章IsBadXxxPtr should really be called CrashProgramRandomly。
你可能需要在IDE中调试它并找到一个特定的问题,它几乎可以肯定是在免费问题之后使用,或者是程序中其他地方覆盖对象的更严重的问题。你能直接在IDE中生成它而不是获取转储文件吗?
我也不明白为什么我不能用我的try-catch来捕获这个访问冲突
访问冲突等在各种平台上都不是C ++异常。而且由于它们通常只发生在程序内存损坏后,基本上无法从中恢复。通常有一些特定于平台的方法与它们进行交互。