My understanding is based on this long, but fantastic, article which supports the behavior listed in the C# specification.
The CLI standard (EMCA-335) shows that if there is no suitable catch, the runtime should terminate immediately. The .NET runtime does not do this, instead it seems to lean toward the behavior of the C# specification (EMCA-334).
First, I find it strange that a language specification is appears to be defining framework behavior. Secondly, They seem to contradict.
- Do they contradict each other, or am I getting the wrong meaning of the document?
- Does a runtime have to go about exception handling in this way to be compliant with the standard?
As an optional question, which one is the “correct” one, as in, if I were to write my own implementation of the CLI which one should I use? Note that EMCA-335 (CLI) document was updated two months ago, where EMCA-334 (C#) was updated back in 2006.
ECMA-335 Partition I Section 12.4.2.5
- When an exception occurs, the CLI searches the array for the first protected block that
- Protects a region including the current instruction pointer and
- Is a catch handler block and
- Whose filter wishes to handle the exception
If a match is not found in the current method, the calling method is searched, and so on. If no match is found the CLI will dump a stack trace and abort the program.
If a match is found, the CLI walks the stack back to the point just located, but this time calling the finally and fault handlers. It then starts the corresponding exception handler.
C# Specification §15.9.5 and §15.10 (§8.9.5 and §8.10 on MSDN)
The main difference between it and the CLI standard, is that whether or not a catch block is found, the application will not just exist, but will still unwind the stack, and take care of finally handlers.
I would suggest reading the standard itself to get a better meaning of this, since below is a very crude summary. It outlines step-by-step how a try statement is executed with each possible scenario.
- In the function that raises the exception:
- Looks for a matching catch clause in each try statement
- Executes the catch statement if it exists
- A finally block is executed if it exists
- If there was no handler, the above steps are repeated in the calling function
- If the exception processing terminates all function member invocations in the current thread, indicating that the thread has no handler for the exception, then the thread is itself terminated. The impact of such termination is implementation-defined.
I think this might just be a matter of a vague wording.
Okay, that’s true in C#. We all know that if we don’t have a
catchthen an exception will bring down our program.And that matches what we know from C# too. If there are some
finally(we don’t get to seefault) blocks to deal with as we go up the stack from the exception being thrown until ourcatchblock, they get processed, but it stops there and goes no further up the stack.A lot hangs on how we read the “If” that starts that second excerpt I just quoted. You’re reading it as “if … then … otherwise no such thing”. It could be read though as the first excerpt identifying the point in the stack that will be walked to: If there was a
catch, then it’s walked to that point. If there is no catch, then it’s walked to the very top of the stack and we get a dump and abort. The finally handlers (and fault handlers) still get called, but the point is not that of a matching catch handler.Your reading is the most literal, and mine the one that stretches things a bit. However, mine does match with the description of
finallyelsewhere in the same standard, most closely