首页 > 解决方案 > 为什么更改 Visual Studio 版本后我的函数会崩溃?

问题描述

我有一个用 Visual Studio 2010 编写的 C++ 中的旧 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,但是当我查看调试器中的值时,对于某些值,内存不可读。

问题可能是什么?使用旧版本的视觉工作室我没有这个问题。我只重新编译了这个项目,我不得不将目标操作系统设置为 Windows XP。

错误消息是“线程试图读取或写入它没有适当访问权限的虚拟地址。”</p>

我也不明白为什么我不能用我的 try-catch 来捕捉这个访问冲突。

更新: 我找到了原因。这是一个覆盖我的指针的 strcpy。

标签: c++visual-studioaccess-violation

解决方案


的使用AfxIsValidAddress非常令人担忧。

测试任何内存地址以确保它完全包含在程序的内存空间中。

更糟糕的是,它只适用于调试版本

在非调试版本中,如果 lp 不为 NULL,则为非零;否则为 0。

这并不能保证它是你想要的。如果你删除一个对象,内存可能仍在应用程序中准备好被重用,而不是返回给操作系统,并且类似的东西AfxIsValidAddress将返回 true。更糟糕的是,当您的分配器确实重用该内存时,它仍然会返回 true,而指针现在实际上指向的是一些完全不同的未知对象,从而导致堆损坏。

这适用于所有类似的功能,例如IsBadReadPtr. Raymond Chen 有一篇 Microsoft 博客文章IsBadXxxPtr 真的应该被称为 CrashProgramRandomly

您可能必须在 IDE 中对此进行调试并找到一个特定问题,这几乎可以肯定是免费问题后的使用,或者是覆盖对象的程序中其他地方的更严重问题。您可以直接在 IDE 中生成它而不是获取转储文件吗?

我也不明白为什么我不能用我的 try-catch 来捕捉这个访问冲突

各种平台上的访问冲突等都不是 C++ 异常。而且由于它们通常仅在程序内存损坏后发生,因此基本上无法恢复。通常有一些特定于平台的方法可以与它们进行交互。


推荐阅读