Visual Studio Fail -- How not to debug .NET exception handling
Some months ago I came across an anomaly in both Visual Studio 2005 and 2008 when handling exceptions in a .NET project and it threw me through a loop. I'm a fan of the ANTLR parser generator and so I was working on a project that parses some user input text. As a feature, if the parser doesn't like the input, I expect that it will throw an exception which I would catch from my code. This worked in all but one particular test case. If I provided input for which the lexer has no rules for, such as giving it a string with a semicolon when there's no rules recognizing that character, it throws a
NoViableAltException to let you know it didn't know what to do with that character.
Only, no matter what try/catch I put in my user code, I couldn't catch this exception with the debugger. Visual Studio would halt execution every time with "Exception unhandled by user code" deep in the generated ANTLR code. This didn't make sense since there were other test cases where exceptions thrown (even the venerable
NoViableAltException) were handled properly by a try/catch block in my code.
The attached project archive below contains a simple Visual Studio 2008 project that replicates this issue.
The Explanation, or Something
I finally found out what was going on. It turns out Visual Studio 2005 and 2008 are installed with default debugger settings that didn't particularly help me. I didn't know this because the menu option was hidden away from me due to an dubious install-time option.
For many, you'll find the Debug|Exceptions menu option and it probably looks like:
Missing the Debug|Exceptions menu item?
If you're missing the Debug|Exceptions menu item, like I was, it is probably because you picked a Visual Studio settings profile that didn't include it, such as "General Development Settings", during install. You can fix this by going to Tools|Import and Export Settings...|Reset all settings, and pick a specialized settings profile, like "Visual C# Development Settings". Or, you could customize the Debug menu under Tools|Customize|Commands and add the menu item manually.
Here, the defaults are to break execution on almost every user-unhandled exception type that is thrown. This is generally what you want, since it means the debugger should break at the point where an exception is thrown and your code didn't catch it, probably of any type.
But, this isn't what was happening for me. Instead, I had code in place to handle
NoViableAltException, but the debugger was still treating it as an unhandled exception and breaking unnecessarily without the option to continue.
Note that the exception stated "... was unhandled by user code", which is different than a completely unhandled exception that would have said "... was unhandled". So, Visual Studio had decided that some portions of my project are not considered user code and therefore the thrown exception was "user-unhandled".
I was able to resolve this by creating an exception on the exception type "Antlr.Runtime.NoViableAltException" by adding it to the Debug|Exceptions dialog and checking the "User-unhandled" box.
Alternatively, in a Stack Overflow question that I posted, an answerer had directed me towards the "Enable Just My Code" option.
Visual Studio defines this ill-named option as
"When this feature is enabled, the debugger displays and steps into user code ("My Code") only, ignoring system code and other code that is optimized or does not have debugging symbols. For more information, see How to: Step Into Just My Code."
By unchecking this option, my code also ran successfully without unnecessary halts! (even without the exception type added to the Debug|Exceptions dialog)
What is interesting is that after disabling "Enable Just My Code", the Debug|Exceptions dialog is now missing the "User-unhandled" column. This implies to me that all exceptions are by default set to break when user-unhandled.
The question now is why was my own code considered not user code? The code that threw the exception was in a referenced ANTLR assembly, but the code that handled it was user code. Isn't that considered user-handled? I haven't been able to figure that out.
About Shawn Poulson / Exploding Coder
Software developer and designer
I'm a software developer in the Philadelphia/Baltimore metro area that loves web technology and creating compelling and useful applications. This blog was created to showcase some of my ideas and share my passion and experiences with others in the same field. Read more...