在 MS Visual C++ 中调试未处理异常的正确方法

Posted

技术标签:

【中文标题】在 MS Visual C++ 中调试未处理异常的正确方法【英文标题】:Right way to debug unhandled exception in MS Visual C++ 【发布时间】:2017-05-30 08:41:45 【问题描述】:

在 Microsoft Visual Studio C++(原生 c++,Visual Studio 2015)中调试未知未处理异常的正确方法是什么。 今天收到了异常(文:Exception thrown: read access violation. this was 0x4.):

按下“Break”按钮后显示的代码只是标准Qt framework标头qscopedpointer.h的代码:

现在我不知道这个问题的原因是什么。通常没问题,但知道我已经运行了在 VS 2012 中运行的始终正确的项目,现在我什至不确定这是否是一个真正的错误,或者我只需要取消选中“抛出此异常类型时中断” .

我不能从这一点“跳出”,查看调用堆栈也无法理解问题:

正文:

Qt5Cored.dll!QScopedPointer<QObjectData,QScopedPointerDeleter<QObjectData> >::data() Line 135   C++
    Qt5Cored.dll!qGetPtrHelper<QScopedPointer<QObjectData,QScopedPointerDeleter<QObjectData> > >(const QScopedPointer<QObjectData,QScopedPointerDeleter<QObjectData> > & p) Line 1014   C++
    Qt5Cored.dll!QWinOverlappedIoNotifier::d_func() Line 60 C++
    Qt5Cored.dll!QWinOverlappedIoNotifier::waitForAnyNotified(int msecs=1) Line 358 C++
    Qt5SerialPortd.dll!QSerialPortPrivate::waitForNotified(int msecs=1) Line 588    C++
    Qt5SerialPortd.dll!QSerialPortPrivate::waitForReadyRead(int msecs=1) Line 251   C++
    Qt5SerialPortd.dll!QSerialPort::waitForReadyRead(int msecs=1) Line 1309 C++
    MyProject.exe!UsualSep::send_cmd_and_receive_answer(const QByteArray & ba=..., QByteArray & ans=..., int nread=2) Line 797  C++
    MyProject.exe!UsualSep::isAvailable(bool & avbl=false) Line 204 C++
    MyProject.exe!UsualSep::on_workThread_started() Line 80 C++
    MyProject.exe!QtPrivate::FunctorCall<QtPrivate::IndexesList<>,QtPrivate::List<>,void,void (__thiscall UsualSep::*)(void)>::call(void(UsualSep::*)() f=0x00eb172b, UsualSep * o=0x007838d8, void * * arg=0x02bff91c) Line 501    C++
    MyProject.exe!QtPrivate::FunctionPointer<void (__thiscall UsualSep::*)(void)>::call<QtPrivate::List<>,void>(void(UsualSep::*)() f=0x00eb172b, UsualSep * o=0x007838d8, void * * arg=0x02bff91c) Line 520    C++
    MyProject.exe!QtPrivate::QSlotObject<void (__thiscall UsualSep::*)(void),QtPrivate::List<>,void>::impl(int which=1, QtPrivate::QSlotObjectBase * this_=0x029ee9d8, QObject * r=0x007838d8, void * * a=0x02bff91c, bool * ret=0x00000000) Line 143   C++
    Qt5Cored.dll!QtPrivate::QSlotObjectBase::call(QObject * r=0x007838d8, void * * a=0x02bff91c) Line 124   C++
    Qt5Cored.dll!QMetaObject::activate(QObject * sender=0x029ee9a0, int signalOffset=3, int local_signal_index=0, void * * argv=0x00000000) Line 3720   C++
    Qt5Cored.dll!QMetaObject::activate(QObject * sender=0x029ee9a0, const QMetaObject * m=0x670e5db0, int local_signal_index=0, void * * argv=0x00000000) Line 3595 C++
    Qt5Cored.dll!QThread::started(QThread::QPrivateSignal __formal=...) Line 156  C++
    Qt5Cored.dll!QThreadPrivate::start(void * arg=0x029ee9a0) Line 384  C++
    ucrtbased.dll!774f8968()    Unknown
    [Frames below may be incorrect and/or missing, no symbols loaded for ucrtbased.dll] 
    ucrtbased.dll!774f867b()    Unknown
    kernel32.dll!74fc336a() Unknown
    ntdll.dll!77169902()    Unknown
    ntdll.dll!771698d5()    Unknown

我的主要问题不是关于在这种特殊情况下该怎么做,而是调试此类异常的一般方法是什么

【问题讨论】:

此时d无效。您应该检查程序中调用它的堆栈跟踪以及为什么此时它无效。我强烈建议评估这个问题,不要忽视它。 【参考方案1】:

如果异常在调用堆栈中的某处有一个处理程序,可能无论如何都可以让它继续。但是,请仔细查看以确保您了解发生了什么。

如果调用堆栈指向您的代码,请从那里开始。我认为,在这种情况下,“MyProject.exe!UsualSep::send_cmd_and_receive_answer...”这最终会如何尝试获取数据d?你认为这是你设置的吗?

我的一般方法是尝试将问题缩小到一个小的独立函数并将其包装在一个可以自动运行的测试中,该测试会重复该问题。然后尝试修复它。也许您需要尝试isNull 作为代码中某处的检查?

【讨论】:

【参考方案2】:

如果您选中“抛出此异常类型时中断”,那么我猜在下一次调试运行时,您将在抛出异常时打开调试器,这很可能会告诉您问题所在。

如果您处理异常,当然它不再一定是错误。您可以通过在 main 中的 try 块中处理异常来进行一些困难的调试,然后深入了解程序的哪个部分引发了异常。

Qt 中可能存在错误,而不是您自己的代码。如果是这样,它可能是非常模糊的东西——Qt 已针对大多数现实世界的一般用途进行了测试——但很难找到。但是堆栈跟踪表明您的函数 send_cmd_and_receive_answer() 有问题。很可能它用它不拥有的内存调用 Qt,或者换句话说,它传递了一个野指针。

【讨论】:

以上是关于在 MS Visual C++ 中调试未处理异常的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

启用“仅我的代码”时,Visual Studio 2015 JavaScript 调试不会捕获未处理的异常

防止 Visual Studio 调试因明显的“未处理异常”而中断

MS Visual Studio 2010 C++ 预处理器 - 如果函数在宏中定义并在其他地方调用,未定义时是不是有任何开销

c++ 未处理的异常 - 如何调试

Visual Studio 不会因用户未处理的异常而中断

Visual Studio 2008 发布版本上的 c++ 应用程序出现未处理异常 - 从函数返回时发生