{"id":109276,"date":"2024-01-17T07:00:00","date_gmt":"2024-01-17T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109276"},"modified":"2024-01-16T21:15:19","modified_gmt":"2024-01-17T05:15:19","slug":"20240117-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240117-00\/?p=109276","title":{"rendered":"Getting a strong reference from the <CODE>this<\/CODE> pointer too soon"},"content":{"rendered":"<p>A bunch of us were investigating a crash that appeared to be due to the premature destruction of an object while they were still active COM references to it. After some investigation, we tracked it down: An object handed out a COM reference to itself in its constructor, even though it couldn&#8217;t fulfill all the requirements of COM strong references.<\/p>\n<p>Here&#8217;s a simplified version of the mistake:<\/p>\n<pre>\/\/ C++\/WinRT - this code is wrong\r\nnamespace winrt::Contoso::implementation\r\n{\r\n    struct MyPage : MyPageT&lt;MyPage&gt;\r\n    {\r\n        MyPage()\r\n        {\r\n            Application::LoadComponent(*this, blah, blah);\r\n            something_that_might_throw();\r\n        }\r\n\r\n        \u27e6 ... \u27e7\r\n    };\r\n}\r\n\r\n\/\/ C++\/WRL - this code is wrong\r\nstruct MyPage : RuntimeClass&lt;IPage&gt;\r\n{\r\n    MyPage()\r\n    {\r\n        Application::LoadComponent(this, blah, blah);\r\n        something_that_might_throw();\r\n    }\r\n\r\n    \u27e6 ... \u27e7\r\n};\r\n\r\n\/\/ Manually implemented - this code is wrong\r\nstruct MyPage : IPage\r\n{\r\n    MyPage() : m_refCount(1)\r\n    {\r\n        Application::LoadComponent(this, blah, blah);\r\n        something_that_might_throw();\r\n    }\r\n\r\n    LONG m_refCount;\r\n    \u27e6 ... \u27e7\r\n};\r\n\r\nCComPtr&lt;IPage&gt; page;\r\npage.Attach(new MyPage());\r\n<\/pre>\n<p>The C++\/WinRT library convention for producing a COM reference to the current object is to use the <code>*<\/code> operator, so the line<\/p>\n<pre>\/\/ C++\/WinRT\r\nApplication::LoadComponent(*this, blah, blah);\r\n<\/pre>\n<p>creates an <code>IInspectable<\/code> that refers to the current object and passes it to <code>LoadComponent<\/code>. If you use WRL or some other library that operates at the ABI level, then you just pass <code>this<\/code>, and the compiler will automatically convert it to a pointer to the <code>IInspectable<\/code> base class.<\/p>\n<p>No matter how you slice it, what happens is that you passed a COM pointer to <code>Application::<wbr \/>Load<wbr \/>Component<\/code>, and therefore <code>Load<wbr \/>Component<\/code> is within its rights to call <code>AddRef<\/code> on that COM pointer to extend the pointer&#8217;s lifetime, and retain the pointer for later use.<\/p>\n<p>When <code>Application::<wbr \/>Load<wbr \/>Component<\/code> returns, the object&#8217;s reference count has been incremented to 2.<\/p>\n<p>Unfortunately, what might happen next is that an exception or other error is encountered in the next part of the constructor. An exception in the constructor forces the object to destruct, and that means that the <code>MyPage<\/code> destructs without regard for its reference count.\u00b9<\/p>\n<p>Later, some other code tries to use the COM pointer that <code>Application::<wbr \/>Load<wbr \/>Component<\/code> saved, and it crashes because it now points to freed memory.<\/p>\n<p>Your code made a promise it couldn&#8217;t keep. It told <code>Application::<wbr \/>Load<wbr \/>Component<\/code>, &#8220;Here&#8217;s a COM pointer,&#8221; and one of the things that COM pointers can do is extend their lifetime with the <code>AddRef<\/code> method. But this particular COM pointer doesn&#8217;t honor that <code>AddRef<\/code> if an exception occurs.<\/p>\n<p>The traditional solution to this problem is to have a rule (enforced by code review) that constructors may not throw exceptions if they also hand out COM references to themselves.<\/p>\n<p>If you do hand out COM references, and you want to do things that might throw exceptions, then use two-phase construction, where all of the potentially-throwing operations are put in the second phase. WRL implements two-phase construction with the <code>Runtime\u00adClass\u00adInitialize()<\/code> method,\u00b2 and starting in C++\/WinRT version 2.0.220331.4, <a href=\"https:\/\/github.com\/microsoft\/cppwinrt\/pull\/1130\"> C++\/WinRT uses the name <code>Initialize\u00adComponent()<\/code> for the second phase<\/a>.<\/p>\n<p>If the second phase of two-phase construction fails, then the caller is told that the object failed to construct, but if there are any outstanding COM references to the object, the object won&#8217;t destruct until those outstanding references are released. You do have to be careful to leave your object in a harmless state after the exception is thrown, because those components which still have COM references will try to use them, and they should get some sort of reasonable behavior out of the zombie object. (What counts as &#8220;reasonable&#8221; is a domain-specific decision.)<\/p>\n<p>In the above cases, we would do something like this:<\/p>\n<pre>\/\/ C++\/WinRT, non-XAML class\r\nnamespace winrt::Contoso::implementation\r\n{\r\n    struct MyPage : MyPageT&lt;MyPage&gt;\r\n    {\r\n        <span style=\"border: solid 1px currentcolor;\">void InitializeComponent()<\/span>\r\n        {\r\n            Application::LoadComponent(*this, blah, blah);\r\n            something_that_might_throw();\r\n        }\r\n\r\n        \u27e6 ... \u27e7\r\n    };\r\n}\r\n\r\n\/\/ C++\/WinRT, XAML class\r\nnamespace winrt::Contoso::implementation\r\n{\r\n    struct MyPage : MyPageT&lt;MyPage&gt;\r\n    {\r\n        void InitializeComponent()\r\n        {\r\n            <span style=\"border: solid 1px currentcolor;\">MyPageT::InitializeComponent();<\/span> \/\/ let base class initialize\r\n            Application::LoadComponent(*this, blah, blah);\r\n            something_that_might_throw();\r\n        }\r\n\r\n        \u27e6 ... \u27e7\r\n    };\r\n}\r\n\r\n\/\/ C++\/WRL\r\nstruct MyPage : RuntimeClass&lt;IPage&gt;\r\n{\r\n    <span style=\"border: solid 1px currentcolor;\">HRESULT RuntimeClassInitialize()<\/span> try\r\n    {\r\n        Application::LoadComponent(this, blah, blah);\r\n        something_that_might_throw();\r\n        return S_OK;\r\n    }\r\n    CATCH_RETURN();\r\n\r\n    \u27e6 ... \u27e7\r\n};\r\n\r\n\/\/ Manually implemented\r\nstruct MyPage : IPage\r\n{\r\n    MyPage() : m_refCount(1)\r\n    {\r\n    }\r\n\r\n    \/\/ You can call this method anything you want.\r\n    <span style=\"border: solid 1px currentcolor;\">void Phase2Initialize()<\/span>\r\n    {\r\n        Application::LoadComponent(this, blah, blah);\r\n        something_that_might_throw();\r\n    }\r\n\r\n    LONG m_refCount;\r\n    \u27e6 ... \u27e7\r\n};\r\n\r\nCComPtr&lt;IPage&gt; page;\r\npage.Attach(new MyPage());\r\npage-&gt;Phase2Initialize();\r\n<\/pre>\n<p>&#8220;What about ATL?&#8221;<\/p>\n<p>Yeah, what about ATL?<\/p>\n<p>ATL gets its own discussion next time.<\/p>\n<p><b>Bonus chatter<\/b>: This problem doesn&#8217;t exist for C++ standard library <code>shared_ptr<\/code> because you cannot obtain a <code>shared_ptr<\/code> to yourself from your constructor. If you call <code>shared_<wbr \/>from_<wbr \/>this()<\/code> from the constructor, you will get a <code>std::<wbr \/>bad_<wbr \/>weak_<wbr \/>ptr<\/code> exception. That&#8217;s because, <a title=\"Inside STL: The shared_ptr constructor and enable_shared_from_this\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230816-00\/?p=108608\"> as we saw some time ago<\/a>, the weak pointer hiding inside <code>enable_<wbr \/>shared_<wbr \/>from_<wbr \/>this<\/code> is not initialized until after the object is constructed.<\/p>\n<p>\u00b9 This is basically a variant of <a title=\"Getting a strong reference from the this pointer too late\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230526-00\/?p=108252\"> getting a strong reference from the this pointer too late<\/a>: We are destructing an object before its reference count goes to zero.<\/p>\n<p>\u00b2 WRL much prefers that you report failure to initialize the class by returning a failure <code>HRESULT<\/code> from <code>Runtime\u00adClass\u00adInitialize()<\/code> rather than throwing an exception. WRL does nothing to translate the exception, and if the <code>Make\u00adAnd\u00adInitialize()<\/code> call came from <code>Dll\u00adGet\u00adActivation\u00adFactory<\/code> or from the autogenerated implementation of <code>IActivation\u00adFactory::<wbr \/>Create\u00adInstance()<\/code>, the exception will go uncaught and escape the ABI boundary.<\/p>\n<p>WRL does catch exceptions that come from the constructor, but it blindly translates all such exceptions into <code>E_<wbr \/>OUT\u00adOF\u00adMEMORY<\/code>, even if the exception was not <code>std::<wbr \/>bad_<wbr \/>alloc<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Giving out strong references to an object before you can guarantee that it will work.<\/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-109276","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Giving out strong references to an object before you can guarantee that it will work.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109276","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=109276"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109276\/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=109276"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109276"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109276"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}