为什么我的函数在更改visual studio版本后崩溃? 我在C++中有一个旧的32位MFC应用程序,它是用Visual Studio 2010编写的。它运行起来没有问题。现在我不得不升级到Visual Studio 2017,当我点击treeview窗口时,它经常崩溃。我有一个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); }

为什么我的函数在更改visual studio版本后崩溃? 我在C++中有一个旧的32位MFC应用程序,它是用Visual Studio 2010编写的。它运行起来没有问题。现在我不得不升级到Visual Studio 2017,当我点击treeview窗口时,它经常崩溃。我有一个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); },c++,visual-studio,access-violation,C++,Visual Studio,Access Violation,当我返回通话列表时,我在这里结束: //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 { i

当我返回通话列表时,我在这里结束:

//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,但是当我查看调试器中的值时,对于某些值,内存是不可读的

有什么问题吗?对于旧版本的VisualStudio,我没有这个问题。我只重新编译了这个项目,我必须将目标操作系统设置为Windows XP

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

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

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

的使用非常令人担忧

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

更糟糕的是,它只在调试构建中起作用

在非调试构建中,如果lp不为NULL,则为非零;否则为0

这并不能保证这就是你想要的。如果删除对象,内存很可能仍在应用程序中,可以重新使用,而不会返回到操作系统,类似于
AfxIsValidAddress
的内容将返回true。更糟糕的是,当分配器确实重用该内存时,它仍将返回true,而指针现在实际上引用了一些完全不同的未知对象,从而导致堆损坏

这适用于所有类似的函数,如
IsBadReadPtr
。雷蒙德·陈(Raymond Chen)有一篇微软的博客文章

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

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


访问冲突,以及在各种平台上的这种情况不是C++异常。由于它们通常只发生在程序内存损坏之后,因此基本上不可能从中恢复。通常有一些特定于平台的方法与它们交互。

NULL
不是指针唯一的无效地址。你确定它已经初始化了吗?你确定指向它的对象存在并且没有被销毁吗?事实上,您有类似于
this!=NULL
并检查对象
指向的内存是否有效,这会让我相信您的代码可能充满了未定义的行为,任何行为都可能导致您观察到的问题。我的问题是,我没有首先编写此代码。这是一个更大的项目,我只需要用更新的VisualStudio重新编译它。有没有办法检查指针是否有效?我和你一起想空的和空的,我站在拯救的一边。我查看了该类,该指针初始化为null,在函数中只设置了一次,在关闭方法中只删除了一次。这可能是一个配置问题,因为您正在迁移到另一个版本的Visual Studio。确保所有组件,包括.Obj+文件和带有C++链接(静态和动态)的库,都使用相同的VC++使用兼容的参数重新编译。这也可能是UB使用新的编译器以不同的方式表达自己的结果。确保编译时不进行优化,以帮助发现问题。仔细浏览代码,看看调试器在什么时候不能再报告对象的内部。我可能会注意到,这项检查是在MFC函数中进行的,CObject::IsKindOf不是我自己编写的程序代码中的任何内容。根据定义,达到未定义行为的代码可以显示任何行为。此行为可以在任何时间因任何原因而更改,包括更改编译器。我所说的“UB以不同的方式表达自身的结果”是指,您的代码可能包含未定义的行为,这些行为用于显示自己做了开发人员期望的任何事情,但更改编译器改变了该行为,从而导致程序崩溃。这不是更改编译器的问题,而是代码不正确的问题。不幸的是,到目前为止,这只发生在没有IDE的测试系统上。我是否也可以调试带有取消标记的优化的发布版本,或者我是否需要调试版本?我是否可以调试带有取消标记的优化的发布版本?是的,调试RelWithDebInfo配置。还可以更改设置,这样就不会进行优化。@Fellnase如果必须,您可以进行远程调试,尽管经验并不完美。如果调试构建在测试系统上失败,但不是本地失败,那么这很有用,无论哪种方式,调试发布崩溃都是相当困难的。