{"id":16073,"date":"2009-11-11T07:00:00","date_gmt":"2009-11-11T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2009\/11\/11\/trying-to-avoid-double-destruction-and-inadvertently-triggering-it\/"},"modified":"2009-11-11T07:00:00","modified_gmt":"2009-11-11T07:00:00","slug":"trying-to-avoid-double-destruction-and-inadvertently-triggering-it","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20091111-00\/?p=16073","title":{"rendered":"Trying to avoid double-destruction and inadvertently triggering it"},"content":{"rendered":"<p>\nWe saw some time ago the importance of\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/09\/28\/474855.aspx\">\nartificially bumping an object&#8217;s reference count during destruction\nto avoid double-destruction<\/a>.\nHowever, one person&#8217;s attempt to avoid this problem ended up triggering it.\n<\/p>\n<pre>\nULONG MyObject::Release()\n{\n LONG cRef = InterlockedDecrement(&amp;m_cRef);\n if (cRef &gt; 0) return cRef;\n m_cRef = MAXLONG; \/\/ avoid double-destruction\n delete this;\n return 0;\n}\n<\/pre>\n<p>\nThe explanation for the line <code>m_cRef = MAXLONG<\/code>\nwas that it was done\nto avoid the double-destruction problem if the object receives\na temporary <code>AddRef\/Release<\/code> during destruction.\n<\/p>\n<p>\nWhile it&#8217;s true that you should set the reference count to an artificial\nnon-zero value,\nchoosing <code>MAXLONG<\/code> has its own problem:\ninteger overflow.\n<\/p>\n<p>\nSuppose that during the object&#8217;s destruction,\nthe reference count is temporarily incremented twice and decremented\ntwice.\n<\/p>\n<table BORDER=\"1\" CELLPADDING=\"3\">\n<tr>\n<th>Action<\/th>\n<th>m_cRef<\/th>\n<\/tr>\n<tr>\n<td>Just before call to Release()<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>InterlockedDecrement<\/td>\n<td>0<\/td>\n<\/tr>\n<tr>\n<td>m_cRef = MAXLONG<\/td>\n<td>2147483647<\/td>\n<\/tr>\n<tr>\n<td>destructor does temporary <code>AddRef()<\/code><\/td>\n<td>&minus;2147483648 (integer overflow)<\/td>\n<\/tr>\n<tr>\n<td>destructor does temporary <code>AddRef()<\/code><\/td>\n<td>&minus;2147483647<\/td>\n<\/tr>\n<tr>\n<td>destructor does temporary <code>Release()<\/code><\/td>\n<td>&minus;2147483648<\/td>\n<\/tr>\n<tr>\n<td COLSPAN=\"2\">since <code>m_cRef<\/code> &lt; 0, we re-destruct<\/td>\n<\/tr>\n<\/table>\n<p>\nSure, choosing a huge <code>DESTRUCTOR_REFCOUNT<\/code>\nmeans that you have absolutely no chance of decrementing\nthe reference count back to zero prematurely.\nHowever, if you choose a value too high, you introduce the\nrisk of <i>incrementing<\/i> the reference count\nso high that it overflows.\n<\/p>\n<p>\nThat&#8217;s why the most typical values for <code>DESTRUCTOR_REFCOUNT<\/code>\nare 1, 42, and 1000.\nThe value 1 is really all you need to avoid double-destruction.\nSome people choose 42 because it&#8217;s cute,\nand other people choose 1000 because it&#8217;s higher than any &#8220;normal&#8221;\nrefcount, so it makes it easier to spot during debugging.\nBut even then, the &#8220;high&#8221; value of 1000 still leaves room for over\ntwo billion <code>AddRef()<\/code>s before overflowing the\nreference count.\n<\/p>\n<p>\nOn the other hand, if you choose a value like <code>MAXLONG<\/code>\nor <code>MAXDWORD<\/code>,\nthen you&#8217;re taking something that previously never happened\n(reference count integer overflow)\nand turning it into an almost certainty.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We saw some time ago the importance of artificially bumping an object&#8217;s reference count during destruction to avoid double-destruction. However, one person&#8217;s attempt to avoid this problem ended up triggering it. ULONG MyObject::Release() { LONG cRef = InterlockedDecrement(&amp;m_cRef); if (cRef &gt; 0) return cRef; m_cRef = MAXLONG; \/\/ avoid double-destruction delete this; return 0; } [&hellip;]<\/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-16073","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>We saw some time ago the importance of artificially bumping an object&#8217;s reference count during destruction to avoid double-destruction. However, one person&#8217;s attempt to avoid this problem ended up triggering it. ULONG MyObject::Release() { LONG cRef = InterlockedDecrement(&amp;m_cRef); if (cRef &gt; 0) return cRef; m_cRef = MAXLONG; \/\/ avoid double-destruction delete this; return 0; } [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/16073","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=16073"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/16073\/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=16073"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=16073"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=16073"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}