{"id":107303,"date":"2022-10-20T07:00:00","date_gmt":"2022-10-20T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107303"},"modified":"2022-10-20T06:34:53","modified_gmt":"2022-10-20T13:34:53","slug":"20221020-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20221020-00\/?p=107303","title":{"rendered":"Is it true that raising a structured exception from a structured exception handler terminates the process?"},"content":{"rendered":"<p>A customer had a vague recollection that they had read somewhere that if you raise a structured exception from a structured exception handler, the operating system would terminate the process. However, they couldn&#8217;t find any confirmation of this behavior. Was it just a dream?<\/p>\n<p>When you write a Windows structured exception handler (which is different from a C++ exception handler), you provide two code fragments:<\/p>\n<ul>\n<li>The code to decide whether to handle the exception.<\/li>\n<li>The code to execute if the exception is handled.<\/li>\n<\/ul>\n<p>Let&#8217;s annotate some code that handles a structured exception:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>\n<pre>__try\r\n{\r\n    Block1;\r\n}\r\n__except (FilterExpression)\r\n{\r\n    Block2;\r\n}\r\n__finally\r\n{\r\n    Block3;\r\n}<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Now, you aren&#8217;t allowed to have both an <code>__except<\/code> block and a <code>__finally<\/code> block, so the above code is technically incorrect, but I&#8217;m going to use it because it lets me talk about all the parts of the structured exception handler in a single (if impossible) example. In reality, either the <code>__except<\/code> block or the <code>__finally<\/code> block will be missing, in which case you can just ignore that part of the discussion.<\/p>\n<p>If a structured exception is raised in the <code>__try<\/code> block labeled <code>Block1<\/code>, then the <code>__except<\/code> block&#8217;s filter expression is evaluated. If the filter returns <code>EXCEPTION_<wbr \/>EXECUTE_<wbr \/>HANDLER<\/code>, then the exception is considered to have been handled, and execution resumes at the <code>__except<\/code> block labeled <code>Block2<\/code>.<\/p>\n<p>If a structured exception is raised in the <code>__except<\/code> block labeled <code>Block2<\/code> or in the <code>__finally<\/code> block labeled <code>Block3<\/code>, that structured exception is not considered to be in scope of this structured exception handler. The search for a handler begins at the next outer scope.<\/p>\n<p>There is no automatic termination if a structured exception occurs in the <code>__except<\/code> block <code>Block2<\/code> or the <code>__finally<\/code> block <code>Block3<\/code>. The search for a handler proceeds in the usual fashion, but with the understanding that the exception is not protected by the <code>__try<\/code> statement. The search begins with the scope that <i>contains<\/i> the <code>__try<\/code> statement.<\/p>\n<p>But wait, the story isn&#8217;t over yet. There&#8217;s still a place where an exception can be raised that I haven&#8217;t talked about yet. Do you see it?<\/p>\n<p>What if an exception is raised by the evaluation of the <code>FilterExpression<\/code>?<\/p>\n<p>The filter expression is considered to be inside the scope of the <code>__try<\/code>, so the exception raised by the filter expression will cause a new evaluation of the filter expresion, but this time to evaluate the recursively raised exception.<\/p>\n<p>That&#8217;s the part that usually causes trouble.<\/p>\n<p>If the evaluation of the filter expression for the first exception raises an exception, there&#8217;s a good chance that evaluation of the filter expression for the nested exception will raise the same exception, because the nested exception is probably an access violation due to some bug in the filter expression.<\/p>\n<p>You now run into a recursive exception death: To decide what to do about the original exception, the system evaluates the filter expression. But the filter expression has a bug, and it raises an exception. Now, the system decides what to do about the nested exception, which evaluates a new filter expression. That second filter expression encounters the same bug, so it raises a second nested exception. Each nested exception triggers a re-evaluation of the filter expression, and (on the assumption that the filter expression has a crashing bug) each re-evaluation in turn raises another nested exception.<\/p>\n<p>Eventually, you run out of stack, and the unhandled stack overflow exception is what terminates the process.<\/p>\n<p>Here&#8217;s an annotated version of the above impossible example:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"border: solid 1px gray; border-right: none;\">\n<pre>__try\r\n{\r\n    Block1;\r\n}\r\n__except (FilterExpression)<\/pre>\n<\/td>\n<td style=\"border: solid 1px gray; border-left: none; margin-right: 1ex;\">Under consideration<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; border-right: none;\">\n<pre>{\r\n    Block2;\r\n}\r\n__finally\r\n{\r\n    Block3;\r\n}<\/pre>\n<\/td>\n<td style=\"border: solid 1px gray; border-left: none; margin-right: 1ex;\" rowspan=\"2\">Not considered<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>If an exception occurs in the code marked &#8220;under consideration&#8221;, then the filter expression participates in the handling of the exception. But if an exception occurs in the code marked &#8220;not considered&#8221;, then the filter expression does not participate; execution has left the exception scope of the <code>__try<\/code> statement.<\/p>\n<p>Next time, we&#8217;ll look at the C++ version of this same question. The answer isn&#8217;t the same!<\/p>\n<p><b>Bonus chatter<\/b>: But wait, suppose we are using the <code>__try<\/code>\/<code>__finally<\/code> version of this statement. If an exception is raised inside the <code>__try<\/code> block, and nothing in <code>Block1<\/code> handles the exception, then the <code>__finally<\/code> block will run. But what if the <code>__finally<\/code> block also raises an exception?<\/p>\n<p>The system looks for a handler for the nested exception, and if an outer handler decides to handle it, then that handler executes, and the original exception is lost. On the other hand, if no filter expression declares that it wants to handle the exception, then the unhandled exception filter is called, and that terminates the process.<\/p>\n<p>Either way, the original exception doesn&#8217;t get observed by any of the exceptions handlers that are in scope at the time the <code>__finally<\/code> block runs, so you can think of it as saying that the exception raised by the <code>__finally<\/code> block replaces the original exception.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Untangling the myth.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-107303","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Untangling the myth.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107303","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=107303"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107303\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=107303"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107303"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107303"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}