{"id":106213,"date":"2022-02-02T07:00:00","date_gmt":"2022-02-02T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106213"},"modified":"2022-02-02T07:23:59","modified_gmt":"2022-02-02T15:23:59","slug":"20220202-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220202-00\/?p=106213","title":{"rendered":"Gotcha: C++\/WinRT weak_ref.get() doesn&#8217;t get the weak reference; it gets the strong reference"},"content":{"rendered":"<p>If you have a <code>winrt::com_ptr&lt;T&gt;<\/code>, you can call the <code>get()<\/code> method to obtain the raw COM pointer inside it. This is handy if you need to pass that raw pointer along to another method that wants raw pointers.<\/p>\n<p>The <code>winrt::weak_ref&lt;T&gt;<\/code> also has a <code>get()<\/code> method, but its behavior is different: It tries to resolve the weak reference to a strong reference and returns that strong reference as a <code>com_ptr&lt;T&gt;<\/code>. If it fails to resolve the weak reference to a strong reference, then it returns an empty <code>com_ptr&lt;T&gt;<\/code>. (If <code>T<\/code> is a projected type, then the returned object is a <code>T<\/code> rather than <code>com_ptr&lt;T&gt;<\/code>, since <code>com_ptr&lt;T&gt;<\/code> is redundant.)<\/p>\n<p>I&#8217;ve seen this gotcha bite people who are familiar with <code>com_ptr<\/code>s, but haven&#8217;t worked much with <code>weak_ref<\/code>. They have a <code>weak_ref<\/code> in their hand and they want to look at the pointer inside it. They&#8217;ll call <code>weak_ref.get()<\/code> (because that&#8217;s what works for <code>com_ptr<\/code>), and not only is that not what they want, the result can be downright dangerous.<\/p>\n<pre>weak_ref&lt;T&gt; saved_weak;\r\n\r\nbool IsTheSavedWeakRef(weak_ref&lt;T&gt; const&amp; ref)\r\n{\r\n    return saved_weak.get() == ref.get();\r\n}\r\n<\/pre>\n<p>The idea here is that we want to compare the <code>IWeak\u00adReference<\/code> pointers hiding inside the <code>weak_ref<\/code> to see if the weak reference passed in is the same one we had saved earlier. Unfortunately, what actually happens is that we resolve both weak references to strong <code>T<\/code> references, and then see if the strong references match.<\/p>\n<p>The first bug is that this treats all broken weak references as equal, even if they aren&#8217;t the <i>same<\/i> weak reference. Indeed, they may even have been obtained from different objects entirely!<\/p>\n<p>The second bug is that the temporary materialization of a strong reference means that when the function returns, those strong references are released, and that can result in object destruction at a time you weren&#8217;t expecting. Suppose we initially have a strong reference to a <code>T<\/code> in a variable called <code>saved_strong<\/code> and a weak reference to the same <code>T<\/code> in a variable called <code>saved_weak<\/code>.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"border: 1px black; border-style: none solid solid none;\">Thread 1<\/td>\n<td style=\"border: 1px black; border-style: none none solid solid;\">Thread 2<\/td>\n<td style=\"width: 1em;\">\u00a0<\/td>\n<td style=\"border-bottom: solid 1px black;\">Refcount on <code>T<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>IsTheSavedWeakRef()<\/code><\/td>\n<td>&nbsp;<\/td>\n<td style=\"width: 1em;\">\u00a0<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td><code>saved_weak.get()<\/code><\/td>\n<td>&nbsp;<\/td>\n<td style=\"width: 1em;\">\u00a0<\/td>\n<td>2<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td><code>saved_strong.reset()<\/code><\/td>\n<td style=\"width: 1em;\">\u00a0<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>temporary <code>com_ptr<\/code> destructs<\/td>\n<td>&nbsp;<\/td>\n<td style=\"width: 1em;\">\u00a0<\/td>\n<td>0<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Initially, there is one strong reference to the object, held in <code>saved_strong<\/code>. The <code>Is\u00adThe\u00adSaved\u00adWeak\u00adRef()<\/code> function tries to promote the <code>saved_weak<\/code> to a strong reference in the form of a <code>com_ptr<\/code> (say), and it succeeds. The number of strong references is now two.<\/p>\n<p>Meanwhile, another thread resets the <code>saved_strong<\/code> strong reference, which would have destructed the object if <code>Is\u00adThe\u00adSaved\u00adWeak\u00adRef()<\/code> hadn&#8217;t created a temporary strong reference. Instead, the reset of <code>saved_strong<\/code> causes the reference count to drop to one.<\/p>\n<p>Back on Thread\u00a01, the <code>Is\u00adThe\u00adSaved\u00adWeak\u00adRef()<\/code> function finishes its comparison and destructs the temporary <code>shared_ptr<\/code>, which drops the reference count to zero and destroys the object.<\/p>\n<p>The <code>Is\u00adThe\u00adSaved\u00adWeak\u00adRef()<\/code> function is destroying an object!<\/p>\n<p>This can be quite a surprise to the authors of <code>Is\u00adThe\u00adSaved\u00adWeak\u00adRef()<\/code>, who thought they were doing completely non-intrusive lightweight operations. In particular, the caller of <code>Is\u00adThe\u00adSaved\u00adWeak\u00adRef()<\/code> might be holding a lock, such as one that is designed to protect access to <code>saved_weak<\/code>.<\/p>\n<p>Now you are in the world of <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20201111-00\/?p=104439\"> destroying an object under a lock<\/a>, and depending on how those objects are structured, this could be harmless or create a potential deadlock or trigger memory corruption due to unexpected reentrancy.<\/p>\n<p><b>Bonus chatter<\/b>: With <a href=\"https:\/\/github.com\/microsoft\/cppwinrt\/pull\/608\"> PR#608<\/a>, you can now compare weak references directly for equality, so you aren&#8217;t tempted to try the <code>get()<\/code> trick.<\/p>\n<p>Nevertheless, if you want to get the raw pointer inside a <code>winrt::weak_ref<\/code>, you can use <code>get_abi<\/code>.<\/p>\n<p><b>Bonus bonus chatter<\/b>: The WIL library has its own quirk related to COM weak references and COM agile references. The <code>wil::com_weak_ref<\/code> and <code>wil::com_agile_ref<\/code> act like a <code>wil::com_ptr<\/code> in most respects, but the <code>query<\/code> and <code>copy<\/code> methods operate on the underlying object, not the weak reference or agile reference itself.<\/p>\n<p>For weak references, this is normally what you want, since there isn&#8217;t much you can query from a weak reference. However, if you have a weak reference to a remote object, you may want to query the weak reference for interfaces like <code>IMarshal<\/code> or <code>IClientSecurity<\/code>, and those queries will go not to the weak reference but to the underlying object.<\/p>\n<p>If you want to perform the query against the weak reference itself, you will have to use a Jedi mind trick to make WIL forget that the pointer was ever a weak pointer: Decay it back to the <code>IUnknown<\/code>, and then operate on that.<\/p>\n<pre>\/\/ marshal = saved_weak.query&lt;IMarshal&gt;(); \/\/ doesn't work, do this instead\r\nauto marshal = wil::com_query&lt;IMarshal&gt;(static_cast&lt;IUnknown*&gt;(saved_weak.get()));\r\n<\/pre>\n<p>Here, we use the free <code>com_query<\/code> function which does the equivalent of a <code>com_ptr.query<\/code>, but as a free function instead of requiring a <code>com_ptr<\/code> in hand.<\/p>\n<p>(Personally, I think this magic behavior of weak and agile references is a pit of failure. I think the methods should have been called <code>lock<\/code> or <code>resolve<\/code>. Reserve <code>get<\/code> for extracting the raw ABI pointer.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>What traditionally goes by the name <CODE>lock()<\/CODE>.<\/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-106213","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>What traditionally goes by the name <CODE>lock()<\/CODE>.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106213","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=106213"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106213\/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=106213"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106213"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106213"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}