{"id":18390,"date":"2009-05-14T17:13:00","date_gmt":"2009-05-14T17:13:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/dotnet\/2009\/05\/14\/how-clr-maps-seh-exceptions-to-managed-exception-types\/"},"modified":"2021-10-04T15:44:14","modified_gmt":"2021-10-04T22:44:14","slug":"how-clr-maps-seh-exceptions-to-managed-exception-types","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/how-clr-maps-seh-exceptions-to-managed-exception-types\/","title":{"rendered":"How CLR maps SEH exceptions to managed exception types"},"content":{"rendered":"<p><P>Managed exception handling is built on Windows OS\u2019s <A href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms680657(VS.85).aspx\">Structured Exception Handling<\/A>, commonly referred to as SEH (to learn more about SEH, please read Matt Pietrek\u2019s <A href=\"http:\/\/www.microsoft.com\/msj\/0197\/Exception\/Exception.aspx\">excellent article<\/A> first). This implies that CLR understands how to interoperate between SEH and managed exception systems, which is a very key point since SEH is based upon the notion of exception codes, while managed exception handling represents an exception using a managed type. Depending upon how, and by whom, the SEH exception is raised, the CLR accordingly maps it to a managed exception.<\/P>\n<P><I>Note: The following discussion is focused on the Desktop CLR, which runs on Windows OS. While the idea of the discussion is to help understand the concept, it is illustrated using some implementation details that could change in future.<\/I><\/P>\n<H3>Synchronous exceptions in managed code<\/H3>\n<P>When managed code uses the <I>throw <\/I>keyword to throw an exception, it has already instantiated a managed exception object that will represent the thrown exception. This is passed to the CLR, which sets up some exception related state on the thread and invokes the Kernel32\u2019s <A href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms680552(VS.85).aspx\"><I>RaiseException<\/I><\/A><I> <\/I>API to raise the managed exception. The first argument to this API is the SEH exception code for the exception being raised and the CLR passes <I>0xE0434F4D, <\/I>the managed exception SEH code.<\/P>\n<P>At this point, the OS comes into the picture and begins to look for an SEH exception handler on the stack of the thread which raised the exception. The CLR registers one of its functions as an exception handler with the OS, to process exceptions arising out of managed code. When it sees the CLR SEH exception code, it <I>knows <\/I>that a managed exception is being raised and proceeds to look up the thread state to retrieve exception related details (e.g. identify the managed exception object representing the exception being raised). <\/P>\n<P>Thus, in the case of synchronous managed throw, it is easy to map the SEH exception to managed exception type.<\/P>\n<H3>Asynchronous exceptions in managed code<\/H3>\n<P>Asynchronous exceptions, simply put, are the ones which get raised without an explicit throw. This can happen in managed code if you perform arithmetic operations (e.g. divide by zero exception) or use <A href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/t2yzs44b.aspx\"><I>unsafe<\/I><\/A><I> <\/I>managed code that could result in exceptions like Access Violation (AV). The interesting thing about asynchronous exceptions is that they are represented using their unique SEH exception code. For example, AV is represented by <I>0xC0000005, <\/I>divide by zero (integer) is represented by <I>0xC0000094, <\/I>while divide by zero (floating) is represented by <I>0xC000008E. <\/I>Common exceptions are listed <A href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa363082(VS.85).aspx\">here<\/A> and exception code values can be found in <I>WinNT.h.<\/I><\/P>\n<P>When such an exception is raised in managed code, once again the OS begins looking for an exception handler on the stack of the thread where the exception was raised. When CLR\u2019s exception handler is invoked, it <I>understands <\/I>that the exception in question was not synchronously thrown by managed code since the exception code is not the CLR SEH exception code. Thus, instead of looking up the thread state for exception related details, it proceeds to <I>map <\/I>the SEH exception to one of the managed exception types. For example, divide by zero exception (both integer and floating point) are represented using <A href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.dividebyzeroexception.aspx\"><I>System.DivideByZeroException<\/I><\/A><I>. <\/I><\/P>\n<P>On a similar note, when a real AV is generated in managed code, it has the exception code of <I>0xC0000005. <\/I>Since managed code has the notion of a <I>null reference, <\/I>the runtime does few more checks to determine if the AV represents an attempt to use a null reference or not. If it is, then it gets mapped to <A href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.nullreferenceexception.aspx\"><I>System.NullReferenceException<\/I><\/A>. Otherwise, it gets mapped to <A href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.accessviolationexception.aspx\"><I>System.AccessViolationException<\/I><\/A><I> <\/I>type (in v2.0 and later runtimes).<\/P>\n<H3>Exceptions thrown in native code<\/H3>\n<P>Another way the CLR gets to see SEH exceptions is when managed code has called into native code using a mechanism like <A href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms235282.aspx\">Platform Invocation Services<\/A> (PInvoke for short). In the example below, the stack grows from top to bottom and blue frames represent managed code, while the reddish frame represents native code:<\/P>\n<P><A href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/10\/2019\/02\/image_2.png\"><IMG title=\"image\" border=\"0\" alt=\"image\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/10\/2019\/02\/image_thumb.png\" width=\"710\" height=\"318\"><\/A> <\/P>\n<P>Assuming <I>Zoo <\/I>throws a native exception that is not handled in it, the exception will propagate up the stack, as the OS walks up the stack looking for a potential handler for the exception. In such a case, since the next frame on the stack is <I>Bar<\/I>, which is managed, the OS ends up calling the CLR\u2019s exception handler. Since the SEH exception comes from native code, it could have <I>any <\/I>exception code. For instance, it could be a C++ exception (which has the SEH exception code of <I>0xE06D7363<\/I>) or it could be a SEH exception code specific to the application. The point is that CLR <I>does not <\/I>know about all the SEH exception codes that exist (and will be created in the future). And only a subset of the existing ones is of interest from the perspective of mapping the code to a specific managed exception type. <\/P>\n<P>Thus, when the native exception is seen by CLR\u2019s exception handler, it will attempt to map the most common SEH exception codes to their corresponding managed exception type (as explained earlier with some examples). For any other SEH exception code that the runtime does not identify, it gets mapped to the <A href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.runtime.interopservices.sehexception.aspx\"><I>System.Runtime.InteropServices.SEHException<\/I><\/A><I> <\/I>type. <\/P>\n<H3>Subtleties and what happens next?<\/H3>\n<P>1) This mapping is done <I>only<\/I> once when CLR\u2019s exception handler is invoked by the OS (assuming there are no context transitions on the stack) for the first managed frame on the stack from the point of throw of the specific SEH exception.<\/P>\n<P>2) Since this mapping is done based upon SEH exception codes, the CLR <I>knows <\/I>if a given managed exception instance represents a real native SEH exception or not. For example, CLR knows if a <I>System.AccessViolationException <\/I>instance represents a real AV or is a regular managed exception thrown by managed code. Why does this matter? Well, it does when the CLR has determine the <A href=\"http:\/\/msdn.microsoft.com\/en-us\/magazine\/dd419661.aspx\">corruption severity<\/A> of an exception!<\/P>\n<P>Once the mapping is completed, the CLR begins regular exception handling process of finding a handler for the exception. <\/P>\n<P>&nbsp;<\/P>\n<P>&#8211; Gaurav Khanna,<\/P>\n<P>Developer, CLR<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Managed exception handling is built on Windows OS\u2019s Structured Exception Handling, commonly referred to as SEH (to learn more about SEH, please read Matt Pietrek\u2019s excellent article first). This implies that CLR understands how to interoperate between SEH and managed exception systems, which is a very key point since SEH is based upon the notion [&hellip;]<\/p>\n","protected":false},"author":342,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685],"tags":[],"class_list":["post-18390","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet"],"acf":[],"blog_post_summary":"<p>Managed exception handling is built on Windows OS\u2019s Structured Exception Handling, commonly referred to as SEH (to learn more about SEH, please read Matt Pietrek\u2019s excellent article first). This implies that CLR understands how to interoperate between SEH and managed exception systems, which is a very key point since SEH is based upon the notion [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/18390","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/342"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=18390"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/18390\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=18390"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=18390"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=18390"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}