MSVC17调试器未处理异常行为异常问题咨询
MSVC17调试器异常行为问题分析
问题复现
第一段代码
#include <iostream> int main() { throw std::exception(); std::cout << "Hello World!" << std::endl; return 0; }
- 未附加调试器:未处理异常正常终止程序
- 附加调试器:触发异常后点击「Continue」,代码继续执行,仿佛异常从未发生(Linux GDB中测试会正常终止程序)
第二段代码
#include <iostream> int main() { try { throw std::exception(); } catch (...) { throw; } std::cout << "Hello World!" << std::endl; return 0; }
- 附加调试器:触发异常后点击「Continue」,出现访问冲突:
调试器陷入停滞Exception thrown at 0x0000000000000000 in ConsoleApplication1.exe: 0xC0000005: Access violation executing location 0x0000000000000000.
编译参数:
/JMC /permissive- /ifcOutput "ConsoleA.5d991025\x64\Debug\" /GS /W3 /Zc:wchar_t /ZI /Gm- /Od /sdl /Fd"ConsoleA.5d991025\x64\Debug\vc143.pdb" /Zc:inline /fp:precise /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /FC /Fa"ConsoleA.5d991025\x64\Debug\" /EHsc /nologo /Fo"ConsoleA.5d991025\x64\Debug\" /Fp"ConsoleA.5d991025\x64\Debug\ConsoleApplication1.pch" /diagnostics:column
问题解答
1. 为何调试器跳过未处理异常不终止程序?
这是MSVC调试器的**「仅我的代码(JMC)」**特性导致的。当启用JMC(编译参数包含/JMC)时,调试器会把标准库、系统代码标记为「非用户代码」。对于未处理的C++异常,调试器拦截后若判定异常来自非用户代码(或无用户代码的异常处理逻辑),点击「Continue」时会尝试跳过异常,让程序继续执行——这是为了方便开发者调试时忽略系统/库抛出的非关键异常,聚焦自身代码。
但实际上此时程序状态已被异常破坏,继续执行属于未定义行为,只是恰好能走到后续代码而已。
2. 为何第二段代码表现不同?
第二段代码中,异常被用户代码的catch(...)捕获后重新抛出,此时重新抛出的异常会被调试器判定为「用户代码发起的未处理异常」。点击「Continue」后,调试器找不到有效异常处理逻辑,程序进入Windows未处理异常流程,最终触发访问冲突——因为程序栈已处于异常展开的错误状态,没有合法后续执行路径,导致执行到空地址。
3. 能否关闭该「特性」?
可以,有两种方式:
- 编译时关闭JMC:移除编译参数中的
/JMC,重新编译程序。调试器会将所有代码视为待调试代码,未处理异常点击「Continue」后会按正常流程终止程序。 - 调试器设置中关闭JMC:在Visual Studio的「调试」→「选项」→「调试」→「常规」中,取消勾选「启用仅我的代码」选项。无需重新编译,修改后调试行为即可改变。
内容的提问来源于stack exchange,提问作者Brykyz
相关产品推荐
相关产品推荐

