Catch block is not being evaluated when exceptions are thrown from finallys
.net, .net-4.5, c#, specifications
Solution
As it turns out, I am not crazy. Based on the answers I got to this question, I think it seemed like I was having difficulty understanding what is so clearly outlined in the spec. It's really not at all difficult to grasp.
The truth is that the spec makes sense, while the behavior wasn't. This is seen even more so when you run the code in an older runtime, where it behaves completely different...or at least appears to.
A quick recap
What I saw, on my x64 Win7 machine:
.NET v2.0-3.5 - WER dialog when the `CryptographicException` is thrown. After hitting `Close the program`, the program continues, as if the execption were never thrown. The application is not terminated. This is the behavior one would expect from reading the spec, and is well defined by the architects who implemented exception handling in .NET.
.NET v4.0-4.5 - No WER dialog is displayed. Instead, a window appears asking if you want to debug the program. Clicking `no` causes the program to terminate immediately. No finally blocks are executed after that.
As it turns out, pretty much anybody who would try to answer my question would get the exact same results as I did, so that explains why nobody could answer my question of why the runtime was terminating from an exception that it swallowed.
It's never quite what you expect
Who would have suspected the Just-In-Time debugger?
You may have noticed that running the application under .NET 2 produces a different error dialog than .NET 4. However, if you're like me, you've come to expect that window during the development cycle, and so you didn't think anything of it.
The vsjitdebugger executable was forcibly terminating the application, instead of letting it continue. In the 2.0 runtime, `dw20.exe` doesn't have this behavior, in fact, the first thing you see is that WER message.
Thanks to the jit debugger terminating the application, it made it seem like it wasn't conforming to what spec says when, in fact, it does.
To test this, I disabled the vsjitdebugger from launching on failure, by changing the registry key at `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug\Auto` from 1 to 0. Sure enough, the application ignored the exception and continued on, just like .NET 2.0.
As it turns out, there is a workaround, though there's really no reason to workaround this behavior, since your application is terminating.
- When the Just-In-Time debugger window pops up, check `Manually choose the debugging engines` and click yes, that you want to debug.
- When Visual Studio gives you engine options, click cancel.
- This will cause the program to continue, or a WER dialog to pop up, depending on your machine configuration. If that happens, telling it to close the program won't actually close it, it will continue running as if everything was okay.
Problem
This question came about because code that worked previously in .NET 4.0 failed with an unhandled exception in .NET 4.5, partly because of try/finallys. If you want details, read more at Microsoft connect. I used it as the base for this example, so it might be helpful to reference. The code For the people who chose to not read about the details behind this question, here is a very quick look at the conditions where this happened: ``` using(var ms = new MemoryStream(encryptedData)) using(var cryptoStream = new CryptoStream(encryptedData, decryptor, CryptoStreamMode.Read)) using(var sr = new StreamReader(cryptoStream)) ``` This issue is that there are exceptions thrown from the `Dispose` method of CryptoStream (since they are inside a using statement, these exceptions happen to be thrown from two different finally blocks). When `cryptoStream.Dispose()` is called by the `StreamReader`, the `CryptographicException` is thrown. The second time `cryptoStream.Dispose()` is called, in its using statement, it throws a `ArgumentNullException` The following code removes most of the unnecessary code from the link provided above, and unwinds the using statements into try/finallys to clearly show that they are being throw in finally blocks. ``` using System; using System.Security.Cryptography; namespace Sandbox { public class Program { public static void Main(string[] args) { try { try { try { Console.WriteLine("Propagate, my children"); } finally { // F1 Console.WriteLine("Throwing CryptographicExecption"); throw new CryptographicException(); } } finally { // F2 Console.WriteLine("Throwing ArgumentException"); throw new ArgumentException(); } } catch (ArgumentException) { // C1 Console.WriteLine("Caught ArgumentException"); } // Same behavior if this was in an enclosing try/catch catch (CryptographicException) { // C2 Console.WriteLine("Caught CryptographicException"); } Console.WriteLine("Made it out of the exception minefield"); } }} ``` Note: The try/finally correspond to expanded using statements from the referenced code. Output: ``` Propagate, my children Throwing CryptographicExecption Throwing ArgumentException Caught ArgumentException Press any key to continue . . . ``` It doesn't appear that the `CryptographicException` catch block is ever executed. However, removing that catch block causes the exception to terminate the runtime. A little more information EDIT: This was updated to the newest revision of the specification. The one I happened to grab off of MSDN had older wording. `Lost` has been updated to `terminated`. Diving into the C# spec, sections 8.9.5 and 8.10 discuss exception behavior: - When an exception is thrown, including from inside a finally block, control is transferred to the first catch clause in an enclosing try statement. This continues up try statements until a suitable one is found. - If an exception is thrown during execution of a finally block, and an exception was already being propagated, that exception is terminated "Terminated" makes it seem that the first exception would forever be hidden by the second thrown exception, though it doesn't seem to be what is happening. I'm sure the question is in here somewhere For the most part, it's easy to visualize what the runtime is doing. The code executes to the first finally block (`F1`) where an exception is thrown. As the exception propagates, the second exception is thrown from the second finally block (`F2`). According to the spec, the `CryptographicException` thrown from `F1` is now terminated, and the runtime is looking for a handler for the `ArgumentException`. The runtime finds a handler, and executes the code in the catch block for the `ArgumentException` (`C1`). Here is where it gets foggy: the spec says that the first exception would be terminated. However, if the second catch block (`C2`) is removed from the code, the `CryptographicException` that was supposedly lost, is now an unhandled exception that terminates the program. With the `C2` present, the code will not terminate from an unhandled exception, so on the surface it appears to be handling the exception, but the actually exception handling code in the block is never executed. Questions The questions are basically the same, but re-worded for specificity. How is it that the `CryptographicException` becomes terminated due to the `ArgumentException` exception thrown from the enclosing finally block, as removing the `catch (CryptographicException)` block causes the exception to go unhandled and terminate the runtime? Since the runtime seems to be handling the `CryptographicException` when the `catch (CryptographicException)` block is present, why is the code inside of the block not executing? Extra informational Edit I'm still looking into the actual behavior of this, and many of the answers have been particularly helpful in at least answering parts of the above questions. Another curious behavior, that happens when you run the code with the `catch (CryptographicException)` block commented out, is the difference between .NET 4.5 and .NET 3.5. .NET 4.5 will throw the `CryptographicException` and terminate the application. .NET 3.5, however, seems to behave more according to the C# spec where the exception. ``` Propagate, my children Throwing CryptographicExecption Unhandled Exception: System.Security.Cryptography.CryptographicException [...] ram.cs:line 23 Throwing ArgumentException Caught ArgumentException Made it out of the exception minefield ``` In .NET 3.5, I see what I read in the spec. The exception becomes "lost", or "terminated", since the only thing that ever needs to get caught is the `ArgumentException`. Because of that the program can continue execution. I only have .NET 4.5 on my machine, I wonder if this happens in .NET 4.0?