{"id":94855,"date":"2016-12-05T07:00:00","date_gmt":"2016-12-05T22:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=94855"},"modified":"2019-03-13T10:34:31","modified_gmt":"2019-03-13T17:34:31","slug":"20161205-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20161205-00\/?p=94855","title":{"rendered":"The case of the unexpected ERROR_ACCESS_DENIED when calling MapViewOfFile"},"content":{"rendered":"<p>A customer was trying to figure out how to use shared memory, but even their simplest program couldn&#8217;t work. The customer shared their code and asked for help. <\/p>\n<p>The first process creates a named file mapping object backed by the page file. The second process opens the file mapping object by name, and then maps a view of that file mapping object. But the attempt to map the view always fails with <code>ERROR_ACCESS_DENIED<\/code>. The file mapping object was created by the first process as read\/write, and it was opened by the second process as read\/write. The two processes are running in the same session as the same user. And yet, the second process can&#8217;t get access. What&#8217;s wrong? <\/p>\n<p>To simplify presentation, error checking has been deleted. Instead, we will describe what happened with comments. <\/p>\n<pre>\n<i>\/\/ code in italics is wrong\n\/\/\n\/\/ Program 1\n\n#include &lt;windows.h&gt;\n\nint main(int, char**)\n{\n \/\/ This succeeds with a non-null handle.\n HANDLE fileMapping = CreateFileMapping(\n    INVALID_HANDLE_VALUE, \/\/ backed by page file\n    nullptr,              \/\/ default security\n    PAGE_READWRITE,       \/\/ read-write access\n    0,                    \/\/ high part of size\n    65536,                \/\/ low part of size\n    L\"Local\\\\FileMappingTest\"); \/\/ name\n\n \/\/ This succeeds with a non-null pointer.\n void* view = MapViewOfFile(\n    fileMapping,\n    FILE_MAP_READ | FILE_MAP_WRITE, \/\/ desired access\n    0, 0,                   \/\/ file offset zero\n    0);                     \/\/ map the whole thing\n\n  Sleep(5000); \/\/ pause to let user run second process\n\n  UnmapViewOfFile(view);\n  CloseHandle(fileMapping);\n \n  return 0;\n}\n\n\/\/ Program 2\n#include &lt;windows.h&gt;\n\nint main(int, char**)\n{\n \/\/ This succeeds with a non-null handle.\n HANDLE fileMapping = OpenFileMapping(\n    PAGE_READWRITE,       \/\/ read-write access\n    FALSE,                \/\/ don't inherit this handle\n    L\"Local\\\\FileMappingTest\"); \/\/ name\n\n \/\/ This fails with a null pointer.\n \/\/ GetLastError() returns ERROR_ACCESS_DENIED.\n void* view = MapViewOfFile(\n    fileMapping,\n    FILE_MAP_READ | FILE_MAP_WRITE, \/\/ desired access\n    0, 0,                   \/\/ file offset zero\n    0);                     \/\/ map the whole thing\n\n  UnmapViewOfFile(view);\n  CloseHandle(fileMapping);\n \n  return 0;\n}<\/i>\n<\/pre>\n<p>The customer added that the second process successfully opened the file mapping object, so presumably the handle does have read\/write access. Otherwise, the <code>Open&shy;File&shy;Mapping<\/code> would have failed with <code>ERROR_ACCESS_DENIED<\/code> right away, rather than waiting for the <code>Map&shy;View&shy;Of&shy;File<\/code>. <\/p>\n<p>Study these programs and see if you can find the problem. <\/p>\n<p>(Time passes.) <\/p>\n<p>The problem is that the first parameter to <code>Open&shy;File&shy;Mapping<\/code> is not supposed to be a <code>PAGE_*<\/code> value. It&#8217;s supposed to be a <code>FILE_MAP_*<\/code> value. This is easily overlooked because you are tempted to just do a copy\/paste of the <code>Create&shy;File&shy;Mapping<\/code> call&#8217;s parameters, and just delete the parameters related specifically to creation, like file size and security descriptor. <\/p>\n<p>However, it is a common&sup1; pattern that <code>Create<\/code> functions return a handle with full access and do not have an explicit access mask parameter, whereas <code>Open<\/code> functions accept an access mask parameter that controls what level of access the returned handle has. <\/p>\n<p>The numeric value of <code>PAGE_READ&shy;WRITE<\/code> is 4, which happens to match the numeric value of <code>FILE_MAP_READ<\/code>. Therefore, the second program successfully opened the file mapping for read, but when it tried to map it for read and write, it got <code>ERROR_ACCESS_DENIED<\/code> because it&#8217;s trying to obtain a mapping for writing, even though the mapping was opened only for read. <\/p>\n<p>This is one of the nasty pitfalls of using plain old integers for flags. There&#8217;s no type safety: Integers look the same. <\/p>\n<p>&sup1; Note that the pattern is common but not not universal. The most notable exception is <code>Create&shy;File<\/code>, which takes an explicit access mask. But if you think about it some more, <code>Create&shy;File<\/code> is an open-like function, because if the file already exists, <code>Create&shy;File<\/code> opens a handle to it, and it uses the requested access mask to evaluate whether your attempt to open that handle will succeed. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Mind those weakly-typed integers.<\/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-94855","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Mind those weakly-typed integers.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/94855","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=94855"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/94855\/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=94855"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=94855"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=94855"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}