{"id":91411,"date":"2015-10-08T07:00:00","date_gmt":"2015-10-08T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20151008-00\/?p=91411\/"},"modified":"2019-03-13T12:20:22","modified_gmt":"2019-03-13T19:20:22","slug":"20151008-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20151008-00\/?p=91411","title":{"rendered":"What happens if you call VirtualAlloc to MEM_COMMIT a page you never MEM_RESERVE?"},"content":{"rendered":"<p>A customer reported that while trying to solve a problem with their program, they noticed that they had been calling <code>Virtual&shy;Alloc<\/code> incorrectly for years. They were able to reduce it into a simple program: <\/p>\n<pre>\n#include &lt;windows.h&gt;\n#include &lt;stdio.h&gt;\n#include &lt;tchar.h&gt;\n\nint _tmain(int argc, _TCHAR* argv[])\n{\n LPVOID base = VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_READWRITE);\n _tprintf(TEXT(\"Allocated at %p\\n\"), base);\n return 0;\n}\n<\/pre>\n<p>First of all, thank you for <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/10\/18\/10457796.aspx\">reducing<\/a> your program. That really focuses the investigation. <\/p>\n<p>The customer noted that their code was passing the <code>MEM_COMMIT<\/code> flag without the <code>MEM_RESERVE<\/code> flag, a scenario that is specifically called out in the documentation: <\/p>\n<blockquote CLASS=\"q\"><p>The function fails if you attempt to commit a page that has not been reserved.  The resulting error code is <b>ERROR_INVALID_ADDRESS<\/b>. <\/p><\/blockquote>\n<p>But their call to <code>Virtual&shy;Alloc<\/code> was succeeding! The customer suspected that this was not actually the source of their problem, but they wanted to double-check that perhaps their incorrect use of <code>Virtual&shy;Alloc<\/code> was somehow indirectly contributing to it. Specifically, they were wondering if what they&#8217;re doing is okay, or whether they should always use <code>MEM_RESERVE | MEM_COMMIT<\/code>. <\/p>\n<p>What the customer found is a compatibility hack. A lot of application forget to set the <code>MEM_RESERVE<\/code> flag when they <code>MEM_COMMIT<\/code>, so the memory manager lets it slide if they also pass <code>lpAddress = NULL<\/code>, indicating that they are requesting a new allocation rather than modifying an existing one. <\/p>\n<p>The problem is that MSDN fell into the trap of over-documenting. Instead of documenting the contract, MSDN documented the implementation. The contract is &#8220;A page being committed must also be reserved.&#8221; If you try to commit a page that is not also reserved, then the behavior is unspecified. It is therefore valid for the implementation to treat the violation as &#8220;Sorry, you lose,&#8221; or &#8220;Okay, I&#8217;ll let you do it, but just this time.&#8221; <\/p>\n<p>It appears that some time after this issue was identified, the MSDN documentation was revised. But they didn&#8217;t revise it by documenting the contract. They revised it by documenting the implementation <i>more precisely<\/i>. <\/p>\n<blockquote CLASS=\"q\"><p>Attempting to commit a specific address range by specifying <b>MEM_COMMIT<\/b> without <b>MEM_RESERVE<\/b> and a non-<b>NULL<\/b> <i>lpAddress<\/i> fails unless the entire range has already been reserved. The resulting error code is <b>ERROR_INVALID_ADDRESS<\/b>. <\/p><\/blockquote>\n<p>My recommendation to the customer was to switch to <code>MEM_RESERVE | MEM_COMMIT<\/code>, since that is the preferred behavior and therefore the one least likely to trigger compatibility behavior. But the fact that they were accidentally omitting the <code>MEM_RESERVE<\/code> was not related to their problem, and they should keep looking. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>It is not guaranteed to succeed.<\/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-91411","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It is not guaranteed to succeed.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/91411","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=91411"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/91411\/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=91411"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=91411"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=91411"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}