| By John Gomez | Article Rating: |
|
| April 6, 2004 12:00 AM EDT | Reads: |
12,956 |
From the perspective of most programmers, the ability to raise an exception is typically a rather straightforward set of semantics that allows your program to react to an unexpected situation. But as with most things related to .NET, there are a variety of under-the-covers "happenings" that allow your particular programming language to implement a common service without sacrificing the language's usability or flexibility. Gaining an understanding of structured exception handling (SEH) will not only help you to develop systems that are robust, but will also serve as a good introduction into how the .NET Common Language Runtime (CLR) generally implements common services.
In most cases, exception handling is something that is either a service of the programming language itself or part of the operating system. For example, before VB.NET the VB runtime managed exceptions, which was considered a part of that language's services. In other areas of technology a particular offering may have depended on something like Win32 or the HRESULT model in COM. In these examples a language, component model, or operating system has its "own" manner of representing an exception, with varying degrees of success.
All of this poses a challenge in the .NET world, where the CLR must reduce everything to a common denominator. In .NET the common denominators are the Intermediate Language (IL) and the Common Type System (CTS). IL allows us to represent the particular semantics of how a language or other technology implements exception handling, while the CTS allows for the implementation of standardized structures that can be passed between languages. This also allows .NET to support integration with legacy services such as COM and Win32, or even - if we decide to write the bridges - with exceptions raised on other operating systems and platforms. Imagine the flexibility of having a Linux system raise an exception that is trapped by a .NET component acting as a centralized exception management broker.
Basic SEH: Where It All Starts.
So just how does the CLR, using IL and CTS, implement structured exception handling? What are the various constructs and how does knowing all this help us develop better programs? Well, the best way to answer this and other questions is probably for us to establish a solid and basic foundation related to how the CLR deals with a fundamental construct - the method.
In .NET a method helps to describe the services of a class; it does this through something known as the method record. The way this works is much like a relational database system: the class has a descriptor record that contains a reference to a method record. The method record contains metadata, known as the method metadata, that describes the method. This method record can either be tiny or fat; a tiny method record contains no local variables or structured exception handling table (SEH table). If a method has either or both of these, it is considered fat - and its size and layout are slightly different from those of a tiny method record.
The fat method record is what comes into play whenever you declare some type of exception handling in your programming language. A way to think of this is that when you define a method in a class that has exception handling code, internally the method is represented as a fat method record and it contains all the metadata to describe the method, the IL code for the method, and the SEH table. A graphical representation of the fat method record is depicted in Figure 1.
Inside the SEH Table
The SEH table consists of a set of clauses that describe the structure of the guarded code. The table has a set of binary flags that describe the type of exception handling clause: a Try Offset flag, which is the beginning of the guarded code block; a Try Length flag, which is the length of the guarded code; Handler Offset and Handler Length flags, which detail the beginning of the exception handler block and its length; and a Class Token or Filter Offset flag, depending on the type of Exception Handler that was defined. This information allows the CLR to determine what to do when an exception occurs. It maps out the beginning of the guarded code block, the code to execute for an exception, and special semantics related to filtering or other special circumstance.
So how does the CLR allow a language designer to define how to handle an exception? We know that the SEH table allows us to define an exception handling clause - and that the clause, which is represented in the SEH table as a binary flag, can be one of four types.
The four types are described in Table 1, but in essence language designers need to correlate the exception management options in their languages to one of these clauses so the CLR execution subsystem knows how to react. For example, if I set the Flags value of the SEH table for a method to "0x0002", I would be stating that the handler for this method should always be executed, regardless of whether or not an exception occurs.
Examining the Exception Process
With the information you have now you should be able to make some fairly safe assumptions about how the CLR processes an exception. Simply stated, when the CLR encounters an exception for a method it will use the descriptors in the SEH table to determine how to handle the exception, which code block is affected, and what handler should be invoked. But if we stop here we would miss out on some of the more interesting magic that is performed under the covers by the CLR to manage and handle exceptions generically.
The CLR uses a technique generally referred to as a two-pass exception review process. What this means is that the CLR will process an exception in two passes. In the first pass, the CLR will determine if there is a handler for the exception. This is done by reviewing the entries in the SEH table; specifically it looks at the Try Offset and Try Length flags to see if the exception occurred within a guarded block, and if so, whether the Flags entry dictates that a handler exists for this type of occurrence. Let's assume that the CLR did find a handler during the first pass. At that point the CLR begins a second pass of the SEH table during which it will work through the execution phase of the exception management process. So we can divide the two passes into a discovery pass, in which we determine whether there is a handler in this method context to handle the exception; and an execution pass, in which we actually execute the handler and any special rules.
If the CLR finds that there are no handlers for this exception during the discovery pass it will begin to walk up the stack. Consider that the method in which the exception was thrown is the bottom of a call chain in which this method is called by another method, which is called by another method. The CLR will walk up the call chain and examine the SEH table entries for each of those methods until it either finds an acceptable handler or reaches the top of the stack, having traversed the entire call chain. If this occurs the CLR will then execute a default handler depending on the runtime context. The default handler, again depending on the runtime context, will either abort the program or launch a dialog that gives the user the option to abort, retry, or launch a debugger.
A Quick Tour of Unmanaged Exceptions
When I started this investigation of SEH in the CLR I mentioned that there are legacy technologies and systems that have their own way of managing exceptions. One of the technologies I mentioned was Win32, which has its own exception management subsystem as part of the operating system. Considering that many of the .NET systems being deployed today must interact with non-.NET systems, it is important to have at least a cursory understanding of how the .NET CLR manages exceptions raised by other systems.
Within .NET is a standard set of exception types that are defined as part of the System.Exception class. System.Exception is the base class in .NET from which all exception types derive. The CLR throws a variety of standard exceptions, such as those related to the execution engine, the JIT compiler, and more. This standardization allows for the ability to map nonstandard exceptions to the standard exceptions in .NET and treat them as if they were native or managed exceptions. For instance, in Win32 a standard exception the operating system could throw is STATUS_NO_MEMORY, which, as the moniker states, indicates a situation in which no more memory can be allocated. If you have a .NET component or application that interacts with an unmanaged application and it causes this situation it would cause the STATUS_NO_MEMORY exception to be raised, which would be passed up through the .NET Interop services to the CLR. The CLR SEH system maps that exception to the .NET equivalent, in this case the OUTOFMEMORYEXCEPTION. Once this mapping takes place the exception is processed by the CLR as if it were a managed exception.
Wrapping Up
My goal in this article was to provide a basic overview of the internal mechanisms and services provided by the .NET CLR. I hope you now have a better understanding of what is provided under the covers and how your actions in a programming language are translated to a set of semantics and structures that allow the CLR to deal with them generically.
You should also be able to make some assumptions regarding the design of your application. Given the two-pass nature of the exception management system in .NET you are safe to assume that if you design your application methods to handle exceptions locally you will have better performance. But it is also important to realize that you should only handle exceptions specific to your method. A good rule of thumb is to avoid walking the stack but never prevent things you don't know about from bubbling back up the call chain.
Last, this article presented only some of the basics related to structured exception handling in .NET. There is still much more to learn, understand, and explore. I truly hope that this article encourages and challenges you to find out what makes .NET tick - from the inside out.
Published April 6, 2004 Reads 12,956
Copyright © 2004 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By John Gomez
John Gomez, open source editor for .NET Developer's Journal, has over 25 years of software development and architectural experience, and is considered a leader in the design of highly distributed transaction systems. His interests include chaos- and fuzzy-based systems, self-healing and self-reliant systems, and offensive security technologies, as well as artificial intelligence. John started developing software at age 9 and is currently the CTO of Eclipsys Corporation, a worldwide leader in hospital and physician information systems.
- Kindle 2 vs Nook
- Wave on Ulitzer: Confessions of a Google Wave Fanboy
- Confessions of a Ulitzer Addict
- IBM Hardware Chief, Intel VC Exec Arrested in Insider Trading Scam
- Cloud Computing Best Practices
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- Ulitzer.com Named Exclusive "New Media" Sponsor of Cloud Computing Conference & Expo
- Infrastructure-as-a-Service Will Mature in 2010: Microsoft's David Chou
- Windows 7 – Microsoft’s First Step to the Cloud
- Cloud Computing & Federal IT - What Does the Future Hold?
- Jill Tummler Singer, Deputy CIO of CIA, Keynotes at GovIT Expo
- Cloud Expo and the End of Tech Recession
- Kindle 2 vs Nook
- The Difference Between Web Hosting and Cloud Computing
- Ajax in RichFaces 3.3, JSF 2 and RichFaces 4
- Wave on Ulitzer: Confessions of a Google Wave Fanboy
- Confessions of a Ulitzer Addict
- IBM Hardware Chief, Intel VC Exec Arrested in Insider Trading Scam
- Cloud Computing Best Practices
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- Ulitzer.com Named Exclusive "New Media" Sponsor of Cloud Computing Conference & Expo
- Eval JavaScript in a Global Context
- Infrastructure-as-a-Service Will Mature in 2010: Microsoft's David Chou
- Windows 7 – Microsoft’s First Step to the Cloud
- Google Maps and ASP.NET
- Crystal Reports XI & How It Has Changed
- Converting VB6 to VB.NET, Part I
- Creating Controls for.NET Compact Framework in Visual Studio 2005
- Where Are RIA Technologies Headed in 2008?
- How to Write High-Performance C# Code
- AJAX World RIA Conference & Expo Kicks Off in New York City
- Implementing Tab Navigation with ASP.NET 2.0
- i-Technology Photo Exclusive: Bill Gates & Steve Jobs In "Nerds"
- .NET Archives: Getting Reacquainted with the Father of C#
- i-Technology Viewpoint: "SOA Sucks"
- Programmatically Posting Data to ASP .NET Web Applications

































