{"id":107097,"date":"2022-09-01T07:00:00","date_gmt":"2022-09-01T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107097"},"modified":"2022-08-31T07:04:59","modified_gmt":"2022-08-31T14:04:59","slug":"20220901-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220901-00\/?p=107097","title":{"rendered":"Why am I getting a null pointer crash when trying to call a method on my C++\/WinRT object?"},"content":{"rendered":"<p>A customer found that their program ran fine on their machine, but it crashed when run on a Windows Server 2019 system.<\/p>\n<div id=\"p20220901_head\" style=\"display: none;\">\u00a0<\/div>\n<pre>namespace winrt\r\n{\r\n    using namespace winrt::Windows::Web::Http;\r\n}\r\n\r\nwinrt::HttpClient httpClient;\r\n\r\n\/\/ Crashes on the next line\r\nauto result = co_await httpClient.TryGetStringAsync(L\"http:\/\/example.com\/\");\r\nif (result.Succeeded()) { \/* use the result *\/ }\r\n<\/pre>\n<p>An inspection of the crash dump shows that we crashed inside the C++\/WinRT projection:<\/p>\n<pre> check_hresult(WINRT_IMPL_SHIM(Windows::Web::Http::IHttpClient2)-&gt;\r\n    TryGetStringAsync(*(void**)(&amp;uri), &amp;operation));\r\n<\/pre>\n<p>The problem is that <code>WINRT_IMPL_SHIM<\/code> is producing a null pointer, and therefore the attempt to call the <code>Try\u00adGet\u00adString\u00adAsync<\/code> method crashes.<\/p>\n<p>The <code>WINRT_<wbr \/>IMPL_<wbr \/>SHIM<\/code> internal macro converts the <code>this<\/code> object into the appropriate interface so we can call it. And it does this via the conversion operator:<\/p>\n<pre>template &lt;typename D, typename I&gt;\r\nstruct require_one : consume_t&lt;D, I&gt;\r\n{\r\n    operator I() const noexcept\r\n    {\r\n        return static_cast&lt;D const*&gt;(this)-&gt;template try_as&lt;I&gt;();\r\n    }\r\n};\r\n<\/pre>\n<p>Observe that the conversion operator uses <code>try_as<\/code>, which means that if the <code>Query\u00adInterface<\/code> fails, then it returns <code>nullptr<\/code>.<\/p>\n<p>And that&#8217;s the problem.<\/p>\n<p>The <code>Try\u00adGet\u00adString\u00adAsync<\/code> method was added to the <code>Http\u00adClient<\/code> object in Windows 10, version 1903 (10.0.18362.0), and Windows Server 2019 corresponds to Windows 10, Version 1809 (10.0.17763.0). The <code>Query\u00adInterface<\/code> call fails because the <code>IHttpClient2<\/code> interface is not supported on Windows Server 2019.<\/p>\n<p>What happened is that the customer was using the Windows Runtime metadata files corresponding to a more recent version of Windows than their target platform. You are allowed to do that, but it also means that you have to be careful when trying to do things on older systems. You have this same problem in classic Win32, where you have to avoid using new versions of structures or calling new functions when running on older systems.<\/p>\n<p>There are two general approaches for detecting whether a Windows Runtime feature is supported.<\/p>\n<p>The first is to ask the system whether the method exists, using the <code>ApiInformation<\/code> runtime class:<\/p>\n<pre>namespace winrt\r\n{\r\n    using namespace winrt::Windows::Web::Http;\r\n    <span class=\"p20220901_accent\">using namespace winrt::Windows::Foundation::Metadata;<\/span>\r\n}\r\n\r\nwinrt::HttpClient httpClient;\r\n\r\nwinrt::hresult error;\r\nwinrt::hstring stringResult;\r\nif (<span class=\"p20220901_accent\">winrt::ApiInformation::IsMethodPresent(\r\n        winrt::name_of&lt;winrt::HttpClient&gt;,\r\n        L\"TryGetStringAsync\", 1)<\/span>) {\r\n    auto result = co_await client.TryGetStringAsync(L\"http:\/\/example.com\/\");\r\n    if (result.Succeeded()) stringResult = result.Value();\r\n    else error = result.ExtendedError();\r\n} else {\r\n    \/\/ Running on older system that doesn't support TryGetStringAsync\r\n    try {\r\n        stringResult = co_await httpClient.GetStringAsync(L\"http:\/\/example.com\");\r\n    } catch (...) {\r\n        error = winrt::to_hresult();\r\n    }\r\n}\r\nif (!error) { \/* do something with stringResult *\/ }\r\nelse { \/* deal with the error *\/ }\r\n<\/pre>\n<p>The above version probes by the method name and arity. &#8220;Is there a method on <code>HttpClient<\/code> called <code>TryGetAsync<\/code> that takes one parameter?&#8221; The arity parameter is optional, and if you omit it, then you are checking if a method by that name exists regardless of arity. But since we know we&#8217;re calling the 1-parameter version, we should be specific and look for the 1-parameter version.<\/p>\n<p>Alternatively, you can look up in the documentation which interface supports <code>Try\u00adGet\u00adString\u00adAsync<\/code> and probe for the presence of the interface. A bonus static assertion tells the compiler to check our work.<\/p>\n<pre><span class=\"p20220901_accent\">static_assert(&amp;winrt::IHttpClient2::TryGetStringAsync);<\/span>\r\nif (winrt::ApiInformation::<span class=\"p20220901_accent\">IsTypePresent(\r\n        winrt::name_of&lt;winrt::IHttpClient2&gt;)<\/span>) {\r\n<\/pre>\n<p>Another alternative is to look up in the documentation which contract version introduced the method and probe for presence of that version of the contract.<\/p>\n<pre>namespace winrt\r\n{\r\n    <span class=\"p20220901_accent\">using namespace winrt::Windows::Foundation;<\/span>\r\n}\r\n\r\nif (winrt::ApiInformation::<span class=\"p20220901_accent\">IsApiContractPresent(\r\n        winrt::name_of&lt;winrt::UniversalApiContract&gt;(), 8)<\/span>) {\r\n<\/pre>\n<p>If you have an older version of C++\/WinRT, you can use the string literal <code>L\"Windows.Foundation.UniversalApiContract\"<\/code>.<\/p>\n<p>The second pattern is to to probe for for the interface that supports the method you want to check.<\/p>\n<pre>winrt::HttpClient httpClient;\r\n\r\nwinrt::hresult error;\r\nwinrt::hstring stringResult;\r\n<span class=\"p20220901_accent\">static_assert(&amp;winrt::IHttpClient2::TryGetStringAsync);<\/span>\r\nif (<span class=\"p20220901_accent\">httpClient.try_as&lt;winrt::IHttpClient2&gt;()<\/span>) {\r\n    auto result = co_await client.TryGetStringAsync(L\"http:\/\/example.com\/\");\r\n    if (result.Succeeded()) stringResult = result.Value();\r\n    else error = result.ExtendedError();\r\n} else {\r\n    \/\/ Running on older system that doesn't support TryGetStringAsync\r\n    try {\r\n        stringResult = co_await httpClient.GetStringAsync(L\"http:\/\/example.com\");\r\n    } catch (...) {\r\n        error = winrt::to_hresult();\r\n    }\r\n}\r\nif (!error) { \/* do something with stringResult *\/ }\r\nelse { \/* deal with the error *\/ }\r\n<\/pre>\n<p>As an optimization, you can save the result of the query and use it to call the method. This avoids a second query inside the projection. Note that if we do it this way, we no longer need a <code>static_assert<\/code> to ask the compiler to check our work. It will check our work when we try to call <code>client2.<wbr \/>Try\u00adGet\u00adString\u00adAsync()<\/code>.<\/p>\n<pre>winrt::HttpClient httpClient;\r\n\r\nwinrt::hresult error;\r\nwinrt::hstring stringResult;\r\nif (<span class=\"p20220901_accent\">auto client2 = httpClient.try_as&lt;winrt::IHttpClient2&gt;()<\/span>) {\r\n    auto result = co_await <span class=\"p20220901_accent p20220901_accent_border\">client2<\/span>.TryGetStringAsync(L\"http:\/\/example.com\/\");\r\n    if (result.Succeeded()) stringResult = result.Value();\r\n    else error = result.ExtendedError();\r\n} else {\r\n    \/\/ Running on older system that doesn't support TryGetStringAsync\r\n    try {\r\n        stringResult = co_await httpClient.GetStringAsync(L\"http:\/\/example.com\");\r\n    } catch (...) {\r\n        error = winrt::to_hresult();\r\n    }\r\n}\r\nif (!error) { \/* do something with stringResult *\/ }\r\nelse { \/* deal with the error *\/ }\r\n<\/pre>\n<p>The story is the same: If an interface is marked as <code>required<\/code> in the metadata, then C++\/WinRT assumes that it will always be there. Because that&#8217;s what &#8220;required&#8221; means. If you need to support running on a system that fails to satisfy the requirements, you&#8217;ll have to detect the unmet requirements yourself.<\/p>\n<p><b>Bonus chatter<\/b>: Why does C++\/WinRT work this way? Why doesn&#8217;t <code>require_one<\/code> use <code>as()<\/code>, so that you get an <code>hresult_<wbr \/>no_<wbr \/>interface<\/code> exception instead of a hard crash?<\/p>\n<p>Early versions of C++\/WinRT indeed did that: They used <code>as()<\/code> and consequently threw an <code>hresult_<wbr \/>no_<wbr \/>interface<\/code> exception if the interface was not present. The behavior was changed some time before version 1.0.171013.2 to make the absence of a required interface a fatal error instead of a recoverable one.<\/p>\n<p>As I dimly recall, the reason is that checking the result and throwing a C++ exception was bloating the code. Querying for non-default interfaces happens a lot in Windows Runtime code, and all of the checks and throws were adding significant cost to each method call, as well as generating a lot of exception-handling infrastructure code. A &#8220;required&#8221; interface should never be missing (assuming you matched your SDK to the operating system), so there was little incentive to check for something whose failure indicates that the operating system and SDK teams messed up badly.<\/p>\n<p>In the less common case that you need to write version-adaptive code, you can add the appropriate checks yourself.<\/p>\n<p>\n<script>\nwindow.addEventListener(\"load\", function() {\n  \/\/ break up \"style\" to prevent wordpress from injecting random junk\n  document.getElementById(\"p20220901_head\").innerHTML =\n`<s` + `tyle>\nhtml:not([theme=dark]) .p20220901_accent { color: blue; }\nhtml:not([theme=dark]) .p20220901_accent_border { border: solid 1px blue; }\nhtml[theme=dark] .p20220901_accent { color: #9b9bff; }\nhtml[theme=dark] .p20220901_accent_border { border: solid 1px #9b9bff; }\n<\/s` + `tyle>`;\n});\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Requirements weren&#8217;t met.<\/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-107097","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Requirements weren&#8217;t met.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107097","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=107097"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107097\/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=107097"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107097"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107097"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}