{"id":34343,"date":"2005-09-01T10:00:17","date_gmt":"2005-09-01T10:00:17","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2005\/09\/01\/more-undocumented-behavior-and-the-people-who-rely-on-it-output-buffers\/"},"modified":"2005-09-01T10:00:17","modified_gmt":"2005-09-01T10:00:17","slug":"more-undocumented-behavior-and-the-people-who-rely-on-it-output-buffers","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050901-17\/?p=34343","title":{"rendered":"More undocumented behavior and the people who rely on it: Output buffers"},"content":{"rendered":"<p><P>\nFor functions that return data,\nthe contents of the output buffer if the function fails are typically\nleft unspecified.\nIf the function fails, callers should assume nothing about the contents.\n<\/P>\n<P>\nBut that doesn&#8217;t stop them from assuming it anyway.\n<\/P>\n<P>\nI was reminded of this topic after reading\n<A HREF=\"http:\/\/blogs.msdn.com\/michkap\/archive\/2005\/03\/06\/386194.aspx\">\nMichael Kaplan&#8217;s story of one customer who wanted the output buffer\ncontents to be defined even on failure<\/A>.\nThe reason the buffer is left untouched is because many\nprograms assume that the buffer is unchanged on failure,\neven though there is no documentation supporting this behavior.\n<\/P>\n<P>\nHere&#8217;s one example of code I&#8217;ve seen (reconstructed) that relies\non the output buffer being left unchanged:\n<\/P>\n<PRE>\n<I>HKEY hk = hkFallback;\nRegOpenKeyEx(&#8230;, &amp;hk);\nRegQueryValue(hk, &#8230;);\nif (hk != hkFallback) RegCloseKey(hk);\n<\/I><\/PRE>\n<P>\nThis code fragment starts out with a fallback key then tries\nto open a &#8220;better&#8221; key,\nassuming that if the open fails,\nthe contents of the <CODE>hk<\/CODE> variable will be left unchanged\nand therefore will continue to have the original fallback value.\nThis behavior is not guaranteed by the specification for\n<A HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/sysinfo\/base\/regopenkeyex.asp\">\nthe <CODE>RegOpenKeyEx<\/CODE> function<\/A>, but that doesn&#8217;t stop people\nfrom relying on it anyway.\n<\/P>\n<P>\nHere&#8217;s another example\n<A HREF=\"http:\/\/cvs.sourceforge.net\/viewcvs.py\/cdexos\/cdexos\/Registry.cpp?rev=1.3\">\nfrom actual shipping code<\/A>.\nObserve that the <CODE>CRegistry::Restore<\/CODE> method is documented\nas &#8220;If the specified key does not exist, the value of &#8216;Value&#8217; is unchanged.&#8221;\n(Let&#8217;s ignore for now that the documentation uses registry\nterminology incorrectly; the parameter specified is a value name,\nnot a key name.)\nIf you look at what the code actually does,\nit loads the buffer with the original value of &#8220;Value&#8221;,\nthen calls\n<A HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/sysinfo\/base\/regqueryvalueex.asp\">\nthe <CODE>RegQueryValueEx<\/CODE> function<\/A> twice\nand ignores the return value both times!\nThe real work happens in the <CODE>CRegistry::RestoreDWORD<\/CODE>\nfunction.\nAt the first call, observe that it initializes\nthe <CODE>type<\/CODE> variable, then calls\nthe <CODE>RegQueryValueEx<\/CODE> function and assumes that\nit does not modify the\n<CODE>&amp;type<\/CODE> parameter on failure.\nNext, it calls\nthe <CODE>RegQueryValueEx<\/CODE> function a second time,\nthis time assuming that the output buffer\n<CODE>&amp;Value<\/CODE> remains unchanged in the event of failure,\nbecause that&#8217;s what <CODE>CRegistry::Restore<\/CODE> expects.\n<\/P>\n<P>\nI don&#8217;t mean to pick on that code sample.\nIt was merely a convenient example\nof the sorts of abuses that Win32 needs to sustain\non a regular basis for the sake of compatibility.\nBecause, after all, people buy computers in order to\nrun programs on them.\n<\/P>\n<P>\nOne significant exception to the &#8220;output buffers are undefined on failure&#8221;\nrule is output buffers returned by COM interface methods.\nCOM rules are that output buffers are always initialized, even on failure.\nThis is necessary to ensure that the marshaller doesn&#8217;t crash.\nFor example, the last parameter to the IUnknown::QueryInterface method\nmust be set to NULL on failure.\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>For functions that return data, the contents of the output buffer if the function fails are typically left unspecified. If the function fails, callers should assume nothing about the contents. But that doesn&#8217;t stop them from assuming it anyway. I was reminded of this topic after reading Michael Kaplan&#8217;s story of one customer who wanted [&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-34343","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>For functions that return data, the contents of the output buffer if the function fails are typically left unspecified. If the function fails, callers should assume nothing about the contents. But that doesn&#8217;t stop them from assuming it anyway. I was reminded of this topic after reading Michael Kaplan&#8217;s story of one customer who wanted [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/34343","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=34343"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/34343\/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=34343"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=34343"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=34343"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}