kernel32: Add the tests for various combinations of CreateFileMapping/MapViewOfFile protections.
Dmitry Timoshkov
dmitry at baikal.ru
Wed Dec 14 23:42:19 CST 2011
---
dlls/kernel32/tests/virtual.c | 292 ++++++++++++++++++++++++++++++++++++++++-
1 files changed, 291 insertions(+), 1 deletions(-)
diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c
index d38da6a..768d724 100644
--- a/dlls/kernel32/tests/virtual.c
+++ b/dlls/kernel32/tests/virtual.c
@@ -1699,6 +1699,7 @@ static void test_CreateFileMapping_protection(void)
{
if (!hmap)
{
+ trace("%d: CreateFileMapping(%04x) failed: %d\n", i, td[i].prot, GetLastError());
/* NT4 and win2k don't support EXEC on file mappings */
if (td[i].prot == PAGE_EXECUTE_READ || td[i].prot == PAGE_EXECUTE_READWRITE)
{
@@ -1714,7 +1715,7 @@ static void test_CreateFileMapping_protection(void)
continue;
}
}
- ok(hmap != 0, "%d: CreateFileMapping error %d\n", i, GetLastError());
+ ok(hmap != 0, "%d: CreateFileMapping(%04x) error %d\n", i, td[i].prot, GetLastError());
base = MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0);
ok(base != NULL, "%d: MapViewOfFile failed %d\n", i, GetLastError());
@@ -1871,6 +1872,294 @@ static void test_CreateFileMapping_protection(void)
DeleteFile(file_name);
}
+#define ACCESS_READ 0x01
+#define ACCESS_WRITE 0x02
+#define ACCESS_EXECUTE 0x04
+#define ACCESS_WRITECOPY 0x08
+
+static DWORD page_prot_to_access(DWORD prot)
+{
+ switch (prot)
+ {
+ case PAGE_READWRITE:
+ return ACCESS_READ | ACCESS_WRITE;
+
+ case PAGE_EXECUTE:
+ case PAGE_EXECUTE_READ:
+ return ACCESS_READ | ACCESS_EXECUTE;
+
+ case PAGE_EXECUTE_READWRITE:
+ return ACCESS_READ | ACCESS_WRITE | ACCESS_WRITECOPY | ACCESS_EXECUTE;
+
+ case PAGE_EXECUTE_WRITECOPY:
+ return ACCESS_READ | ACCESS_WRITECOPY | ACCESS_EXECUTE;
+
+ case PAGE_READONLY:
+ return ACCESS_READ;
+
+ case PAGE_WRITECOPY:
+ return ACCESS_READ;
+
+ default:
+ return 0;
+ }
+}
+
+static BOOL is_compatible_protection(DWORD map_prot, DWORD view_prot, DWORD prot)
+{
+ DWORD map_access, view_access, prot_access;
+
+ map_access = page_prot_to_access(map_prot);
+ view_access = page_prot_to_access(view_prot);
+ prot_access = page_prot_to_access(prot);
+
+ if (view_access == prot_access) return TRUE;
+ if (!view_access) return FALSE;
+
+ if ((view_access & prot_access) != prot_access) return FALSE;
+ if ((map_access & prot_access) == prot_access) return TRUE;
+
+ return FALSE;
+}
+
+static DWORD map_prot_to_access(DWORD prot)
+{
+ switch (prot)
+ {
+ case PAGE_READWRITE:
+ case PAGE_EXECUTE_READWRITE:
+ return SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE | SECTION_MAP_EXECUTE_EXPLICIT | SECTION_QUERY;
+ case PAGE_READONLY:
+ case PAGE_WRITECOPY:
+ case PAGE_EXECUTE:
+ case PAGE_EXECUTE_READ:
+ case PAGE_EXECUTE_WRITECOPY:
+ return SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_MAP_EXECUTE_EXPLICIT | SECTION_QUERY;
+ default:
+ return 0;
+ }
+}
+
+static BOOL is_compatible_access(DWORD map_prot, DWORD view_prot)
+{
+ DWORD access = map_prot_to_access(map_prot);
+ return (view_prot & access) == view_prot;
+}
+
+static void test_mapping(void)
+{
+ static const DWORD page_prot[] =
+ {
+ PAGE_NOACCESS, PAGE_READONLY, PAGE_READWRITE, PAGE_WRITECOPY,
+ PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY
+ };
+ static const struct
+ {
+ DWORD access, prot;
+ } view[] =
+ {
+ { 0, PAGE_NOACCESS }, /* 0x00 */
+ { FILE_MAP_COPY, PAGE_WRITECOPY }, /* 0x01 */
+ { FILE_MAP_WRITE, PAGE_READWRITE }, /* 0x02 */
+ { FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_READWRITE }, /* 0x03 */
+ { FILE_MAP_READ, PAGE_READONLY }, /* 0x04 */
+ { FILE_MAP_READ | FILE_MAP_COPY, PAGE_READONLY }, /* 0x05 */
+ { FILE_MAP_READ | FILE_MAP_WRITE, PAGE_READWRITE }, /* 0x06 */
+ { FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_READWRITE }, /* 0x07 */
+ { SECTION_MAP_EXECUTE, PAGE_NOACCESS }, /* 0x08 */
+ { SECTION_MAP_EXECUTE | FILE_MAP_COPY, PAGE_NOACCESS }, /* 0x09 */
+ { SECTION_MAP_EXECUTE | FILE_MAP_WRITE, PAGE_READWRITE }, /* 0x0a */
+ { SECTION_MAP_EXECUTE | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_READWRITE }, /* 0x0b */
+ { SECTION_MAP_EXECUTE | FILE_MAP_READ, PAGE_READONLY }, /* 0x0c */
+ { SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_COPY, PAGE_READONLY }, /* 0x0d */
+ { SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE, PAGE_READWRITE }, /* 0x0e */
+ { SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_READWRITE }, /* 0x0f */
+ { FILE_MAP_EXECUTE, PAGE_NOACCESS }, /* 0x20 */
+ { FILE_MAP_EXECUTE | FILE_MAP_COPY, PAGE_EXECUTE_WRITECOPY }, /* 0x21 */
+ { FILE_MAP_EXECUTE | FILE_MAP_WRITE, PAGE_EXECUTE_READWRITE }, /* 0x22 */
+ { FILE_MAP_EXECUTE | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_EXECUTE_READWRITE }, /* 0x23 */
+ { FILE_MAP_EXECUTE | FILE_MAP_READ, PAGE_EXECUTE_READ }, /* 0x24 */
+ { FILE_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_COPY, PAGE_EXECUTE_READ }, /* 0x25 */
+ { FILE_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE, PAGE_EXECUTE_READWRITE }, /* 0x26 */
+ { FILE_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_EXECUTE_READWRITE }, /* 0x27 */
+ { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE, PAGE_NOACCESS }, /* 0x28 */
+ { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_COPY, PAGE_NOACCESS }, /* 0x29 */
+ { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_WRITE, PAGE_EXECUTE_READWRITE }, /* 0x2a */
+ { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_EXECUTE_READWRITE }, /* 0x2b */
+ { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_READ, PAGE_EXECUTE_READ }, /* 0x2c */
+ { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_COPY, PAGE_EXECUTE_READ }, /* 0x2d */
+ { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE, PAGE_EXECUTE_READWRITE }, /* 0x2e */
+ { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_EXECUTE_READWRITE } /* 0x2f */
+ };
+ void *base;
+ DWORD i, j, k, ret, old_prot, prev_prot;
+ SYSTEM_INFO si;
+ char temp_path[MAX_PATH];
+ char file_name[MAX_PATH];
+ HANDLE hfile, hmap;
+ MEMORY_BASIC_INFORMATION info;
+
+ GetSystemInfo(&si);
+ trace("system page size %#x\n", si.dwPageSize);
+
+ GetTempPath(MAX_PATH, temp_path);
+ GetTempFileName(temp_path, "map", 0, file_name);
+
+ SetLastError(0xdeadbeef);
+ hfile = CreateFile(file_name, GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE, 0, NULL, CREATE_ALWAYS, 0, 0);
+ ok(hfile != INVALID_HANDLE_VALUE, "CreateFile(%s) error %d\n", file_name, GetLastError());
+ SetFilePointer(hfile, si.dwPageSize, NULL, FILE_BEGIN);
+ SetEndOfFile(hfile);
+
+ for (i = 0; i < sizeof(page_prot)/sizeof(page_prot[0]); i++)
+ {
+ SetLastError(0xdeadbeef);
+ hmap = CreateFileMapping(hfile, NULL, page_prot[i] | SEC_COMMIT, 0, si.dwPageSize, NULL);
+
+ if (!hmap)
+ {
+ trace("%d: CreateFileMapping(%04x) failed: %d\n", i, page_prot[i], GetLastError());
+
+ if (page_prot[i] == PAGE_NOACCESS)
+ {
+ ok(!hmap, "%d: CreateFileMapping(%04x) should fail\n", i, page_prot[i]);
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
+ continue;
+ }
+ /* NT4 and win2k don't support EXEC on file mappings */
+ if (page_prot[i] == PAGE_EXECUTE_READ || page_prot[i] == PAGE_EXECUTE_READWRITE)
+ {
+ ok(broken(!hmap), "%d: CreateFileMapping doesn't support PAGE_EXECUTE\n", i);
+ continue;
+ }
+ /* Vista+ supports PAGE_EXECUTE_WRITECOPY, earlier versions don't */
+ if (page_prot[i] == PAGE_EXECUTE_WRITECOPY)
+ {
+ ok(broken(!hmap), "%d: CreateFileMapping doesn't support PAGE_EXECUTE_WRITECOPY\n", i);
+ continue;
+ }
+ }
+
+ ok(hmap != 0, "%d: CreateFileMapping(%04x) error %d\n", i, page_prot[i], GetLastError());
+
+ for (j = 0; j < sizeof(view)/sizeof(view[0]); j++)
+ {
+ SetLastError(0xdeadbeef);
+ base = MapViewOfFile(hmap, view[j].access, 0, 0, 0);
+
+ if (!is_compatible_access(page_prot[i], view[j].access))
+ {
+ ok(!base, "%d: MapViewOfFile(%04x/%04x) should fail\n", j, page_prot[i], view[j].access);
+ ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
+ continue;
+ }
+
+ /* Vista+ properly supports FILE_MAP_EXECUTE, earlier versions don't */
+ if (!base && (view[j].access & FILE_MAP_EXECUTE))
+ {
+ ok(broken(!base), "%d: MapViewOfFile(%04x/%04x) failed %d\n", j, page_prot[i], view[j].access, GetLastError());
+ continue;
+ }
+
+ ok(base != NULL, "%d: MapViewOfFile(%04x/%04x) failed %d\n", j, page_prot[i], view[j].access, GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = VirtualQuery(base, &info, sizeof(info));
+ ok(ret, "%d: VirtualQuery failed %d\n", j, GetLastError());
+ ok(info.BaseAddress == base, "%d: (%04x) got %p, expected %p\n", j, view[j].access, info.BaseAddress, base);
+ ok(info.RegionSize == si.dwPageSize, "%d: (%04x) got %#lx != expected %#x\n", j, view[j].access, info.RegionSize, si.dwPageSize);
+ /* FIXME: completely remove the condition below once Wine is fixed */
+ if (info.Protect != view[j].prot)
+ todo_wine
+ ok(info.Protect == view[j].prot ||
+ broken(view[j].prot == PAGE_EXECUTE_READ && info.Protect == PAGE_READONLY) || /* win2k */
+ broken(view[j].prot == PAGE_EXECUTE_READWRITE && info.Protect == PAGE_READWRITE) || /* win2k */
+ broken(view[j].prot == PAGE_EXECUTE_WRITECOPY && info.Protect == PAGE_NOACCESS), /* XP */
+ "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, info.Protect, view[j].prot);
+ else
+ ok(info.Protect == view[j].prot ||
+ broken(view[j].prot == PAGE_EXECUTE_READ && info.Protect == PAGE_READONLY) || /* win2k */
+ broken(view[j].prot == PAGE_EXECUTE_READWRITE && info.Protect == PAGE_READWRITE) || /* win2k */
+ broken(view[j].prot == PAGE_EXECUTE_WRITECOPY && info.Protect == PAGE_NOACCESS), /* XP */
+ "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, info.Protect, view[j].prot);
+ ok(info.AllocationBase == base, "%d: (%04x) got %p, expected %p\n", j, view[j].access, info.AllocationBase, base);
+ ok(info.AllocationProtect == info.Protect, "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, info.AllocationProtect, info.Protect);
+ ok(info.State == MEM_COMMIT, "%d: (%04x) got %#x, expected MEM_COMMIT\n", j, view[j].access, info.State);
+ ok(info.Type == MEM_MAPPED, "%d: (%04x) got %#x, expected MEM_MAPPED\n", j, view[j].access, info.Type);
+
+ prev_prot = info.Protect;
+
+ for (k = 0; k < sizeof(page_prot)/sizeof(page_prot[0]); k++)
+ {
+ /*trace("map %#x, view %#x, requested prot %#x\n", page_prot[i], view[j].prot, page_prot[k]);*/
+ SetLastError(0xdeadbeef);
+ old_prot = 0xdeadbeef;
+ ret = VirtualProtect(base, si.dwPageSize, page_prot[k], &old_prot);
+ if (is_compatible_protection(page_prot[i], view[j].prot, page_prot[k]))
+ {
+ /* FIXME: completely remove the condition below once Wine is fixed */
+ if (!ret && page_prot[k] == PAGE_WRITECOPY)
+ {
+ todo_wine
+ ok(ret, "VirtualProtect error %d\n", GetLastError());
+ continue;
+ }
+ /* win2k and XP don't support EXEC on file mappings */
+ if (!ret && page_prot[k] == PAGE_EXECUTE)
+ {
+ ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE\n");
+ continue;
+ }
+ /* NT4 and win2k don't support EXEC on file mappings */
+ if (!ret && (page_prot[k] == PAGE_EXECUTE_READ || page_prot[k] == PAGE_EXECUTE_READWRITE))
+ {
+ ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE\n");
+ continue;
+ }
+ /* Vista+ supports PAGE_EXECUTE_WRITECOPY, earlier versions don't */
+ if (!ret && page_prot[k] == PAGE_EXECUTE_WRITECOPY)
+ {
+ todo_wine
+ ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE_WRITECOPY\n");
+ continue;
+ }
+ /* win2k and XP don't support PAGE_EXECUTE_WRITECOPY views properly */
+ if (!ret && view[j].prot == PAGE_EXECUTE_WRITECOPY)
+ {
+ ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE_WRITECOPY view properly\n");
+ continue;
+ }
+
+ ok(ret, "VirtualProtect error %d, map %#x, view %#x, requested prot %#x\n", GetLastError(), page_prot[i], view[j].prot, page_prot[k]);
+ ok(old_prot == prev_prot, "got %#x, expected %#x\n", old_prot, prev_prot);
+ prev_prot = page_prot[k];
+ }
+ else
+ {
+ /* NT4 doesn't fail on incompatible map and view */
+ if (ret)
+ {
+ todo_wine
+ ok(broken(ret), "VirtualProtect should fail, map %#x, view %#x, requested prot %#x\n", page_prot[i], view[j].prot, page_prot[k]);
+ skip("Incompatible map and view are not properly handled on this platform\n");
+ break; /* NT4 won't pass remaining tests */
+ }
+
+ ok(!ret, "VirtualProtect should fail, map %#x, view %#x, requested prot %#x\n", page_prot[i], view[j].prot, page_prot[k]);
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+ }
+ }
+
+ UnmapViewOfFile(base);
+ }
+
+ CloseHandle(hmap);
+ }
+
+ CloseHandle(hfile);
+ DeleteFile(file_name);
+}
+
START_TEST(virtual)
{
int argc;
@@ -1906,6 +2195,7 @@ START_TEST(virtual)
pResetWriteWatch = (void *) GetProcAddress(hkernel32, "ResetWriteWatch");
pNtAreMappedFilesTheSame = (void *)GetProcAddress( GetModuleHandle("ntdll.dll"),
"NtAreMappedFilesTheSame" );
+ test_mapping();
test_CreateFileMapping_protection();
test_VirtualAlloc_protection();
test_VirtualProtect();
--
1.7.7.4
More information about the wine-patches
mailing list