{"id":104112,"date":"2020-08-21T07:00:00","date_gmt":"2020-08-21T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104112"},"modified":"2020-09-09T06:12:18","modified_gmt":"2020-09-09T13:12:18","slug":"20200821-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200821-00\/?p=104112","title":{"rendered":"Recognizing different types of exception objects that Windows platform libraries can throw"},"content":{"rendered":"<p><a title=\"Inside the Microsoft STL: The std::exception_ptr\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200820-00\/?p=104097\"> Last time<\/a>, we saw how to dig the exception object out of a <code>std::exception_ptr<\/code>. But what kind of exception objects might there be?<\/p>\n<p>For C++\/CX code, you are probably going to get a <code>Platform::Exception^<\/code>.<\/p>\n<pre>0:007&gt; ?? p\r\nclass std::exception_ptr\r\n   +0x000 _Data1           : 0x08a5885c Void\r\n   +0x004 _Data2           : 0x08a58850 Void\r\n<\/pre>\n<p>We learned that the <code>_Data1<\/code> points to an <code>EXCEPTION_RECORD<\/code>\u00b9<\/p>\n<pre>0:007&gt; .exr 0x08a5885c\r\nExceptionAddress: 00000000\r\n   ExceptionCode: e06d7363 (C++ EH exception)\r\n  ExceptionFlags: 00000001\r\nNumberParameters: 3\r\n   Parameter[0]: 19930520\r\n   Parameter[1]: 08a61330\r\n   Parameter[2]: b371fc08\r\n  pExceptionObject: 08a61330\r\n  _s_ThrowInfo    : b371fc08\r\n<\/pre>\n<p>And we noted that <code>Parameter[1]<\/code> is the object that was thrown.<\/p>\n<pre>0:007&gt; dps 08a61330\r\n08a61330  08a5b088\r\n08a61334  fdfdfdfd\r\n08a61338  ...\r\n<\/pre>\n<p>A hat pointer <code>^<\/code> is just a COM pointer in disguise, so let&#8217;s dump the pointer to see what&#8217;s there.<\/p>\n<pre>0:007&gt; dps 08a5b088 l5\r\n08a5b088  793d0640 vccorlib140d_app!Platform::Exception::`vftable'\r\n08a5b08c  793d065c vccorlib140d_app!Platform::Exception::`vftable'\r\n08a5b090  793d0680 vccorlib140d_app!Platform::Exception::`vftable'\r\n08a5b094  793d06ac vccorlib140d_app!Platform::Exception::`vftable'\r\n08a5b098  00e5c694\r\n<\/pre>\n<p>The vtable tells us that we have a <code>Platform::Exception<\/code>, which, to be fair, isn&#8217;t particularly surprising.<\/p>\n<pre>0:007&gt; dt  vccorlib140d_app!Platform::Exception 08a5b088\r\n   +0x000 __VFN_table : 0x793d0640\r\n   +0x004 __VFN_table : 0x793d065c\r\n   +0x008 __VFN_table : 0x793d0680\r\n   +0x00c __VFN_table : 0x793d06ac\r\n   +0x010 __description    : 0x00e5c694 Void\r\n   +0x014 __restrictedErrorString : 0x00e5da54 Void\r\n   +0x018 __restrictedErrorReference : (null)\r\n   +0x01c __capabilitySid  : (null)\r\n   +0x020 __hresult        : 0n-2147483635\r\n   +0x024 __restrictedInfo : 0x08a3843c Void\r\n   +0x028 __throwInfo      : 0x793c6c24 Void\r\n   +0x02c __size           : 0x20\r\n   +0x030 __prepare        : Platform::IntPtr\r\n   +0x034 __abi_reference_count : __abi_FTMWeakRefData\r\n   +0x03c __abi_disposed   : 0\r\n<\/pre>\n<p>Okay, now we have something. The <code>__hresult<\/code> is <code>0n-2147483635<\/code>, which is the debugger&#8217;s strange way of saying <code>0x8000000D<\/code> which is <code>E_ILLEGAL_STATE_CHANGE<\/code>.<\/p>\n<p>If you&#8217;re writing in C++\/WinRT, then the thing that is thrown will probably be a <code>winrt::hresult_error<\/code>.<\/p>\n<p>Go through the same exercise as before, but this time when we dump the thrown object we get<\/p>\n<pre>0:007&gt; dps 0942b8e0\r\n0942b8e0  00000000\r\n0942b8e4  aabbccdd\r\n0942b8e8  80004002\r\n0942b8ec  09439b5c\r\n0942b8f0  fdfdfdfd\r\n<\/pre>\n<p>The <a href=\"https:\/\/github.com\/microsoft\/cppwinrt\/blob\/b26b1adbaab108e01c6d6f8d7db1e7d0b7c04729\/strings\/base_error.h#L320\"> structure of an <code>hresult_error<\/code><\/a> is currently<\/p>\n<pre>    bstr_handle m_debug_reference;\r\n    uint32_t m_debug_magic{ 0xAABBCCDD };\r\n    hresult m_code;\r\n    com_ptr&lt;IRestrictedErrorInfo&gt; m_info;\r\n<\/pre>\n<p>We can match those up to the dump above. The <code>m_debug_reference<\/code> is <code>nullptr<\/code>, the <code>m_debug_magic<\/code> is the expected value of <code>0xxAABBCCDD<\/code> (which is good, because it acts as confirmation that what we have really is an <code>hresult_error<\/code>), the <code>m_code<\/code> is <code>0x80004002<\/code>, which is <code>E_NOINTERFACE<\/code>, and the <code>m_info<\/code> is <code>0x09439b5c<\/code>, whatever that is.<\/p>\n<p>If you use <a href=\"https:\/\/github.com\/Microsoft\/wil\"> WIL<\/a>, then you may have a <code>wil::ResultException<\/code>, which looks like this in memory:<\/p>\n<pre>struct ResultException : std::exception\r\n{\r\n    FailureType type; \/\/ 0 means FailureType::Exception\r\n    HRESULT hr;\r\n    long failureId;\r\n    PCWSTR pszMessage;\r\n    DWORD threadId;\r\n    PCSTR pszCode;\r\n    PCSTR pszFunction;\r\n    PCSTR pszFile;\r\n    uint32_t uLineNumber;\r\n    ... more stuff ...\r\n};\r\n<\/pre>\n<pre>0:000&gt; dps 000001e8a083edb0\r\n000001e8`a083edb0  00007ff7`e2200298 Win32!wil::ResultException::`vftable'\r\n000001e8`a083edb8  00000000`00000000 \/\/ std::exception\r\n000001e8`a083edc0  00000000`00000000 \/\/ std::exception\r\n000001e8`a083edc8  8007139f`00000000 \/\/ hr \/ type (0 = Exception)\r\n000001e8`a083edd0  cccccccc`00000042 \/\/ padding \/ failureId\r\n000001e8`a083edd8  00000000`00000000 \/\/ pszMessage\r\n000001e8`a083ede0  cccccccc`00001de4 \/\/ padding \/ threadId\r\n000001e8`a083ede8  000001e8`a0833a14 \/\/ pszCode\r\n000001e8`a083edf0  000001e8`a0833a26 \/\/ pszFunction\r\n000001e8`a083edf8  000001e8`a0833a2f \/\/ pszFile\r\n000001e8`a083ee00  00000001`0000001e \/\/ cFailureCount \/ uLineNumber\r\n<\/pre>\n<p>From this, we can extract that the <code>HRESULT<\/code> was <code>0x8007139f<\/code> which is <code>E_NOT_VALID_STATE<\/code>, there is no custom message (<code>pszMessage<\/code> is null), and we have pointers to various strings plus a line number.<\/p>\n<pre>0:000&gt; $ pszCode is the expression that failed\r\n0:000&gt; da 000001e8`a0833a14\r\n000001e8`a0833a14  \"TrySomething(a, b, c)\"\r\n\r\n0:000&gt; $ pszFunction is the function that threw\r\n0:000&gt; da 000001e8`a0833a26\r\n000001e8`a0833a26  \"Foo::Bar\"\r\n\r\n0:000&gt; $ pszFile is the file name\r\n0:000&gt; da 000001e8`a0833a2f\r\n000001e8`a0833a2f  \"C:\\\\Test\\\\Bar.cpp\"\r\n<\/pre>\n<p>So we see that this exception was the result of a<\/p>\n<pre>THROW_IF_FAILED(TrySomething(a, b, c));\r\n<\/pre>\n<p>that can be found in the function <code>Foo::Bar<\/code> at line 30 (<code>0x001e<\/code>) of the file <code>C:\\Test\\Bar.cpp<\/code>. It was the <code>0x42<\/code>&#8216;th error encountered by the program.<\/p>\n<p>If you have symbols, you can ask the debugger to print this all nice and pretty for you.<\/p>\n<pre>0:000&gt; ?? ((Contoso!wil::ResultException*)0x000001e8a083edb0)\r\nclass wil::ResultException * 0x000001e8`a083edb0\r\n   +0x000 __VFN_table : 0x00007ff7`c9de0308\r\n   +0x008 _Data            : __std_exception_data\r\n   +0x018 m_failure        : wil::StoredFailureInfo\r\n   +0x0b8 m_what           : wil::details::shared_buffer\r\n\r\n0:000&gt; ?? ((Contoso!wil::ResultException*)0x000001e8a083edb0)-&gt;m_failure\r\nclass wil::StoredFailureInfo\r\n   +0x000 m_failureInfo    : wil::FailureInfo\r\n   +0x090 m_spStrings      : wil::details::shared_buffer\r\n\r\n0:000&gt; ?? ((Contoso!wil::ResultException*)0x000001e8a083edb0)-&gt;m_failure.m_failureInfo\r\ntruct wil::FailureInfo\r\n   +0x000 type             : 0 ( Exception )\r\n   +0x004 hr               : 8007139f\r\n   +0x008 failureId        : 0n66\r\n   +0x010 pszMessage       : (null)\r\n   +0x018 threadId         : 0x1de4\r\n   +0x020 pszCode          : 0x000001e8`a0833a14  \"TrySomething(a, b, c)\"\r\n   +0x028 pszFunction      : 0x000001e8`a0833a26  \"Foo::Bar\"\r\n   +0x030 pszFile          : 0x000001e8`a0833a2f  \"C:\\Test\\Bar.cpp\"\r\n   +0x038 uLineNumber      : 0x1e\r\n   +0x03c cFailureCount    : 0n1\r\n   +0x040 pszCallContext   : (null)\r\n   +0x048 callContextOriginating : wil::CallContextInfo\r\n   +0x060 callContextCurrent : wil::CallContextInfo\r\n   +0x078 pszModule        : 0x000001e8`a0833a38  \"Test.exe\"\r\n   +0x080 returnAddress    : 0x00007ff7`c9dcf993 Void\r\n   +0x088 callerReturnAddress : 0x00007ff7`c9dd7b65 Void\r\n<\/pre>\n<p>You can see the other stuff in the <code>FailureInfo<\/code> structure, like the module name, and a few return addresses.<\/p>\n<p>Of course, the exception could have come from something else, in which case you&#8217;ll have to do your own decoding.<\/p>\n<pre>0:000&gt; dps 0x00000090`5172f8a0 l4\r\n00000090`5172f8a0  00007ffb`22408b98 std::time_put&lt;...&gt;::`vftable'+0x7b8\r\n00000090`5172f8a8  0000026b`841b4b10\r\n00000090`5172f8b0  00000000`00000001\r\n<\/pre>\n<p>This looks like somebody threw a <code>std::time_put<\/code>, but you&#8217;re just being faked out by COMDAT folding. You can dig into the exception type data to see what it is, or you can just guess at pointers, in the hope that one of them will give you a clue.<\/p>\n<p>Fortunately, many exceptions derive from <code>std::exception<\/code>, and in MSVC, the <code>std::exception<\/code> has a string pointer.<\/p>\n<pre>0:000&gt; da 0000026b`841b4b10\r\n0000026b`841b4b10  \"invalid vector&lt;T&gt; subscript\"\r\n<\/pre>\n<p>Aha, so this perticular guy was an invalid subscript exception from <code>std::vector<\/code>, also known as <code>std::out_of_range<\/code>.<\/p>\n<p>Those are the four commonly-thrown exceptions I was planning to cover today. They are the ones that come from the libraries commonly used in Windows client code.\u00b2<\/p>\n<p>\u00b9 Note that this is an implementation detail that may change at any time. This information is provided for debugging purposes. The fields have opaque names to discourage people from relying on said implementation details. But we&#8217;re debugging here, so we can deal with the possibility that the fields no longer mean what we think they mean. Debugging is an exercise in optimism.<\/p>\n<p>\u00b2 I left out MFC&#8217;s <code>CException<\/code>. Sorry, MFC developers.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Just a few of the more common ones.<\/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-104112","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Just a few of the more common ones.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104112","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=104112"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104112\/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=104112"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104112"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104112"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}