{"id":110830,"date":"2025-02-03T07:00:00","date_gmt":"2025-02-03T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=110830"},"modified":"2025-02-03T08:28:08","modified_gmt":"2025-02-03T16:28:08","slug":"20250203-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250203-00\/?p=110830","title":{"rendered":"On trying to log an exception as it leaves your scope"},"content":{"rendered":"<p>A customer wanted to log exceptions that emerged from a function, so they used the WIL <code>scope_exit<\/code> object to specify a block of code to run during exception unwinding.<\/p>\n<pre>void DoSomething()\r\n{\r\n    auto logException = wil::scope_exit([&amp;] {\r\n        Log(\"DoSomething failed\",\r\n            wil::ResultFromCaughtException());\r\n    });\r\n\r\n    \u27e6 do stuff that might throw exceptions \u27e7\r\n\r\n    \/\/ made it to the end - cancel the logging\r\n    logException.release();\r\n}\r\n<\/pre>\n<p>They found, however, that instead of logging the exception, the code in the <code>scope_exit<\/code> was crashing.<\/p>\n<p>They debugged into the <code>Result\u00adFrom\u00adCaught\u00adException<\/code> function, which eventually <a href=\"https:\/\/github.com\/microsoft\/wil\/blob\/bfad71bd51f839ab6d0ce7161785699a6615afc7\/include\/wil\/result_macros.h#L3958,L3980\"> reaches something like this<\/a>:<\/p>\n<pre>try\r\n{\r\n    throw;\r\n}\r\ncatch (\u27e6 blah blah \u27e7)\r\n{\r\n    \u27e6 blah blah \u27e7\r\n}\r\ncatch (\u27e6 blah blah \u27e7)\r\n{\r\n    \u27e6 blah blah \u27e7\r\n}\r\ncatch (...)\r\n{\r\n    \u27e6 blah blah \u27e7\r\n}\r\n<\/pre>\n<p>The idea is that the code rethrows the exception, then tries to catch it in various ways, and when it is successful, it uses the caught object to calculate a result code.<\/p>\n<p>And that&#8217;s where the problem lies.<\/p>\n<p>It&#8217;s sort of implied by the name <code>Result\u00adFrom\u00adCaught\u00adException<\/code> that it tries to calculate a result from an exception that was caught. But the <code>scope_exit<\/code> functor is called during unwinding that results from an <i>uncaught<\/i> exception.<\/p>\n<p>There is no caught exception to get a result from!<\/p>\n<p>The C++ language says that a rethrowing <code>throw<\/code> rethrows the exception that is being handled, where &#8220;being handled&#8221; roughly means &#8220;is executing the body of its <code>catch<\/code> clause&#8221;. If you try a rethrowing throw when there is no exception being handled, then it&#8217;s straight to jail. (Formally, <code>std::<wbr \/>terminate<\/code>.)<\/p>\n<p>The solution, then, is to put the <code>Result\u00adFrom\u00adCaught\u00adException<\/code> somewhere inside a <code>catch<\/code> block, like perhaps this:<\/p>\n<pre>void DoSomething()\r\n{\r\n    try {\r\n        \u27e6 do stuff that might throw exceptions \u27e7\r\n    } catch (...) {\r\n        Log(\"DoSomething failed\",\r\n            wil::ResultFromCaughtException());\r\n        throw;\r\n    })\r\n}\r\n<\/pre>\n<p>After logging the exception, we rethrow it so that the search for a handler can continue.<\/p>\n<p><b>Bonus chatter<\/b>: You can avoid a layer of indentation by using <a title=\"\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230223-00\/?p=107867\"> function-try<\/a>.<\/p>\n<pre>void DoSomething() <span style=\"border: solid 1px currentcolor;\">try<\/span>\r\n{\r\n    \u27e6 do stuff that might throw exceptions \u27e7\r\n<span style=\"border-bottom: solid 1px currentcolor;\">} <\/span><span style=\"border: solid 1px currentcolor; border-bottom: none;\">catch (...) {                           <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">    Log(\"DoSomething failed\",             <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">        wil::ResultFromCaughtException());<\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">    throw;                                <\/span>\r\n<span style=\"border: solid 1px currentcolor; border-top: none;\">}                                         <\/span>\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>You can&#8217;t watch it from an object on the outside.<\/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-110830","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>You can&#8217;t watch it from an object on the outside.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110830","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=110830"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110830\/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=110830"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=110830"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=110830"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}