1 /*
2  * Unit test suite for Virtual* family of APIs.
3  *
4  * Copyright 2004 Dmitry Timoshkov
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include "precomp.h"
22 
23 #include <wine/exception.h>
24 
25 #define NUM_THREADS 4
26 #define MAPPING_SIZE 0x100000
27 
28 static HINSTANCE hkernel32, hntdll;
29 static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
30 static BOOL   (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD);
31 static UINT   (WINAPI *pGetWriteWatch)(DWORD,LPVOID,SIZE_T,LPVOID*,ULONG_PTR*,ULONG*);
32 static UINT   (WINAPI *pResetWriteWatch)(LPVOID,SIZE_T);
33 static NTSTATUS (WINAPI *pNtAreMappedFilesTheSame)(PVOID,PVOID);
34 static NTSTATUS (WINAPI *pNtCreateSection)(HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *,
35                                            const LARGE_INTEGER *, ULONG, ULONG, HANDLE );
36 static NTSTATUS (WINAPI *pNtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG, SIZE_T, const LARGE_INTEGER *, SIZE_T *, ULONG, ULONG, ULONG);
37 static DWORD (WINAPI *pNtUnmapViewOfSection)(HANDLE, PVOID);
38 static NTSTATUS (WINAPI *pNtQuerySection)(HANDLE, SECTION_INFORMATION_CLASS, void *, ULONG, ULONG *);
39 static PVOID  (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG, PVECTORED_EXCEPTION_HANDLER);
40 static ULONG  (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID);
41 static BOOL   (WINAPI *pGetProcessDEPPolicy)(HANDLE, LPDWORD, PBOOL);
42 static BOOL   (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
43 static NTSTATUS (WINAPI *pNtProtectVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG, ULONG *);
44 static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG, SIZE_T *, ULONG, ULONG);
45 static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG);
46 
47 /* ############################### */
48 
49 static UINT_PTR page_mask = 0xfff;
50 #define ROUND_SIZE(addr,size) \
51    (((SIZE_T)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask)
52 
53 static PIMAGE_NT_HEADERS image_nt_header(HMODULE module)
54 {
55     IMAGE_NT_HEADERS *ret = NULL;
56     IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)module;
57 
58     if (dos->e_magic == IMAGE_DOS_SIGNATURE)
59     {
60         ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
61         if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
62     }
63     return ret;
64 }
65 
66 static HANDLE create_target_process(const char *arg)
67 {
68     char **argv;
69     char cmdline[MAX_PATH];
70     PROCESS_INFORMATION pi;
71     BOOL ret;
72     STARTUPINFOA si = { 0 };
73     si.cb = sizeof(si);
74 
75     winetest_get_mainargs( &argv );
76     sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg);
77     ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
78     ok(ret, "error: %u\n", GetLastError());
79     ret = CloseHandle(pi.hThread);
80     ok(ret, "error %u\n", GetLastError());
81     return pi.hProcess;
82 }
83 
84 static void test_VirtualAllocEx(void)
85 {
86     const unsigned int alloc_size = 1<<15;
87     char *src, *dst;
88     SIZE_T bytes_written = 0, bytes_read = 0, i;
89     void *addr1, *addr2;
90     BOOL b;
91     DWORD old_prot;
92     MEMORY_BASIC_INFORMATION info;
93     HANDLE hProcess;
94 
95     /* not exported in all windows-versions  */
96     if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) {
97         win_skip("Virtual{Alloc,Free}Ex not available\n");
98         return;
99     }
100 
101     hProcess = create_target_process("sleep");
102     ok(hProcess != NULL, "Can't start process\n");
103 
104     SetLastError(0xdeadbeef);
105     addr1 = pVirtualAllocEx(hProcess, NULL, alloc_size, MEM_COMMIT,
106                            PAGE_EXECUTE_READWRITE);
107     ok(addr1 != NULL, "VirtualAllocEx error %u\n", GetLastError());
108 
109     src = VirtualAlloc( NULL, alloc_size, MEM_COMMIT, PAGE_READWRITE );
110     dst = VirtualAlloc( NULL, alloc_size, MEM_COMMIT, PAGE_READWRITE );
111     for (i = 0; i < alloc_size; i++)
112         src[i] = i & 0xff;
113 
114     b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
115     ok(b && (bytes_written == alloc_size), "%lu bytes written\n",
116        bytes_written);
117     b = ReadProcessMemory(hProcess, addr1, dst, alloc_size, &bytes_read);
118     ok(b && (bytes_read == alloc_size), "%lu bytes read\n", bytes_read);
119     ok(!memcmp(src, dst, alloc_size), "Data from remote process differs\n");
120 
121     /* test invalid source buffers */
122 
123     b = VirtualProtect( src + 0x2000, 0x2000, PAGE_NOACCESS, &old_prot );
124     ok( b, "VirtualProtect failed error %u\n", GetLastError() );
125     b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
126     ok( !b, "WriteProcessMemory succeeded\n" );
127     ok( GetLastError() == ERROR_NOACCESS ||
128         GetLastError() == ERROR_PARTIAL_COPY, /* vista */
129         "wrong error %u\n", GetLastError() );
130     ok( bytes_written == 0, "%lu bytes written\n", bytes_written );
131     b = ReadProcessMemory(hProcess, addr1, src, alloc_size, &bytes_read);
132     ok( !b, "ReadProcessMemory succeeded\n" );
133     ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
134     ok( bytes_read == 0, "%lu bytes written\n", bytes_read );
135 
136     b = VirtualProtect( src, 0x2000, PAGE_NOACCESS, &old_prot );
137     ok( b, "VirtualProtect failed error %u\n", GetLastError() );
138     b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
139     ok( !b, "WriteProcessMemory succeeded\n" );
140     ok( GetLastError() == ERROR_NOACCESS ||
141         GetLastError() == ERROR_PARTIAL_COPY, /* vista */
142         "wrong error %u\n", GetLastError() );
143     ok( bytes_written == 0, "%lu bytes written\n", bytes_written );
144     b = ReadProcessMemory(hProcess, addr1, src, alloc_size, &bytes_read);
145     ok( !b, "ReadProcessMemory succeeded\n" );
146     ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
147     ok( bytes_read == 0, "%lu bytes written\n", bytes_read );
148 
149     b = pVirtualFreeEx(hProcess, addr1, 0, MEM_RELEASE);
150     ok(b != 0, "VirtualFreeEx, error %u\n", GetLastError());
151 
152     VirtualFree( src, 0, MEM_RELEASE );
153     VirtualFree( dst, 0, MEM_RELEASE );
154 
155     /*
156      * The following tests parallel those in test_VirtualAlloc()
157      */
158 
159     SetLastError(0xdeadbeef);
160     addr1 = pVirtualAllocEx(hProcess, 0, 0, MEM_RESERVE, PAGE_NOACCESS);
161     ok(addr1 == NULL, "VirtualAllocEx should fail on zero-sized allocation\n");
162     ok(GetLastError() == ERROR_INVALID_PARAMETER,
163        "got %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
164 
165     addr1 = pVirtualAllocEx(hProcess, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
166     ok(addr1 != NULL, "VirtualAllocEx failed\n");
167 
168     /* test a not committed memory */
169     memset(&info, 'q', sizeof(info));
170     ok(VirtualQueryEx(hProcess, addr1, &info, sizeof(info)) == sizeof(info), "VirtualQueryEx failed\n");
171     ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
172     ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
173     ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
174     ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
175     ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
176     ok(info.Protect == 0, "%x != PAGE_NOACCESS\n", info.Protect);
177     ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
178 
179     SetLastError(0xdeadbeef);
180     ok(!VirtualProtectEx(hProcess, addr1, 0xFFFC, PAGE_READONLY, &old_prot),
181        "VirtualProtectEx should fail on a not committed memory\n");
182     ok(GetLastError() == ERROR_INVALID_ADDRESS,
183         "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError());
184 
185     addr2 = pVirtualAllocEx(hProcess, addr1, 0x1000, MEM_COMMIT, PAGE_NOACCESS);
186     ok(addr1 == addr2, "VirtualAllocEx failed\n");
187 
188     /* test a committed memory */
189     ok(VirtualQueryEx(hProcess, addr1, &info, sizeof(info)) == sizeof(info),
190         "VirtualQueryEx failed\n");
191     ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
192     ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
193     ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
194     ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize);
195     ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State);
196     /* this time NT reports PAGE_NOACCESS as well */
197     ok(info.Protect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.Protect);
198     ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
199 
200     /* this should fail, since not the whole range is committed yet */
201     SetLastError(0xdeadbeef);
202     ok(!VirtualProtectEx(hProcess, addr1, 0xFFFC, PAGE_READONLY, &old_prot),
203         "VirtualProtectEx should fail on a not committed memory\n");
204     ok(GetLastError() == ERROR_INVALID_ADDRESS,
205        "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError());
206 
207     old_prot = 0;
208     ok(VirtualProtectEx(hProcess, addr1, 0x1000, PAGE_READONLY, &old_prot), "VirtualProtectEx failed\n");
209     ok(old_prot == PAGE_NOACCESS, "wrong old protection: got %04x instead of PAGE_NOACCESS\n", old_prot);
210 
211     old_prot = 0;
212     ok(VirtualProtectEx(hProcess, addr1, 0x1000, PAGE_READWRITE, &old_prot), "VirtualProtectEx failed\n");
213     ok(old_prot == PAGE_READONLY, "wrong old protection: got %04x instead of PAGE_READONLY\n", old_prot);
214 
215     ok(!pVirtualFreeEx(hProcess, addr1, 0x10000, 0),
216        "VirtualFreeEx should fail with type 0\n");
217     ok(GetLastError() == ERROR_INVALID_PARAMETER,
218         "got %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
219 
220     ok(pVirtualFreeEx(hProcess, addr1, 0x10000, MEM_DECOMMIT), "VirtualFreeEx failed\n");
221 
222     /* if the type is MEM_RELEASE, size must be 0 */
223     ok(!pVirtualFreeEx(hProcess, addr1, 1, MEM_RELEASE),
224        "VirtualFreeEx should fail\n");
225     ok(GetLastError() == ERROR_INVALID_PARAMETER,
226         "got %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
227 
228     ok(pVirtualFreeEx(hProcess, addr1, 0, MEM_RELEASE), "VirtualFreeEx failed\n");
229 
230     TerminateProcess(hProcess, 0);
231     CloseHandle(hProcess);
232 }
233 
234 static void test_VirtualAlloc(void)
235 {
236     void *addr1, *addr2;
237     DWORD old_prot;
238     MEMORY_BASIC_INFORMATION info;
239     NTSTATUS status;
240     SIZE_T size;
241 
242     SetLastError(0xdeadbeef);
243     addr1 = VirtualAlloc(0, 0, MEM_RESERVE, PAGE_NOACCESS);
244     ok(addr1 == NULL, "VirtualAlloc should fail on zero-sized allocation\n");
245     ok(GetLastError() == ERROR_INVALID_PARAMETER,
246         "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError());
247 
248     addr1 = VirtualAlloc(0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
249     ok(addr1 != NULL, "VirtualAlloc failed\n");
250 
251     /* test a not committed memory */
252     ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info),
253         "VirtualQuery failed\n");
254     ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
255     ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
256     ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
257     ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
258     ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
259     ok(info.Protect == 0, "%x != PAGE_NOACCESS\n", info.Protect);
260     ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
261 
262     SetLastError(0xdeadbeef);
263     ok(!VirtualProtect(addr1, 0xFFFC, PAGE_READONLY, &old_prot),
264        "VirtualProtect should fail on a not committed memory\n");
265     ok( GetLastError() == ERROR_INVALID_ADDRESS,
266         "got %d, expected ERROR_INVALID_ADDRESS\n", GetLastError());
267 
268     addr2 = VirtualAlloc(addr1, 0x1000, MEM_COMMIT, PAGE_NOACCESS);
269     ok(addr1 == addr2, "VirtualAlloc failed\n");
270 
271     /* test a committed memory */
272     ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info),
273         "VirtualQuery failed\n");
274     ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
275     ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
276     ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
277     ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize);
278     ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State);
279     /* this time NT reports PAGE_NOACCESS as well */
280     ok(info.Protect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.Protect);
281     ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
282 
283     /* this should fail, since not the whole range is committed yet */
284     SetLastError(0xdeadbeef);
285     ok(!VirtualProtect(addr1, 0xFFFC, PAGE_READONLY, &old_prot),
286         "VirtualProtect should fail on a not committed memory\n");
287     ok( GetLastError() == ERROR_INVALID_ADDRESS,
288         "got %d, expected ERROR_INVALID_ADDRESS\n", GetLastError());
289 
290     ok(VirtualProtect(addr1, 0x1000, PAGE_READONLY, &old_prot), "VirtualProtect failed\n");
291     ok(old_prot == PAGE_NOACCESS,
292         "wrong old protection: got %04x instead of PAGE_NOACCESS\n", old_prot);
293 
294     ok(VirtualProtect(addr1, 0x1000, PAGE_READWRITE, &old_prot), "VirtualProtect failed\n");
295     ok(old_prot == PAGE_READONLY,
296         "wrong old protection: got %04x instead of PAGE_READONLY\n", old_prot);
297 
298     ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info),
299         "VirtualQuery failed\n");
300     ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize);
301     ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State);
302     ok(info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect);
303     memset( addr1, 0x55, 20 );
304     ok( *(DWORD *)addr1 == 0x55555555, "wrong data %x\n", *(DWORD *)addr1 );
305 
306     addr2 = VirtualAlloc( addr1, 0x1000, MEM_RESET, PAGE_NOACCESS );
307     ok( addr2 == addr1, "VirtualAlloc failed err %u\n", GetLastError() );
308     ok( *(DWORD *)addr1 == 0x55555555 || *(DWORD *)addr1 == 0, "wrong data %x\n", *(DWORD *)addr1 );
309     ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info),
310        "VirtualQuery failed\n");
311     ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize);
312     ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State);
313     ok(info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect);
314 
315     addr2 = VirtualAlloc( (char *)addr1 + 0x1000, 0x1000, MEM_RESET, PAGE_NOACCESS );
316     ok( (char *)addr2 == (char *)addr1 + 0x1000, "VirtualAlloc failed\n" );
317 
318     ok(VirtualQuery(addr2, &info, sizeof(info)) == sizeof(info),
319        "VirtualQuery failed\n");
320     ok(info.RegionSize == 0xf000, "%lx != 0xf000\n", info.RegionSize);
321     ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
322     ok(info.Protect == 0, "%x != 0\n", info.Protect);
323 
324     addr2 = VirtualAlloc( (char *)addr1 + 0xf000, 0x2000, MEM_RESET, PAGE_NOACCESS );
325     ok( !addr2, "VirtualAlloc failed\n" );
326     ok( GetLastError() == ERROR_INVALID_ADDRESS, "wrong error %u\n", GetLastError() );
327 
328     /* invalid protection values */
329     SetLastError(0xdeadbeef);
330     addr2 = VirtualAlloc(NULL, 0x1000, MEM_RESERVE, 0);
331     ok(!addr2, "VirtualAlloc succeeded\n");
332     ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());
333 
334     SetLastError(0xdeadbeef);
335     addr2 = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, 0);
336     ok(!addr2, "VirtualAlloc succeeded\n");
337     ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());
338 
339     SetLastError(0xdeadbeef);
340     addr2 = VirtualAlloc(addr1, 0x1000, MEM_COMMIT, PAGE_READONLY | PAGE_EXECUTE);
341     ok(!addr2, "VirtualAlloc succeeded\n");
342     ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());
343 
344     SetLastError(0xdeadbeef);
345     ok(!VirtualProtect(addr1, 0x1000, PAGE_READWRITE | PAGE_EXECUTE_WRITECOPY, &old_prot),
346        "VirtualProtect succeeded\n");
347     ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());
348 
349     SetLastError(0xdeadbeef);
350     ok(!VirtualProtect(addr1, 0x1000, 0, &old_prot), "VirtualProtect succeeded\n");
351     ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());
352 
353     SetLastError(0xdeadbeef);
354     ok(!VirtualFree(addr1, 0x10000, 0), "VirtualFree should fail with type 0\n");
355     ok(GetLastError() == ERROR_INVALID_PARAMETER,
356         "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError());
357 
358     SetLastError(0xdeadbeef);
359     ok(!VirtualFree(addr1, 0, MEM_FREE), "VirtualFree should fail with type MEM_FREE\n");
360     ok(GetLastError() == ERROR_INVALID_PARAMETER,
361         "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError());
362 
363     ok(VirtualFree(addr1, 0x10000, MEM_DECOMMIT), "VirtualFree failed\n");
364 
365     /* if the type is MEM_RELEASE, size must be 0 */
366     ok(!VirtualFree(addr1, 1, MEM_RELEASE), "VirtualFree should fail\n");
367     ok(GetLastError() == ERROR_INVALID_PARAMETER,
368         "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError());
369 
370     ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
371 
372     /* memory returned by VirtualAlloc should be aligned to 64k */
373     addr1 = VirtualAlloc(0, 0x2000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
374     ok(addr1 != NULL, "VirtualAlloc failed\n");
375     ok(!((ULONG_PTR)addr1 & 0xffff), "returned memory %p is not aligned to 64k\n", addr1);
376     ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
377     addr2 = VirtualAlloc(addr1, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
378     ok(addr2 == addr1, "VirtualAlloc returned %p, expected %p\n", addr2, addr1);
379 
380     /* allocation conflicts because of 64k align */
381     size = 0x1000;
382     addr2 = (char *)addr1 + 0x1000;
383     status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 0, &size,
384                                       MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
385     ok(status == STATUS_CONFLICTING_ADDRESSES, "NtAllocateVirtualMemory returned %08x\n", status);
386 
387     /* it should conflict, even when zero_bits is explicitly set */
388     size = 0x1000;
389     addr2 = (char *)addr1 + 0x1000;
390     status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 12, &size,
391                                       MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
392     todo_wine
393     ok(status == STATUS_CONFLICTING_ADDRESSES, "NtAllocateVirtualMemory returned %08x\n", status);
394     if (status == STATUS_SUCCESS) ok(VirtualFree(addr2, 0, MEM_RELEASE), "VirtualFree failed\n");
395 
396     /* 21 zero bits is valid */
397     size = 0x1000;
398     addr2 = NULL;
399     status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 21, &size,
400                                       MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
401     ok(status == STATUS_SUCCESS || status == STATUS_NO_MEMORY,
402        "NtAllocateVirtualMemory returned %08x\n", status);
403     if (status == STATUS_SUCCESS) ok(VirtualFree(addr2, 0, MEM_RELEASE), "VirtualFree failed\n");
404 
405     /* 22 zero bits is invalid */
406     size = 0x1000;
407     addr2 = NULL;
408     status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 22, &size,
409                                       MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
410     ok(status == STATUS_INVALID_PARAMETER_3, "NtAllocateVirtualMemory returned %08x\n", status);
411     if (status == STATUS_SUCCESS) ok(VirtualFree(addr2, 0, MEM_RELEASE), "VirtualFree failed\n");
412 
413     /* AT_ROUND_TO_PAGE flag is not supported for VirtualAlloc */
414     SetLastError(0xdeadbeef);
415     addr2 = VirtualAlloc(addr1, 0x1000, MEM_RESERVE | MEM_COMMIT | AT_ROUND_TO_PAGE, PAGE_EXECUTE_READWRITE);
416     ok(!addr2, "VirtualAlloc unexpectedly succeeded\n");
417     ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError());
418 
419     /* AT_ROUND_TO_PAGE flag is not supported for NtAllocateVirtualMemory */
420     size = 0x1000;
421     addr2 = (char *)addr1 + 0x1000;
422     status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 0, &size, MEM_RESERVE |
423                                       MEM_COMMIT | AT_ROUND_TO_PAGE, PAGE_EXECUTE_READWRITE);
424     todo_wine
425     ok(status == STATUS_INVALID_PARAMETER_5, "NtAllocateVirtualMemory returned %08x\n", status);
426 
427     ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
428 }
429 
430 static void test_MapViewOfFile(void)
431 {
432     static const char testfile[] = "testfile.xxx";
433     const char *name;
434     HANDLE file, mapping, map2;
435     void *ptr, *ptr2, *addr;
436     SECTION_BASIC_INFORMATION section_info;
437     SECTION_IMAGE_INFORMATION image_info;
438     MEMORY_BASIC_INFORMATION info;
439     BOOL ret;
440     SIZE_T size;
441     NTSTATUS status;
442     ULONG info_size;
443     LARGE_INTEGER map_size;
444 
445     SetLastError(0xdeadbeef);
446     file = CreateFileA( testfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 );
447     ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() );
448     SetFilePointer( file, 12288, NULL, FILE_BEGIN );
449     SetEndOfFile( file );
450 
451     /* read/write mapping */
452 
453     SetLastError(0xdeadbeef);
454     mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
455     ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() );
456 
457     SetLastError(0xdeadbeef);
458     ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
459     ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
460     UnmapViewOfFile( ptr );
461 
462     SetLastError(0xdeadbeef);
463     ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 );
464     ok( ptr != NULL, "MapViewOfFile FILE_MAP_COPY error %u\n", GetLastError() );
465     UnmapViewOfFile( ptr );
466 
467     SetLastError(0xdeadbeef);
468     ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 );
469     ok( ptr != NULL, "MapViewOfFile 0 error %u\n", GetLastError() );
470     UnmapViewOfFile( ptr );
471 
472     SetLastError(0xdeadbeef);
473     ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 );
474     ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() );
475     UnmapViewOfFile( ptr );
476 
477     ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2,
478                            FILE_MAP_READ|FILE_MAP_WRITE, FALSE, 0 );
479     ok( ret, "DuplicateHandle failed error %u\n", GetLastError());
480     ptr = MapViewOfFile( map2, FILE_MAP_WRITE, 0, 0, 4096 );
481     ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() );
482     UnmapViewOfFile( ptr );
483     CloseHandle( map2 );
484 
485     ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2,
486                            FILE_MAP_READ, FALSE, 0 );
487     ok( ret, "DuplicateHandle failed error %u\n", GetLastError());
488     SetLastError(0xdeadbeef);
489     ptr = MapViewOfFile( map2, FILE_MAP_WRITE, 0, 0, 4096 );
490     ok( !ptr, "MapViewOfFile succeeded\n" );
491     ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
492     CloseHandle( map2 );
493     ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2, 0, FALSE, 0 );
494     ok( ret, "DuplicateHandle failed error %u\n", GetLastError());
495     SetLastError(0xdeadbeef);
496     ptr = MapViewOfFile( map2, 0, 0, 0, 4096 );
497     ok( !ptr, "MapViewOfFile succeeded\n" );
498     ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
499     CloseHandle( map2 );
500     ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2,
501                            FILE_MAP_READ, FALSE, 0 );
502     ok( ret, "DuplicateHandle failed error %u\n", GetLastError());
503     ptr = MapViewOfFile( map2, 0, 0, 0, 4096 );
504     ok( ptr != NULL, "MapViewOfFile NO_ACCESS error %u\n", GetLastError() );
505 
506     UnmapViewOfFile( ptr );
507     CloseHandle( map2 );
508     CloseHandle( mapping );
509 
510     /* read-only mapping */
511 
512     SetLastError(0xdeadbeef);
513     mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL );
514     ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() );
515 
516     SetLastError(0xdeadbeef);
517     ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
518     ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
519     UnmapViewOfFile( ptr );
520 
521     SetLastError(0xdeadbeef);
522     ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 );
523     ok( ptr != NULL, "MapViewOfFile FILE_MAP_COPY error %u\n", GetLastError() );
524     UnmapViewOfFile( ptr );
525 
526     SetLastError(0xdeadbeef);
527     ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 );
528     ok( ptr != NULL, "MapViewOfFile 0 error %u\n", GetLastError() );
529     UnmapViewOfFile( ptr );
530 
531     SetLastError(0xdeadbeef);
532     ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 );
533     ok( !ptr, "MapViewOfFile FILE_MAP_WRITE succeeded\n" );
534     ok( GetLastError() == ERROR_INVALID_PARAMETER ||
535         GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
536     CloseHandle( mapping );
537 
538     /* copy-on-write mapping */
539 
540     SetLastError(0xdeadbeef);
541     mapping = CreateFileMappingA( file, NULL, PAGE_WRITECOPY, 0, 4096, NULL );
542     ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() );
543 
544     SetLastError(0xdeadbeef);
545     ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
546     ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
547     UnmapViewOfFile( ptr );
548 
549     SetLastError(0xdeadbeef);
550     ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 );
551     ok( ptr != NULL, "MapViewOfFile FILE_MAP_COPY error %u\n", GetLastError() );
552     UnmapViewOfFile( ptr );
553 
554     SetLastError(0xdeadbeef);
555     ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 );
556     ok( ptr != NULL, "MapViewOfFile 0 error %u\n", GetLastError() );
557     UnmapViewOfFile( ptr );
558 
559     SetLastError(0xdeadbeef);
560     ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 );
561     ok( !ptr, "MapViewOfFile FILE_MAP_WRITE succeeded\n" );
562     ok( GetLastError() == ERROR_INVALID_PARAMETER ||
563         GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
564     CloseHandle( mapping );
565 
566     /* no access mapping */
567 
568     SetLastError(0xdeadbeef);
569     mapping = CreateFileMappingA( file, NULL, PAGE_NOACCESS, 0, 4096, NULL );
570     ok( !mapping, "CreateFileMappingA succeeded\n" );
571     ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %d\n", GetLastError() );
572     CloseHandle( file );
573 
574     /* now try read-only file */
575 
576     SetLastError(0xdeadbeef);
577     file = CreateFileA( testfile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0 );
578     ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() );
579 
580     SetLastError(0xdeadbeef);
581     mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
582     ok( !mapping, "CreateFileMapping PAGE_READWRITE succeeded\n" );
583     ok( GetLastError() == ERROR_INVALID_PARAMETER ||
584         GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
585 
586     SetLastError(0xdeadbeef);
587     mapping = CreateFileMappingA( file, NULL, PAGE_WRITECOPY, 0, 4096, NULL );
588     ok( mapping != 0, "CreateFileMapping PAGE_WRITECOPY error %u\n", GetLastError() );
589     CloseHandle( mapping );
590 
591     SetLastError(0xdeadbeef);
592     mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL );
593     ok( mapping != 0, "CreateFileMapping PAGE_READONLY error %u\n", GetLastError() );
594     CloseHandle( mapping );
595     CloseHandle( file );
596 
597     /* now try no access file */
598 
599     SetLastError(0xdeadbeef);
600     file = CreateFileA( testfile, 0, 0, NULL, OPEN_EXISTING, 0, 0 );
601     ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() );
602 
603     SetLastError(0xdeadbeef);
604     mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
605     ok( !mapping, "CreateFileMapping PAGE_READWRITE succeeded\n" );
606     ok( GetLastError() == ERROR_INVALID_PARAMETER ||
607         GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
608 
609     SetLastError(0xdeadbeef);
610     mapping = CreateFileMappingA( file, NULL, PAGE_WRITECOPY, 0, 4096, NULL );
611     ok( !mapping, "CreateFileMapping PAGE_WRITECOPY succeeded\n" );
612     ok( GetLastError() == ERROR_INVALID_PARAMETER ||
613         GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
614 
615     SetLastError(0xdeadbeef);
616     mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL );
617     ok( !mapping, "CreateFileMapping PAGE_READONLY succeeded\n" );
618     ok( GetLastError() == ERROR_INVALID_PARAMETER ||
619         GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
620 
621     CloseHandle( file );
622     DeleteFileA( testfile );
623 
624     SetLastError(0xdeadbeef);
625     name = "Local\\Foo";
626     file = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4090, name );
627     /* nt4 doesn't have Local\\ */
628     if (!file && GetLastError() == ERROR_PATH_NOT_FOUND)
629     {
630         name = "Foo";
631         file = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4090, name );
632     }
633     ok( file != 0, "CreateFileMapping PAGE_READWRITE error %u\n", GetLastError() );
634 
635     SetLastError(0xdeadbeef);
636     mapping = OpenFileMappingA( FILE_MAP_READ, FALSE, name );
637     ok( mapping != 0, "OpenFileMapping FILE_MAP_READ error %u\n", GetLastError() );
638     SetLastError(0xdeadbeef);
639     ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 );
640     ok( !ptr, "MapViewOfFile FILE_MAP_WRITE succeeded\n" );
641     ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
642     SetLastError(0xdeadbeef);
643     ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
644     ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
645     SetLastError(0xdeadbeef);
646     size = VirtualQuery( ptr, &info, sizeof(info) );
647     ok( size == sizeof(info),
648         "VirtualQuery error %u\n", GetLastError() );
649     ok( info.BaseAddress == ptr, "%p != %p\n", info.BaseAddress, ptr );
650     ok( info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr );
651     ok( info.AllocationProtect == PAGE_READONLY, "%x != PAGE_READONLY\n", info.AllocationProtect );
652     ok( info.RegionSize == 4096, "%lx != 4096\n", info.RegionSize );
653     ok( info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State );
654     ok( info.Protect == PAGE_READONLY, "%x != PAGE_READONLY\n", info.Protect );
655     UnmapViewOfFile( ptr );
656     status = pNtQuerySection( mapping, SectionBasicInformation, &section_info,
657                               sizeof(section_info), &info_size );
658     ok( status == STATUS_ACCESS_DENIED, "NtQuerySection failed err %x\n", status );
659     CloseHandle( mapping );
660     mapping = OpenFileMappingA( FILE_MAP_READ | SECTION_QUERY, FALSE, name );
661     ok( mapping != 0, "OpenFileMapping FILE_MAP_READ error %u\n", GetLastError() );
662     status = pNtQuerySection( mapping, SectionBasicInformation, &section_info,
663                               sizeof(section_info), &info_size );
664     ok( !status, "NtQuerySection failed err %x\n", status );
665     ok( info_size == sizeof(section_info), "NtQuerySection wrong size %u\n", info_size );
666     ok( section_info.Attributes == SEC_COMMIT, "NtQuerySection wrong attr %08x\n",
667         section_info.Attributes );
668     ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress );
669     ok( section_info.Size.QuadPart == info.RegionSize, "NtQuerySection wrong size %x%08x / %08lx\n",
670         section_info.Size.u.HighPart, section_info.Size.u.LowPart, info.RegionSize );
671     CloseHandle( mapping );
672 
673     SetLastError(0xdeadbeef);
674     mapping = OpenFileMappingA( FILE_MAP_WRITE, FALSE, name );
675     ok( mapping != 0, "OpenFileMapping FILE_MAP_WRITE error %u\n", GetLastError() );
676     SetLastError(0xdeadbeef);
677     ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
678     ok( !ptr, "MapViewOfFile succeeded\n" );
679     ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
680     SetLastError(0xdeadbeef);
681     ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 );
682     ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() );
683     SetLastError(0xdeadbeef);
684     size = VirtualQuery( ptr, &info, sizeof(info) );
685     ok( size == sizeof(info),
686         "VirtualQuery error %u\n", GetLastError() );
687     ok( info.BaseAddress == ptr, "%p != %p\n", info.BaseAddress, ptr );
688     ok( info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr );
689     ok( info.AllocationProtect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.AllocationProtect );
690     ok( info.RegionSize == 4096, "%lx != 4096\n", info.RegionSize );
691     ok( info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State );
692     ok( info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect );
693     UnmapViewOfFile( ptr );
694     status = pNtQuerySection( mapping, SectionBasicInformation, &section_info,
695                               sizeof(section_info), &info_size );
696     ok( status == STATUS_ACCESS_DENIED, "NtQuerySection failed err %x\n", status );
697     CloseHandle( mapping );
698 
699     mapping = OpenFileMappingA( FILE_MAP_WRITE | SECTION_QUERY, FALSE, name );
700     ok( mapping != 0, "OpenFileMapping FILE_MAP_WRITE error %u\n", GetLastError() );
701     status = pNtQuerySection( mapping, SectionBasicInformation, &section_info,
702                               sizeof(section_info), &info_size );
703     ok( !status, "NtQuerySection failed err %x\n", status );
704     ok( info_size == sizeof(section_info), "NtQuerySection wrong size %u\n", info_size );
705     ok( section_info.Attributes == SEC_COMMIT, "NtQuerySection wrong attr %08x\n",
706         section_info.Attributes );
707     ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress );
708     ok( section_info.Size.QuadPart == info.RegionSize, "NtQuerySection wrong size %x%08x / %08lx\n",
709         section_info.Size.u.HighPart, section_info.Size.u.LowPart, info.RegionSize );
710     CloseHandle( mapping );
711 
712     CloseHandle( file );
713 
714     /* read/write mapping with SEC_RESERVE */
715     mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_RESERVE, 0, MAPPING_SIZE, NULL);
716     ok(mapping != INVALID_HANDLE_VALUE, "CreateFileMappingA failed with error %d\n", GetLastError());
717     status = pNtQuerySection( mapping, SectionBasicInformation, &section_info,
718                               sizeof(section_info), NULL );
719     ok( !status, "NtQuerySection failed err %x\n", status );
720     ok( section_info.Attributes == SEC_RESERVE, "NtQuerySection wrong attr %08x\n",
721         section_info.Attributes );
722     ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress );
723     ok( section_info.Size.QuadPart == MAPPING_SIZE, "NtQuerySection wrong size %x%08x / %08x\n",
724         section_info.Size.u.HighPart, section_info.Size.u.LowPart, MAPPING_SIZE );
725 
726     ptr = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
727     ok(ptr != NULL, "MapViewOfFile failed with error %d\n", GetLastError());
728 
729     ptr2 = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
730     ok( ptr2 != NULL, "MapViewOfFile failed with error %d\n", GetLastError());
731     ok( ptr != ptr2, "MapViewOfFile returned same pointer\n" );
732 
733     ret = VirtualQuery(ptr, &info, sizeof(info));
734     ok(ret, "VirtualQuery failed with error %d\n", GetLastError());
735     ok(info.BaseAddress == ptr, "BaseAddress should have been %p but was %p instead\n", ptr, info.BaseAddress);
736     ok(info.AllocationBase == ptr, "AllocationBase should have been %p but was %p instead\n", ptr, info.AllocationBase);
737     ok(info.RegionSize == MAPPING_SIZE, "RegionSize should have been 0x%x but was 0x%lx\n", MAPPING_SIZE, info.RegionSize);
738     ok(info.State == MEM_RESERVE, "State should have been MEM_RESERVE instead of 0x%x\n", info.State);
739     ok(info.AllocationProtect == PAGE_READWRITE,
740        "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect);
741     ok(info.Protect == 0, "Protect should have been 0 instead of 0x%x\n", info.Protect);
742     ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type);
743 
744     ret = VirtualQuery(ptr2, &info, sizeof(info));
745     ok(ret, "VirtualQuery failed with error %d\n", GetLastError());
746     ok(info.BaseAddress == ptr2,
747        "BaseAddress should have been %p but was %p instead\n", ptr2, info.BaseAddress);
748     ok(info.AllocationBase == ptr2,
749        "AllocationBase should have been %p but was %p instead\n", ptr2, info.AllocationBase);
750     ok(info.AllocationProtect == PAGE_READWRITE,
751        "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect);
752     ok(info.RegionSize == MAPPING_SIZE,
753        "RegionSize should have been 0x%x but was 0x%lx\n", MAPPING_SIZE, info.RegionSize);
754     ok(info.State == MEM_RESERVE, "State should have been MEM_RESERVE instead of 0x%x\n", info.State);
755     ok(info.Protect == 0, "Protect should have been 0 instead of 0x%x\n", info.Protect);
756     ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type);
757 
758     ptr = VirtualAlloc(ptr, 0x10000, MEM_COMMIT, PAGE_READONLY);
759     ok(ptr != NULL, "VirtualAlloc failed with error %d\n", GetLastError());
760 
761     ret = VirtualQuery(ptr, &info, sizeof(info));
762     ok(ret, "VirtualQuery failed with error %d\n", GetLastError());
763     ok(info.BaseAddress == ptr, "BaseAddress should have been %p but was %p instead\n", ptr, info.BaseAddress);
764     ok(info.AllocationBase == ptr, "AllocationBase should have been %p but was %p instead\n", ptr, info.AllocationBase);
765     ok(info.RegionSize == 0x10000, "RegionSize should have been 0x10000 but was 0x%lx\n", info.RegionSize);
766     ok(info.State == MEM_COMMIT, "State should have been MEM_COMMIT instead of 0x%x\n", info.State);
767     ok(info.Protect == PAGE_READONLY, "Protect should have been PAGE_READONLY instead of 0x%x\n", info.Protect);
768     ok(info.AllocationProtect == PAGE_READWRITE,
769        "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect);
770     ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type);
771 
772     /* shows that the VirtualAlloc above affects the mapping, not just the
773      * virtual memory in this process - it also affects all other processes
774      * with a view of the mapping, but that isn't tested here */
775     ret = VirtualQuery(ptr2, &info, sizeof(info));
776     ok(ret, "VirtualQuery failed with error %d\n", GetLastError());
777     ok(info.BaseAddress == ptr2,
778        "BaseAddress should have been %p but was %p instead\n", ptr2, info.BaseAddress);
779     ok(info.AllocationBase == ptr2,
780        "AllocationBase should have been %p but was %p instead\n", ptr2, info.AllocationBase);
781     ok(info.AllocationProtect == PAGE_READWRITE,
782        "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect);
783     ok(info.RegionSize == 0x10000,
784        "RegionSize should have been 0x10000 but was 0x%lx\n", info.RegionSize);
785     ok(info.State == MEM_COMMIT,
786        "State should have been MEM_COMMIT instead of 0x%x\n", info.State);
787     ok(info.Protect == PAGE_READWRITE,
788        "Protect should have been PAGE_READWRITE instead of 0x%x\n", info.Protect);
789     ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type);
790 
791     addr = VirtualAlloc( ptr, MAPPING_SIZE, MEM_RESET, PAGE_READONLY );
792     ok( addr == ptr, "VirtualAlloc failed with error %u\n", GetLastError() );
793 
794     ret = VirtualFree( ptr, 0x10000, MEM_DECOMMIT );
795     ok( !ret, "VirtualFree succeeded\n" );
796     ok( GetLastError() == ERROR_INVALID_PARAMETER, "VirtualFree failed with %u\n", GetLastError() );
797 
798     ret = UnmapViewOfFile(ptr2);
799     ok(ret, "UnmapViewOfFile failed with error %d\n", GetLastError());
800     ret = UnmapViewOfFile(ptr);
801     ok(ret, "UnmapViewOfFile failed with error %d\n", GetLastError());
802     CloseHandle(mapping);
803 
804     addr = VirtualAlloc(NULL, 0x10000, MEM_COMMIT, PAGE_READONLY );
805     ok( addr != NULL, "VirtualAlloc failed with error %u\n", GetLastError() );
806 
807     SetLastError(0xdeadbeef);
808     ok( !UnmapViewOfFile(addr), "UnmapViewOfFile should fail on VirtualAlloc mem\n" );
809     ok( GetLastError() == ERROR_INVALID_ADDRESS,
810         "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError());
811     SetLastError(0xdeadbeef);
812     ok( !UnmapViewOfFile((char *)addr + 0x3000), "UnmapViewOfFile should fail on VirtualAlloc mem\n" );
813     ok( GetLastError() == ERROR_INVALID_ADDRESS,
814         "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError());
815     SetLastError(0xdeadbeef);
816     ok( !UnmapViewOfFile((void *)0xdeadbeef), "UnmapViewOfFile should fail on VirtualAlloc mem\n" );
817     ok( GetLastError() == ERROR_INVALID_ADDRESS,
818        "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError());
819 
820     ok( VirtualFree(addr, 0, MEM_RELEASE), "VirtualFree failed\n" );
821 
822     /* close named mapping handle without unmapping */
823     name = "Foo";
824     SetLastError(0xdeadbeef);
825     mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MAPPING_SIZE, name);
826     ok( mapping != 0, "CreateFileMappingA failed with error %d\n", GetLastError() );
827     SetLastError(0xdeadbeef);
828     ptr = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
829     ok( ptr != NULL, "MapViewOfFile failed with error %d\n", GetLastError() );
830     SetLastError(0xdeadbeef);
831     map2 = OpenFileMappingA(FILE_MAP_READ, FALSE, name);
832     ok( map2 != 0, "OpenFileMappingA failed with error %d\n", GetLastError() );
833     SetLastError(0xdeadbeef);
834     ret = CloseHandle(map2);
835     ok(ret, "CloseHandle error %d\n", GetLastError());
836     SetLastError(0xdeadbeef);
837     ret = CloseHandle(mapping);
838     ok(ret, "CloseHandle error %d\n", GetLastError());
839 
840     ret = IsBadReadPtr(ptr, MAPPING_SIZE);
841     ok( !ret, "memory is not accessible\n" );
842 
843     ret = VirtualQuery(ptr, &info, sizeof(info));
844     ok(ret, "VirtualQuery error %d\n", GetLastError());
845     ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr);
846     ok(info.RegionSize == MAPPING_SIZE, "got %#lx != expected %#x\n", info.RegionSize, MAPPING_SIZE);
847     ok(info.Protect == PAGE_READWRITE, "got %#x != expected PAGE_READWRITE\n", info.Protect);
848     ok(info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr);
849     ok(info.AllocationProtect == PAGE_READWRITE, "%#x != PAGE_READWRITE\n", info.AllocationProtect);
850     ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
851     ok(info.Type == MEM_MAPPED, "%#x != MEM_MAPPED\n", info.Type);
852 
853     SetLastError(0xdeadbeef);
854     map2 = OpenFileMappingA(FILE_MAP_READ, FALSE, name);
855     todo_wine
856     ok( map2 == 0, "OpenFileMappingA succeeded\n" );
857     todo_wine
858     ok( GetLastError() == ERROR_FILE_NOT_FOUND, "OpenFileMappingA set error %d\n", GetLastError() );
859     if (map2) CloseHandle(map2); /* FIXME: remove once Wine is fixed */
860     SetLastError(0xdeadbeef);
861     mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MAPPING_SIZE, name);
862     ok( mapping != 0, "CreateFileMappingA failed\n" );
863     todo_wine
864     ok( GetLastError() == ERROR_SUCCESS, "CreateFileMappingA set error %d\n", GetLastError() );
865     SetLastError(0xdeadbeef);
866     ret = CloseHandle(mapping);
867     ok(ret, "CloseHandle error %d\n", GetLastError());
868 
869     ret = IsBadReadPtr(ptr, MAPPING_SIZE);
870     ok( !ret, "memory is not accessible\n" );
871 
872     ret = VirtualQuery(ptr, &info, sizeof(info));
873     ok(ret, "VirtualQuery error %d\n", GetLastError());
874     ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr);
875     ok(info.RegionSize == MAPPING_SIZE, "got %#lx != expected %#x\n", info.RegionSize, MAPPING_SIZE);
876     ok(info.Protect == PAGE_READWRITE, "got %#x != expected PAGE_READWRITE\n", info.Protect);
877     ok(info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr);
878     ok(info.AllocationProtect == PAGE_READWRITE, "%#x != PAGE_READWRITE\n", info.AllocationProtect);
879     ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
880     ok(info.Type == MEM_MAPPED, "%#x != MEM_MAPPED\n", info.Type);
881 
882     SetLastError(0xdeadbeef);
883     ret = UnmapViewOfFile(ptr);
884     ok( ret, "UnmapViewOfFile failed with error %d\n", GetLastError() );
885 
886     ret = IsBadReadPtr(ptr, MAPPING_SIZE);
887     ok( ret, "memory is accessible\n" );
888 
889     ret = VirtualQuery(ptr, &info, sizeof(info));
890     ok(ret, "VirtualQuery error %d\n", GetLastError());
891     ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr);
892     ok(info.Protect == PAGE_NOACCESS, "got %#x != expected PAGE_NOACCESS\n", info.Protect);
893     ok(info.AllocationBase == NULL, "%p != NULL\n", info.AllocationBase);
894     ok(info.AllocationProtect == 0, "%#x != 0\n", info.AllocationProtect);
895     ok(info.State == MEM_FREE, "%#x != MEM_FREE\n", info.State);
896     ok(info.Type == 0, "%#x != 0\n", info.Type);
897 
898     SetLastError(0xdeadbeef);
899     file = CreateFileA(testfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
900     ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() );
901     SetFilePointer(file, 4096, NULL, FILE_BEGIN);
902     SetEndOfFile(file);
903 
904     SetLastError(0xdeadbeef);
905     mapping = CreateFileMappingA(file, NULL, PAGE_READWRITE, 0, MAPPING_SIZE, name);
906     ok( mapping != 0, "CreateFileMappingA failed with error %d\n", GetLastError() );
907     SetLastError(0xdeadbeef);
908     ptr = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
909     ok( ptr != NULL, "MapViewOfFile failed with error %d\n", GetLastError() );
910     SetLastError(0xdeadbeef);
911     map2 = OpenFileMappingA(FILE_MAP_READ, FALSE, name);
912     ok( map2 != 0, "OpenFileMappingA failed with error %d\n", GetLastError() );
913     SetLastError(0xdeadbeef);
914     ret = CloseHandle(map2);
915     ok(ret, "CloseHandle error %d\n", GetLastError());
916     status = pNtQuerySection( mapping, SectionBasicInformation, &section_info,
917                               sizeof(section_info), &info_size );
918     ok( !status, "NtQuerySection failed err %x\n", status );
919     ok( info_size == sizeof(section_info), "NtQuerySection wrong size %u\n", info_size );
920     ok( section_info.Attributes == SEC_FILE, "NtQuerySection wrong attr %08x\n",
921         section_info.Attributes );
922     ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress );
923     ok( section_info.Size.QuadPart == MAPPING_SIZE, "NtQuerySection wrong size %x%08x\n",
924         section_info.Size.u.HighPart, section_info.Size.u.LowPart );
925     SetLastError(0xdeadbeef);
926     ret = CloseHandle(mapping);
927     ok(ret, "CloseHandle error %d\n", GetLastError());
928 
929     ret = IsBadReadPtr(ptr, MAPPING_SIZE);
930     ok( !ret, "memory is not accessible\n" );
931 
932     ret = VirtualQuery(ptr, &info, sizeof(info));
933     ok(ret, "VirtualQuery error %d\n", GetLastError());
934     ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr);
935     ok(info.RegionSize == MAPPING_SIZE, "got %#lx != expected %#x\n", info.RegionSize, MAPPING_SIZE);
936     ok(info.Protect == PAGE_READWRITE, "got %#x != expected PAGE_READWRITE\n", info.Protect);
937     ok(info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr);
938     ok(info.AllocationProtect == PAGE_READWRITE, "%#x != PAGE_READWRITE\n", info.AllocationProtect);
939     ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
940     ok(info.Type == MEM_MAPPED, "%#x != MEM_MAPPED\n", info.Type);
941 
942     SetLastError(0xdeadbeef);
943     map2 = OpenFileMappingA(FILE_MAP_READ, FALSE, name);
944     todo_wine
945     ok( map2 == 0, "OpenFileMappingA succeeded\n" );
946     todo_wine
947     ok( GetLastError() == ERROR_FILE_NOT_FOUND, "OpenFileMappingA set error %d\n", GetLastError() );
948     CloseHandle(map2);
949     SetLastError(0xdeadbeef);
950     mapping = CreateFileMappingA(file, NULL, PAGE_READWRITE, 0, MAPPING_SIZE, name);
951     ok( mapping != 0, "CreateFileMappingA failed\n" );
952     todo_wine
953     ok( GetLastError() == ERROR_SUCCESS, "CreateFileMappingA set error %d\n", GetLastError() );
954     SetLastError(0xdeadbeef);
955     ret = CloseHandle(mapping);
956     ok(ret, "CloseHandle error %d\n", GetLastError());
957 
958     ret = IsBadReadPtr(ptr, MAPPING_SIZE);
959     ok( !ret, "memory is not accessible\n" );
960 
961     ret = VirtualQuery(ptr, &info, sizeof(info));
962     ok(ret, "VirtualQuery error %d\n", GetLastError());
963     ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr);
964     ok(info.RegionSize == MAPPING_SIZE, "got %#lx != expected %#x\n", info.RegionSize, MAPPING_SIZE);
965     ok(info.Protect == PAGE_READWRITE, "got %#x != expected PAGE_READWRITE\n", info.Protect);
966     ok(info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr);
967     ok(info.AllocationProtect == PAGE_READWRITE, "%#x != PAGE_READWRITE\n", info.AllocationProtect);
968     ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
969     ok(info.Type == MEM_MAPPED, "%#x != MEM_MAPPED\n", info.Type);
970 
971     SetLastError(0xdeadbeef);
972     ret = UnmapViewOfFile(ptr);
973     ok( ret, "UnmapViewOfFile failed with error %d\n", GetLastError() );
974 
975     ret = IsBadReadPtr(ptr, MAPPING_SIZE);
976     ok( ret, "memory is accessible\n" );
977 
978     ret = VirtualQuery(ptr, &info, sizeof(info));
979     ok(ret, "VirtualQuery error %d\n", GetLastError());
980     ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr);
981     ok(info.Protect == PAGE_NOACCESS, "got %#x != expected PAGE_NOACCESS\n", info.Protect);
982     ok(info.AllocationBase == NULL, "%p != NULL\n", info.AllocationBase);
983     ok(info.AllocationProtect == 0, "%#x != 0\n", info.AllocationProtect);
984     ok(info.State == MEM_FREE, "%#x != MEM_FREE\n", info.State);
985     ok(info.Type == 0, "%#x != 0\n", info.Type);
986 
987     mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 12288, NULL );
988     ok( mapping != NULL, "CreateFileMappingA failed with error %u\n", GetLastError() );
989 
990     ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 12288 );
991     ok( ptr != NULL, "MapViewOfFile failed with error %u\n", GetLastError() );
992 
993     ret = UnmapViewOfFile( (char *)ptr + 100 );
994     ok( ret, "UnmapViewOfFile failed with error %u\n", GetLastError() );
995 
996     ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 12288 );
997     ok( ptr != NULL, "MapViewOfFile failed with error %u\n", GetLastError() );
998 
999     ret = UnmapViewOfFile( (char *)ptr + 4096 );
1000     ok( ret, "UnmapViewOfFile failed with error %u\n", GetLastError() );
1001 
1002     ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 12288 );
1003     ok( ptr != NULL, "MapViewOfFile failed with error %u\n", GetLastError() );
1004 
1005     ret = UnmapViewOfFile( (char *)ptr + 4096 + 100 );
1006     ok( ret, "UnmapViewOfFile failed with error %u\n", GetLastError() );
1007 
1008     CloseHandle(mapping);
1009 
1010     mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 36, NULL );
1011     ok( mapping != NULL, "CreateFileMappingA failed with error %u\n", GetLastError() );
1012     status = pNtQuerySection( mapping, SectionBasicInformation, &section_info,
1013                               sizeof(section_info), &info_size );
1014     ok( !status, "NtQuerySection failed err %x\n", status );
1015     ok( info_size == sizeof(section_info), "NtQuerySection wrong size %u\n", info_size );
1016     ok( section_info.Attributes == SEC_FILE, "NtQuerySection wrong attr %08x\n",
1017         section_info.Attributes );
1018     ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress );
1019     ok( section_info.Size.QuadPart == 36, "NtQuerySection wrong size %x%08x\n",
1020         section_info.Size.u.HighPart, section_info.Size.u.LowPart );
1021     CloseHandle(mapping);
1022 
1023     SetFilePointer(file, 0x3456, NULL, FILE_BEGIN);
1024     SetEndOfFile(file);
1025     mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 0, NULL );
1026     ok( mapping != NULL, "CreateFileMappingA failed with error %u\n", GetLastError() );
1027     status = pNtQuerySection( mapping, SectionBasicInformation, &section_info,
1028                               sizeof(section_info), &info_size );
1029     ok( !status, "NtQuerySection failed err %x\n", status );
1030     ok( info_size == sizeof(section_info), "NtQuerySection wrong size %u\n", info_size );
1031     ok( section_info.Attributes == SEC_FILE, "NtQuerySection wrong attr %08x\n",
1032         section_info.Attributes );
1033     ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress );
1034     ok( section_info.Size.QuadPart == 0x3456, "NtQuerySection wrong size %x%08x\n",
1035         section_info.Size.u.HighPart, section_info.Size.u.LowPart );
1036     CloseHandle(mapping);
1037 
1038     map_size.QuadPart = 0x3457;
1039     status = pNtCreateSection( &mapping, SECTION_QUERY | SECTION_MAP_READ, NULL,
1040                                &map_size, PAGE_READONLY, SEC_COMMIT, file );
1041     ok( status == STATUS_SECTION_TOO_BIG, "NtCreateSection failed %x\n", status );
1042     status = pNtCreateSection( &mapping, SECTION_QUERY | SECTION_MAP_READ, NULL,
1043                                &map_size, PAGE_READONLY, SEC_IMAGE, file );
1044     ok( status == STATUS_INVALID_IMAGE_NOT_MZ, "NtCreateSection failed %x\n", status );
1045     if (!status) CloseHandle( mapping );
1046     map_size.QuadPart = 0x3452;
1047     status = pNtCreateSection( &mapping, SECTION_QUERY | SECTION_MAP_READ, NULL,
1048                                &map_size, PAGE_READONLY, SEC_COMMIT, file );
1049     ok( !status, "NtCreateSection failed %x\n", status );
1050     status = pNtQuerySection( mapping, SectionBasicInformation, &section_info, sizeof(section_info), NULL );
1051     ok( !status, "NtQuerySection failed err %x\n", status );
1052     ok( section_info.Attributes == SEC_FILE, "NtQuerySection wrong attr %08x\n",
1053         section_info.Attributes );
1054     ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress );
1055     ok( section_info.Size.QuadPart == 0x3452, "NtQuerySection wrong size %x%08x\n",
1056         section_info.Size.u.HighPart, section_info.Size.u.LowPart );
1057     size = map_size.QuadPart;
1058     status = pNtMapViewOfSection( mapping, GetCurrentProcess(), &ptr, 0, 0, NULL,
1059                                   &size, ViewShare, 0, PAGE_READONLY );
1060     ok( !status, "NtMapViewOfSection failed err %x\n", status );
1061     pNtUnmapViewOfSection( GetCurrentProcess(), ptr );
1062     size = map_size.QuadPart + 1;
1063     status = pNtMapViewOfSection( mapping, GetCurrentProcess(), &ptr, 0, 0, NULL,
1064                                   &size, ViewShare, 0, PAGE_READONLY );
1065     ok( status == STATUS_INVALID_VIEW_SIZE, "NtMapViewOfSection failed err %x\n", status );
1066     CloseHandle(mapping);
1067 
1068     status = pNtCreateSection( &mapping, SECTION_QUERY | SECTION_MAP_READ, NULL,
1069                                &map_size, PAGE_READONLY, SEC_COMMIT, 0 );
1070     ok( !status, "NtCreateSection failed %x\n", status );
1071     status = pNtQuerySection( mapping, SectionBasicInformation, &section_info, sizeof(section_info), NULL );
1072     ok( !status, "NtQuerySection failed err %x\n", status );
1073     ok( section_info.Attributes == SEC_COMMIT, "NtQuerySection wrong attr %08x\n",
1074         section_info.Attributes );
1075     ok( section_info.BaseAddress == NULL, "NtQuerySection wrong base %p\n", section_info.BaseAddress );
1076     ok( section_info.Size.QuadPart == 0x4000, "NtQuerySection wrong size %x%08x\n",
1077         section_info.Size.u.HighPart, section_info.Size.u.LowPart );
1078     status = pNtQuerySection( mapping, SectionBasicInformation, &section_info, sizeof(section_info)-1, NULL );
1079     ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQuerySection failed err %x\n", status );
1080     status = pNtQuerySection( mapping, SectionBasicInformation, &section_info, sizeof(section_info)+1, NULL );
1081     ok( !status, "NtQuerySection failed err %x\n", status );
1082     status = pNtQuerySection( mapping, SectionImageInformation, &image_info, sizeof(image_info)-1, NULL );
1083     ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQuerySection failed err %x\n", status );
1084     status = pNtQuerySection( mapping, SectionImageInformation, &image_info, sizeof(image_info), NULL );
1085     ok( status == STATUS_SECTION_NOT_IMAGE, "NtQuerySection failed err %x\n", status );
1086     status = pNtQuerySection( mapping, SectionImageInformation, &image_info, sizeof(image_info)+1, NULL );
1087     ok( status == STATUS_SECTION_NOT_IMAGE, "NtQuerySection failed err %x\n", status );
1088     CloseHandle(mapping);
1089 
1090     SetFilePointer(file, 0, NULL, FILE_BEGIN);
1091     SetEndOfFile(file);
1092     status = pNtCreateSection( &mapping, SECTION_QUERY | SECTION_MAP_READ, NULL,
1093                                NULL, PAGE_READONLY, SEC_COMMIT, file );
1094     ok( status == STATUS_MAPPED_FILE_SIZE_ZERO, "NtCreateSection failed %x\n", status );
1095     status = pNtCreateSection( &mapping, SECTION_QUERY | SECTION_MAP_READ, NULL,
1096                                NULL, PAGE_READONLY, SEC_IMAGE, file );
1097     ok( status == STATUS_INVALID_FILE_FOR_SECTION, "NtCreateSection failed %x\n", status );
1098 
1099     CloseHandle(file);
1100     DeleteFileA(testfile);
1101 }
1102 
1103 static void test_NtMapViewOfSection(void)
1104 {
1105     HANDLE hProcess;
1106 
1107     static const char testfile[] = "testfile.xxx";
1108     static const char data[] = "test data for NtMapViewOfSection";
1109     char buffer[sizeof(data)];
1110     HANDLE file, mapping;
1111     void *ptr, *ptr2;
1112     BOOL is_wow64, ret;
1113     DWORD status, written;
1114     SIZE_T size, result;
1115     LARGE_INTEGER offset;
1116 
1117     if (!pNtMapViewOfSection || !pNtUnmapViewOfSection)
1118     {
1119         win_skip( "NtMapViewOfSection not available\n" );
1120         return;
1121     }
1122 
1123     file = CreateFileA( testfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 );
1124     ok( file != INVALID_HANDLE_VALUE, "Failed to create test file\n" );
1125     WriteFile( file, data, sizeof(data), &written, NULL );
1126     SetFilePointer( file, 4096, NULL, FILE_BEGIN );
1127     SetEndOfFile( file );
1128 
1129     /* read/write mapping */
1130 
1131     mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
1132     ok( mapping != 0, "CreateFileMapping failed\n" );
1133 
1134     hProcess = create_target_process("sleep");
1135     ok(hProcess != NULL, "Can't start process\n");
1136 
1137     ptr = NULL;
1138     size = 0;
1139     offset.QuadPart = 0;
1140     status = pNtMapViewOfSection( mapping, hProcess, &ptr, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1141     ok( !status, "NtMapViewOfSection failed status %x\n", status );
1142     ok( !((ULONG_PTR)ptr & 0xffff), "returned memory %p is not aligned to 64k\n", ptr );
1143 
1144     ret = ReadProcessMemory( hProcess, ptr, buffer, sizeof(buffer), &result );
1145     ok( ret, "ReadProcessMemory failed\n" );
1146     ok( result == sizeof(buffer), "ReadProcessMemory didn't read all data (%lx)\n", result );
1147     ok( !memcmp( buffer, data, sizeof(buffer) ), "Wrong data read\n" );
1148 
1149     /* for some unknown reason NtMapViewOfSection fails with STATUS_NO_MEMORY when zero_bits != 0 ? */
1150     ptr2 = NULL;
1151     size = 0;
1152     offset.QuadPart = 0;
1153     status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 12, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1154     todo_wine
1155     ok( status == STATUS_NO_MEMORY, "NtMapViewOfSection returned %x\n", status );
1156     if (status == STATUS_SUCCESS)
1157     {
1158         status = pNtUnmapViewOfSection( hProcess, ptr2 );
1159         ok( !status, "NtUnmapViewOfSection failed status %x\n", status );
1160     }
1161 
1162     ptr2 = NULL;
1163     size = 0;
1164     status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 16, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1165     todo_wine
1166     ok( status == STATUS_NO_MEMORY, "NtMapViewOfSection returned %x\n", status );
1167     if (status == STATUS_SUCCESS)
1168     {
1169         status = pNtUnmapViewOfSection( hProcess, ptr2 );
1170         ok( !status, "NtUnmapViewOfSection failed status %x\n", status );
1171     }
1172 
1173     /* 22 zero bits isn't acceptable */
1174     ptr2 = NULL;
1175     size = 0;
1176     status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 22, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1177     ok( status == STATUS_INVALID_PARAMETER_4, "NtMapViewOfSection returned %x\n", status );
1178     if (status == STATUS_SUCCESS)
1179     {
1180         status = pNtUnmapViewOfSection( hProcess, ptr2 );
1181         ok( !status, "NtUnmapViewOfSection failed status %x\n", status );
1182     }
1183 
1184     /* mapping at the same page conflicts */
1185     ptr2 = ptr;
1186     size = 0;
1187     offset.QuadPart = 0;
1188     status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1189     ok( status == STATUS_CONFLICTING_ADDRESSES, "NtMapViewOfSection returned %x\n", status );
1190 
1191     /* offset has to be aligned */
1192     ptr2 = ptr;
1193     size = 0;
1194     offset.QuadPart = 1;
1195     status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1196     ok( status == STATUS_MAPPED_ALIGNMENT, "NtMapViewOfSection returned %x\n", status );
1197 
1198     /* ptr has to be aligned */
1199     ptr2 = (char *)ptr + 42;
1200     size = 0;
1201     offset.QuadPart = 0;
1202     status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1203     ok( status == STATUS_MAPPED_ALIGNMENT, "NtMapViewOfSection returned %x\n", status );
1204 
1205     /* still not 64k aligned */
1206     ptr2 = (char *)ptr + 0x1000;
1207     size = 0;
1208     offset.QuadPart = 0;
1209     status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1210     ok( status == STATUS_MAPPED_ALIGNMENT, "NtMapViewOfSection returned %x\n", status );
1211 
1212     /* zero_bits != 0 is not allowed when an address is set */
1213     ptr2 = (char *)ptr + 0x1000;
1214     size = 0;
1215     offset.QuadPart = 0;
1216     status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 12, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1217     ok( status == STATUS_INVALID_PARAMETER_4, "NtMapViewOfSection returned %x\n", status );
1218 
1219     ptr2 = (char *)ptr + 0x1000;
1220     size = 0;
1221     offset.QuadPart = 0;
1222     status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 16, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1223     ok( status == STATUS_INVALID_PARAMETER_4, "NtMapViewOfSection returned %x\n", status );
1224 
1225     ptr2 = (char *)ptr + 0x1001;
1226     size = 0;
1227     offset.QuadPart = 0;
1228     status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 16, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1229     ok( status == STATUS_INVALID_PARAMETER_4, "NtMapViewOfSection returned %x\n", status );
1230 
1231     ptr2 = (char *)ptr + 0x1000;
1232     size = 0;
1233     offset.QuadPart = 1;
1234     status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 16, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1235     ok( status == STATUS_INVALID_PARAMETER_4, "NtMapViewOfSection returned %x\n", status );
1236 
1237     if (sizeof(void *) == sizeof(int) && (!pIsWow64Process ||
1238         !pIsWow64Process( GetCurrentProcess(), &is_wow64 ) || !is_wow64))
1239     {
1240         /* new memory region conflicts with previous mapping */
1241         ptr2 = ptr;
1242         size = 0;
1243         offset.QuadPart = 0;
1244         status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset,
1245                                       &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE );
1246         ok( status == STATUS_CONFLICTING_ADDRESSES, "NtMapViewOfSection returned %x\n", status );
1247 
1248         ptr2 = (char *)ptr + 42;
1249         size = 0;
1250         offset.QuadPart = 0;
1251         status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset,
1252                                       &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE );
1253         ok( status == STATUS_CONFLICTING_ADDRESSES, "NtMapViewOfSection returned %x\n", status );
1254 
1255         /* in contrary to regular NtMapViewOfSection, only 4kb align is enforced */
1256         ptr2 = (char *)ptr + 0x1000;
1257         size = 0;
1258         offset.QuadPart = 0;
1259         status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset,
1260                                       &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE );
1261         ok( status == STATUS_SUCCESS, "NtMapViewOfSection returned %x\n", status );
1262         ok( (char *)ptr2 == (char *)ptr + 0x1000,
1263             "expected address %p, got %p\n", (char *)ptr + 0x1000, ptr2 );
1264         status = pNtUnmapViewOfSection( hProcess, ptr2 );
1265         ok( !status, "NtUnmapViewOfSection failed status %x\n", status );
1266 
1267         /* the address is rounded down if not on a page boundary */
1268         ptr2 = (char *)ptr + 0x1001;
1269         size = 0;
1270         offset.QuadPart = 0;
1271         status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset,
1272                                       &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE );
1273         ok( status == STATUS_SUCCESS, "NtMapViewOfSection returned %x\n", status );
1274         ok( (char *)ptr2 == (char *)ptr + 0x1000,
1275             "expected address %p, got %p\n", (char *)ptr + 0x1000, ptr2 );
1276         status = pNtUnmapViewOfSection( hProcess, ptr2 );
1277         ok( !status, "NtUnmapViewOfSection failed status %x\n", status );
1278 
1279         ptr2 = (char *)ptr + 0x2000;
1280         size = 0;
1281         offset.QuadPart = 0;
1282         status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset,
1283                                       &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE );
1284         ok( status == STATUS_SUCCESS, "NtMapViewOfSection returned %x\n", status );
1285         ok( (char *)ptr2 == (char *)ptr + 0x2000,
1286             "expected address %p, got %p\n", (char *)ptr + 0x2000, ptr2 );
1287         status = pNtUnmapViewOfSection( hProcess, ptr2 );
1288         ok( !status, "NtUnmapViewOfSection failed status %x\n", status );
1289     }
1290     else
1291     {
1292         ptr2 = (char *)ptr + 0x1000;
1293         size = 0;
1294         offset.QuadPart = 0;
1295         status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset,
1296                                       &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE );
1297         todo_wine
1298         ok( status == STATUS_INVALID_PARAMETER_9, "NtMapViewOfSection returned %x\n", status );
1299     }
1300 
1301     status = pNtUnmapViewOfSection( hProcess, ptr );
1302     ok( !status, "NtUnmapViewOfSection failed status %x\n", status );
1303 
1304     CloseHandle( mapping );
1305     CloseHandle( file );
1306     DeleteFileA( testfile );
1307 
1308     TerminateProcess(hProcess, 0);
1309     CloseHandle(hProcess);
1310 }
1311 
1312 static void test_NtAreMappedFilesTheSame(void)
1313 {
1314     static const char testfile[] = "testfile.xxx";
1315     HANDLE file, file2, mapping, map2;
1316     void *ptr, *ptr2;
1317     NTSTATUS status;
1318     char path[MAX_PATH];
1319 
1320     if (!pNtAreMappedFilesTheSame)
1321     {
1322         win_skip( "NtAreMappedFilesTheSame not available\n" );
1323         return;
1324     }
1325 
1326     file = CreateFileA( testfile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1327                         NULL, CREATE_ALWAYS, 0, 0 );
1328     ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() );
1329     SetFilePointer( file, 4096, NULL, FILE_BEGIN );
1330     SetEndOfFile( file );
1331 
1332     mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
1333     ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() );
1334 
1335     ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
1336     ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
1337 
1338     file2 = CreateFileA( testfile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
1339                          NULL, OPEN_EXISTING, 0, 0 );
1340     ok( file2 != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() );
1341 
1342     map2 = CreateFileMappingA( file2, NULL, PAGE_READONLY, 0, 4096, NULL );
1343     ok( map2 != 0, "CreateFileMapping error %u\n", GetLastError() );
1344     ptr2 = MapViewOfFile( map2, FILE_MAP_READ, 0, 0, 4096 );
1345     ok( ptr2 != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
1346     status = pNtAreMappedFilesTheSame( ptr, ptr2 );
1347     ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status );
1348     UnmapViewOfFile( ptr2 );
1349 
1350     ptr2 = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
1351     ok( ptr2 != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
1352     status = pNtAreMappedFilesTheSame( ptr, ptr2 );
1353     ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status );
1354     UnmapViewOfFile( ptr2 );
1355     CloseHandle( map2 );
1356 
1357     map2 = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL );
1358     ok( map2 != 0, "CreateFileMapping error %u\n", GetLastError() );
1359     ptr2 = MapViewOfFile( map2, FILE_MAP_READ, 0, 0, 4096 );
1360     ok( ptr2 != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
1361     status = pNtAreMappedFilesTheSame( ptr, ptr2 );
1362     ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status );
1363     UnmapViewOfFile( ptr2 );
1364     CloseHandle( map2 );
1365     CloseHandle( file2 );
1366 
1367     status = pNtAreMappedFilesTheSame( ptr, ptr );
1368     ok( status == STATUS_SUCCESS || broken(status == STATUS_NOT_SAME_DEVICE),
1369         "NtAreMappedFilesTheSame returned %x\n", status );
1370 
1371     status = pNtAreMappedFilesTheSame( ptr, (char *)ptr + 30 );
1372     ok( status == STATUS_SUCCESS || broken(status == STATUS_NOT_SAME_DEVICE),
1373         "NtAreMappedFilesTheSame returned %x\n", status );
1374 
1375     status = pNtAreMappedFilesTheSame( ptr, GetModuleHandleA("kernel32.dll") );
1376     ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status );
1377 
1378     status = pNtAreMappedFilesTheSame( ptr, (void *)0xdeadbeef );
1379     ok( status == STATUS_CONFLICTING_ADDRESSES || status == STATUS_INVALID_ADDRESS,
1380         "NtAreMappedFilesTheSame returned %x\n", status );
1381 
1382     status = pNtAreMappedFilesTheSame( ptr, NULL );
1383     ok( status == STATUS_INVALID_ADDRESS, "NtAreMappedFilesTheSame returned %x\n", status );
1384 
1385     status = pNtAreMappedFilesTheSame( ptr, (void *)GetProcessHeap() );
1386     ok( status == STATUS_CONFLICTING_ADDRESSES, "NtAreMappedFilesTheSame returned %x\n", status );
1387 
1388     status = pNtAreMappedFilesTheSame( NULL, NULL );
1389     ok( status == STATUS_INVALID_ADDRESS, "NtAreMappedFilesTheSame returned %x\n", status );
1390 
1391     ptr2 = VirtualAlloc( NULL, 0x10000, MEM_COMMIT, PAGE_READWRITE );
1392     ok( ptr2 != NULL, "VirtualAlloc error %u\n", GetLastError() );
1393     status = pNtAreMappedFilesTheSame( ptr, ptr2 );
1394     ok( status == STATUS_CONFLICTING_ADDRESSES, "NtAreMappedFilesTheSame returned %x\n", status );
1395     VirtualFree( ptr2, 0, MEM_RELEASE );
1396 
1397     UnmapViewOfFile( ptr );
1398     CloseHandle( mapping );
1399     CloseHandle( file );
1400 
1401     status = pNtAreMappedFilesTheSame( GetModuleHandleA("ntdll.dll"),
1402                                        GetModuleHandleA("kernel32.dll") );
1403     ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status );
1404     status = pNtAreMappedFilesTheSame( GetModuleHandleA("kernel32.dll"),
1405                                        GetModuleHandleA("kernel32.dll") );
1406     ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %x\n", status );
1407     status = pNtAreMappedFilesTheSame( GetModuleHandleA("kernel32.dll"),
1408                                        (char *)GetModuleHandleA("kernel32.dll") + 4096 );
1409     ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %x\n", status );
1410 
1411     GetSystemDirectoryA( path, MAX_PATH );
1412     strcat( path, "\\kernel32.dll" );
1413     file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
1414     ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() );
1415 
1416     mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL );
1417     ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() );
1418     ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
1419     ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
1420     status = pNtAreMappedFilesTheSame( ptr, GetModuleHandleA("kernel32.dll") );
1421     ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status );
1422     UnmapViewOfFile( ptr );
1423     CloseHandle( mapping );
1424 
1425     mapping = CreateFileMappingA( file, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL );
1426     ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() );
1427     ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
1428     ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
1429     status = pNtAreMappedFilesTheSame( ptr, GetModuleHandleA("kernel32.dll") );
1430     todo_wine
1431     ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %x\n", status );
1432 
1433     file2 = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
1434     ok( file2 != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() );
1435     map2 = CreateFileMappingA( file2, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL );
1436     ok( map2 != 0, "CreateFileMapping error %u\n", GetLastError() );
1437     ptr2 = MapViewOfFile( map2, FILE_MAP_READ, 0, 0, 0 );
1438     ok( ptr2 != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
1439     status = pNtAreMappedFilesTheSame( ptr, ptr2 );
1440     ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %x\n", status );
1441     UnmapViewOfFile( ptr2 );
1442     CloseHandle( map2 );
1443     CloseHandle( file2 );
1444 
1445     UnmapViewOfFile( ptr );
1446     CloseHandle( mapping );
1447 
1448     CloseHandle( file );
1449     DeleteFileA( testfile );
1450 }
1451 
1452 static void test_CreateFileMapping(void)
1453 {
1454     HANDLE handle, handle2;
1455 
1456     /* test case sensitivity */
1457 
1458     SetLastError(0xdeadbeef);
1459     handle = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, 0x1000,
1460                                  "Wine Test Mapping");
1461     ok( handle != NULL, "CreateFileMapping failed with error %u\n", GetLastError());
1462     ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
1463 
1464     SetLastError(0xdeadbeef);
1465     handle2 = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, 0x1000,
1466                                   "Wine Test Mapping");
1467     ok( handle2 != NULL, "CreateFileMapping failed with error %d\n", GetLastError());
1468     ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError());
1469     CloseHandle( handle2 );
1470 
1471     SetLastError(0xdeadbeef);
1472     handle2 = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, 0x1000,
1473                                  "WINE TEST MAPPING");
1474     ok( handle2 != NULL, "CreateFileMapping failed with error %d\n", GetLastError());
1475     ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
1476     CloseHandle( handle2 );
1477 
1478     SetLastError(0xdeadbeef);
1479     handle2 = OpenFileMappingA( FILE_MAP_ALL_ACCESS, FALSE, "Wine Test Mapping");
1480     ok( handle2 != NULL, "OpenFileMapping failed with error %d\n", GetLastError());
1481     CloseHandle( handle2 );
1482 
1483     SetLastError(0xdeadbeef);
1484     handle2 = OpenFileMappingA( FILE_MAP_ALL_ACCESS, FALSE, "WINE TEST MAPPING");
1485     ok( !handle2, "OpenFileMapping succeeded\n");
1486     ok( GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError());
1487 
1488     CloseHandle( handle );
1489 }
1490 
1491 static void test_IsBadReadPtr(void)
1492 {
1493     BOOL ret;
1494     void *ptr = (void *)0xdeadbeef;
1495     char stackvar;
1496 
1497     ret = IsBadReadPtr(NULL, 0);
1498     ok(ret == FALSE, "Expected IsBadReadPtr to return FALSE, got %d\n", ret);
1499 
1500     ret = IsBadReadPtr(NULL, 1);
1501     ok(ret == TRUE, "Expected IsBadReadPtr to return TRUE, got %d\n", ret);
1502 
1503     ret = IsBadReadPtr(ptr, 0);
1504     ok(ret == FALSE, "Expected IsBadReadPtr to return FALSE, got %d\n", ret);
1505 
1506     ret = IsBadReadPtr(ptr, 1);
1507     ok(ret == TRUE, "Expected IsBadReadPtr to return TRUE, got %d\n", ret);
1508 
1509     ret = IsBadReadPtr(&stackvar, 0);
1510     ok(ret == FALSE, "Expected IsBadReadPtr to return FALSE, got %d\n", ret);
1511 
1512     ret = IsBadReadPtr(&stackvar, sizeof(char));
1513     ok(ret == FALSE, "Expected IsBadReadPtr to return FALSE, got %d\n", ret);
1514 }
1515 
1516 static void test_IsBadWritePtr(void)
1517 {
1518     BOOL ret;
1519     void *ptr = (void *)0xdeadbeef;
1520     char stackval;
1521 
1522     ret = IsBadWritePtr(NULL, 0);
1523     ok(ret == FALSE, "Expected IsBadWritePtr to return FALSE, got %d\n", ret);
1524 
1525     ret = IsBadWritePtr(NULL, 1);
1526     ok(ret == TRUE, "Expected IsBadWritePtr to return TRUE, got %d\n", ret);
1527 
1528     ret = IsBadWritePtr(ptr, 0);
1529     ok(ret == FALSE, "Expected IsBadWritePtr to return FALSE, got %d\n", ret);
1530 
1531     ret = IsBadWritePtr(ptr, 1);
1532     ok(ret == TRUE, "Expected IsBadWritePtr to return TRUE, got %d\n", ret);
1533 
1534     ret = IsBadWritePtr(&stackval, 0);
1535     ok(ret == FALSE, "Expected IsBadWritePtr to return FALSE, got %d\n", ret);
1536 
1537     ret = IsBadWritePtr(&stackval, sizeof(char));
1538     ok(ret == FALSE, "Expected IsBadWritePtr to return FALSE, got %d\n", ret);
1539 }
1540 
1541 static void test_IsBadCodePtr(void)
1542 {
1543     BOOL ret;
1544     void *ptr = (void *)0xdeadbeef;
1545     char stackval;
1546 
1547     ret = IsBadCodePtr(NULL);
1548     ok(ret == TRUE, "Expected IsBadCodePtr to return TRUE, got %d\n", ret);
1549 
1550     ret = IsBadCodePtr(ptr);
1551     ok(ret == TRUE, "Expected IsBadCodePtr to return TRUE, got %d\n", ret);
1552 
1553     ret = IsBadCodePtr((void *)&stackval);
1554     ok(ret == FALSE, "Expected IsBadCodePtr to return FALSE, got %d\n", ret);
1555 }
1556 
1557 static void test_write_watch(void)
1558 {
1559     static const char pipename[] = "\\\\.\\pipe\\test_write_watch_pipe";
1560     static const char testdata[] = "Hello World";
1561     DWORD ret, size, old_prot, num_bytes;
1562     MEMORY_BASIC_INFORMATION info;
1563     HANDLE readpipe, writepipe;
1564     OVERLAPPED overlapped;
1565     void *results[64];
1566     ULONG_PTR count;
1567     ULONG pagesize;
1568     BOOL success;
1569     char *base;
1570 
1571     if (!pGetWriteWatch || !pResetWriteWatch)
1572     {
1573         win_skip( "GetWriteWatch not supported\n" );
1574         return;
1575     }
1576 
1577     size = 0x10000;
1578     base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT | MEM_WRITE_WATCH, PAGE_READWRITE );
1579     if (!base &&
1580         (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_NOT_SUPPORTED))
1581     {
1582         win_skip( "MEM_WRITE_WATCH not supported\n" );
1583         return;
1584     }
1585     ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
1586     ret = VirtualQuery( base, &info, sizeof(info) );
1587     ok(ret, "VirtualQuery failed %u\n", GetLastError());
1588     ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base );
1589     ok( info.AllocationProtect == PAGE_READWRITE, "wrong AllocationProtect %x\n", info.AllocationProtect );
1590     ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize );
1591     ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State );
1592     ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect );
1593     ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type );
1594 
1595     count = 64;
1596     SetLastError( 0xdeadbeef );
1597     ret = pGetWriteWatch( 0, NULL, size, results, &count, &pagesize );
1598     ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1599     ok( GetLastError() == ERROR_INVALID_PARAMETER ||
1600         broken( GetLastError() == 0xdeadbeef ), /* win98 */
1601         "wrong error %u\n", GetLastError() );
1602 
1603     SetLastError( 0xdeadbeef );
1604     ret = pGetWriteWatch( 0, GetModuleHandleW(NULL), size, results, &count, &pagesize );
1605     if (ret)
1606     {
1607         ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1608         ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1609     }
1610     else  /* win98 */
1611     {
1612         ok( count == 0, "wrong count %lu\n", count );
1613     }
1614 
1615     ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1616     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1617     ok( count == 0, "wrong count %lu\n", count );
1618 
1619     base[pagesize + 1] = 0x44;
1620 
1621     count = 64;
1622     ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1623     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1624     ok( count == 1, "wrong count %lu\n", count );
1625     ok( results[0] == base + pagesize, "wrong result %p\n", results[0] );
1626 
1627     count = 64;
1628     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
1629     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1630     ok( count == 1, "wrong count %lu\n", count );
1631     ok( results[0] == base + pagesize, "wrong result %p\n", results[0] );
1632 
1633     count = 64;
1634     ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1635     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1636     ok( count == 0, "wrong count %lu\n", count );
1637 
1638     base[2*pagesize + 3] = 0x11;
1639     base[4*pagesize + 8] = 0x11;
1640 
1641     count = 64;
1642     ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1643     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1644     ok( count == 2, "wrong count %lu\n", count );
1645     ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] );
1646     ok( results[1] == base + 4*pagesize, "wrong result %p\n", results[1] );
1647 
1648     count = 64;
1649     ret = pGetWriteWatch( 0, base + 3*pagesize, 2*pagesize, results, &count, &pagesize );
1650     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1651     ok( count == 1, "wrong count %lu\n", count );
1652     ok( results[0] == base + 4*pagesize, "wrong result %p\n", results[0] );
1653 
1654     ret = pResetWriteWatch( base, 3*pagesize );
1655     ok( !ret, "pResetWriteWatch failed %u\n", GetLastError() );
1656 
1657     count = 64;
1658     ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1659     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1660     ok( count == 1, "wrong count %lu\n", count );
1661     ok( results[0] == base + 4*pagesize, "wrong result %p\n", results[0] );
1662 
1663     *(DWORD *)(base + 2*pagesize - 2) = 0xdeadbeef;
1664 
1665     count = 64;
1666     ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1667     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1668     ok( count == 3, "wrong count %lu\n", count );
1669     ok( results[0] == base + pagesize, "wrong result %p\n", results[0] );
1670     ok( results[1] == base + 2*pagesize, "wrong result %p\n", results[1] );
1671     ok( results[2] == base + 4*pagesize, "wrong result %p\n", results[2] );
1672 
1673     count = 1;
1674     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
1675     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1676     ok( count == 1, "wrong count %lu\n", count );
1677     ok( results[0] == base + pagesize, "wrong result %p\n", results[0] );
1678 
1679     count = 64;
1680     ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1681     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1682     ok( count == 2, "wrong count %lu\n", count );
1683     ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] );
1684     ok( results[1] == base + 4*pagesize, "wrong result %p\n", results[1] );
1685 
1686     /* changing protections doesn't affect watches */
1687 
1688     ret = VirtualProtect( base, 3*pagesize, PAGE_READONLY, &old_prot );
1689     ok( ret, "VirtualProtect failed error %u\n", GetLastError() );
1690     ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
1691 
1692     ret = VirtualQuery( base, &info, sizeof(info) );
1693     ok(ret, "VirtualQuery failed %u\n", GetLastError());
1694     ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base );
1695     ok( info.RegionSize == 3*pagesize, "wrong RegionSize 0x%lx\n", info.RegionSize );
1696     ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State );
1697     ok( info.Protect == PAGE_READONLY, "wrong Protect 0x%x\n", info.Protect );
1698 
1699     ret = VirtualProtect( base, 3*pagesize, PAGE_READWRITE, &old_prot );
1700     ok( ret, "VirtualProtect failed error %u\n", GetLastError() );
1701     ok( old_prot == PAGE_READONLY, "wrong old prot %x\n", old_prot );
1702 
1703     count = 64;
1704     ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1705     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1706     ok( count == 2, "wrong count %lu\n", count );
1707     ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] );
1708     ok( results[1] == base + 4*pagesize, "wrong result %p\n", results[1] );
1709 
1710     ret = VirtualQuery( base, &info, sizeof(info) );
1711     ok(ret, "VirtualQuery failed %u\n", GetLastError());
1712     ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base );
1713     ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize );
1714     ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State );
1715     ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect );
1716 
1717     /* ReadFile should trigger write watches */
1718 
1719     memset( &overlapped, 0, sizeof(overlapped) );
1720     overlapped.hEvent = CreateEventA( NULL, TRUE, FALSE, NULL );
1721 
1722     readpipe = CreateNamedPipeA( pipename, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_INBOUND,
1723                                  PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1024, 1024,
1724                                  NMPWAIT_USE_DEFAULT_WAIT, NULL );
1725     ok( readpipe != INVALID_HANDLE_VALUE, "CreateNamedPipeA failed %u\n", GetLastError() );
1726 
1727     success = ConnectNamedPipe( readpipe, &overlapped );
1728     ok( !success, "ConnectNamedPipe unexpectedly succeeded\n" );
1729     ok( GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %u\n", GetLastError() );
1730 
1731     writepipe = CreateFileA( pipename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL );
1732     ok( writepipe != INVALID_HANDLE_VALUE, "CreateFileA failed %u\n", GetLastError() );
1733 
1734     ret = WaitForSingleObject( overlapped.hEvent, 1000 );
1735     ok( ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret );
1736 
1737     memset( base, 0, size );
1738 
1739     count = 64;
1740     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
1741     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1742     ok( count == 16, "wrong count %lu\n", count );
1743 
1744     success = ReadFile( readpipe, base, size, NULL, &overlapped );
1745     ok( !success, "ReadFile unexpectedly succeeded\n" );
1746     ok( GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %u\n", GetLastError() );
1747 
1748     count = 64;
1749     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
1750     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1751     ok( count == 16, "wrong count %lu\n", count );
1752 
1753     num_bytes = 0;
1754     success = WriteFile( writepipe, testdata, sizeof(testdata), &num_bytes, NULL );
1755     ok( success, "WriteFile failed %u\n", GetLastError() );
1756     ok( num_bytes == sizeof(testdata), "wrong number of bytes written\n" );
1757 
1758     num_bytes = 0;
1759     success = GetOverlappedResult( readpipe, &overlapped, &num_bytes, TRUE );
1760     ok( success, "GetOverlappedResult failed %u\n", GetLastError() );
1761     ok( num_bytes == sizeof(testdata), "wrong number of bytes read\n" );
1762     ok( !memcmp( base, testdata, sizeof(testdata)), "didn't receive expected data\n" );
1763 
1764     count = 64;
1765     memset( results, 0, sizeof(results) );
1766     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
1767     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1768     todo_wine ok( count == 1, "wrong count %lu\n", count );
1769     ok( results[0] == base, "wrong result %p\n", results[0] );
1770 
1771     CloseHandle( readpipe );
1772     CloseHandle( writepipe );
1773     CloseHandle( overlapped.hEvent );
1774 
1775     /* some invalid parameter tests */
1776 
1777     SetLastError( 0xdeadbeef );
1778     count = 0;
1779     ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1780     if (ret)
1781     {
1782         ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1783         ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1784 
1785         SetLastError( 0xdeadbeef );
1786         ret = pGetWriteWatch( 0, base, size, results, NULL, &pagesize );
1787         ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1788         ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
1789 
1790         SetLastError( 0xdeadbeef );
1791         count = 64;
1792         ret = pGetWriteWatch( 0, base, size, results, &count, NULL );
1793         ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1794         ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
1795 
1796         SetLastError( 0xdeadbeef );
1797         count = 64;
1798         ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize );
1799         ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1800         ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
1801 
1802         SetLastError( 0xdeadbeef );
1803         count = 0;
1804         ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize );
1805         ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1806         ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1807 
1808         SetLastError( 0xdeadbeef );
1809         count = 64;
1810         ret = pGetWriteWatch( 0xdeadbeef, base, size, results, &count, &pagesize );
1811         ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1812         ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1813 
1814         SetLastError( 0xdeadbeef );
1815         count = 64;
1816         ret = pGetWriteWatch( 0, base, 0, results, &count, &pagesize );
1817         ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1818         ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1819 
1820         SetLastError( 0xdeadbeef );
1821         count = 64;
1822         ret = pGetWriteWatch( 0, base, size * 2, results, &count, &pagesize );
1823         ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1824         ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1825 
1826         SetLastError( 0xdeadbeef );
1827         count = 64;
1828         ret = pGetWriteWatch( 0, base + size - pagesize, pagesize + 1, results, &count, &pagesize );
1829         ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1830         ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1831 
1832         SetLastError( 0xdeadbeef );
1833         ret = pResetWriteWatch( base, 0 );
1834         ok( ret == ~0u, "ResetWriteWatch succeeded %u\n", ret );
1835         ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1836 
1837         SetLastError( 0xdeadbeef );
1838         ret = pResetWriteWatch( GetModuleHandleW(NULL), size );
1839         ok( ret == ~0u, "ResetWriteWatch succeeded %u\n", ret );
1840         ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1841     }
1842     else  /* win98 is completely different */
1843     {
1844         SetLastError( 0xdeadbeef );
1845         count = 64;
1846         ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize );
1847         ok( ret == ERROR_INVALID_PARAMETER, "GetWriteWatch succeeded %u\n", ret );
1848         ok( GetLastError() == 0xdeadbeef, "wrong error %u\n", GetLastError() );
1849 
1850         count = 0;
1851         ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize );
1852         ok( !ret, "GetWriteWatch failed %u\n", ret );
1853 
1854         count = 64;
1855         ret = pGetWriteWatch( 0xdeadbeef, base, size, results, &count, &pagesize );
1856         ok( !ret, "GetWriteWatch failed %u\n", ret );
1857 
1858         count = 64;
1859         ret = pGetWriteWatch( 0, base, 0, results, &count, &pagesize );
1860         ok( !ret, "GetWriteWatch failed %u\n", ret );
1861 
1862         ret = pResetWriteWatch( base, 0 );
1863         ok( !ret, "ResetWriteWatch failed %u\n", ret );
1864 
1865         ret = pResetWriteWatch( GetModuleHandleW(NULL), size );
1866         ok( !ret, "ResetWriteWatch failed %u\n", ret );
1867     }
1868 
1869     VirtualFree( base, 0, MEM_RELEASE );
1870 
1871     base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_WRITE_WATCH, PAGE_READWRITE );
1872     ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
1873     VirtualFree( base, 0, MEM_RELEASE );
1874 
1875     base = VirtualAlloc( 0, size, MEM_WRITE_WATCH, PAGE_READWRITE );
1876     ok( !base, "VirtualAlloc succeeded\n" );
1877     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1878 
1879     /* initial protect doesn't matter */
1880 
1881     base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_WRITE_WATCH, PAGE_NOACCESS );
1882     ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
1883     base = VirtualAlloc( base, size, MEM_COMMIT, PAGE_NOACCESS );
1884     ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
1885 
1886     count = 64;
1887     ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1888     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1889     ok( count == 0, "wrong count %lu\n", count );
1890 
1891     ret = VirtualProtect( base, 6*pagesize, PAGE_READWRITE, &old_prot );
1892     ok( ret, "VirtualProtect failed error %u\n", GetLastError() );
1893     ok( old_prot == PAGE_NOACCESS, "wrong old prot %x\n", old_prot );
1894 
1895     base[5*pagesize + 200] = 3;
1896 
1897     ret = VirtualProtect( base, 6*pagesize, PAGE_NOACCESS, &old_prot );
1898     ok( ret, "VirtualProtect failed error %u\n", GetLastError() );
1899     ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
1900 
1901     count = 64;
1902     ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1903     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1904     ok( count == 1, "wrong count %lu\n", count );
1905     ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] );
1906 
1907     ret = VirtualFree( base, size, MEM_DECOMMIT );
1908     ok( ret, "VirtualFree failed %u\n", GetLastError() );
1909 
1910     count = 64;
1911     ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1912     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1913     ok( count == 1 || broken(count == 0), /* win98 */
1914         "wrong count %lu\n", count );
1915     if (count) ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] );
1916 
1917     VirtualFree( base, 0, MEM_RELEASE );
1918 }
1919 
1920 #if defined(__i386__) || defined(__x86_64__)
1921 
1922 static DWORD WINAPI stack_commit_func( void *arg )
1923 {
1924     volatile char *p = (char *)&p;
1925 
1926     /* trigger all guard pages, to ensure that the pages are committed */
1927     while (p >= (char *)NtCurrentTeb()->DeallocationStack + 4 * 0x1000)
1928     {
1929         p[0] |= 0;
1930         p -= 0x1000;
1931     }
1932 
1933     ok( arg == (void *)0xdeadbeef, "expected 0xdeadbeef, got %p\n", arg );
1934     return 42;
1935 }
1936 
1937 static void test_stack_commit(void)
1938 {
1939 #ifdef __i386__
1940     static const char code_call_on_stack[] = {
1941         0x55,                   /* pushl %ebp */
1942         0x56,                   /* pushl %esi */
1943         0x89, 0xe6,             /* movl %esp,%esi */
1944         0x8b, 0x4c, 0x24, 0x0c, /* movl 12(%esp),%ecx - func */
1945         0x8b, 0x54, 0x24, 0x10, /* movl 16(%esp),%edx - arg */
1946         0x8b, 0x44, 0x24, 0x14, /* movl 20(%esp),%eax - stack */
1947         0x83, 0xe0, 0xf0,       /* andl $~15,%eax */
1948         0x83, 0xe8, 0x0c,       /* subl $12,%eax */
1949         0x89, 0xc4,             /* movl %eax,%esp */
1950         0x52,                   /* pushl %edx */
1951         0x31, 0xed,             /* xorl %ebp,%ebp */
1952         0xff, 0xd1,             /* call *%ecx */
1953         0x89, 0xf4,             /* movl %esi,%esp */
1954         0x5e,                   /* popl %esi */
1955         0x5d,                   /* popl %ebp */
1956         0xc2, 0x0c, 0x00 };     /* ret $12 */
1957 #else
1958     static const char code_call_on_stack[] = {
1959         0x55,                   /* pushq %rbp */
1960         0x48, 0x89, 0xe5,       /* movq %rsp,%rbp */
1961                                 /* %rcx - func, %rdx - arg, %r8 - stack */
1962         0x48, 0x87, 0xca,       /* xchgq %rcx,%rdx */
1963         0x49, 0x83, 0xe0, 0xf0, /* andq $~15,%r8 */
1964         0x49, 0x83, 0xe8, 0x20, /* subq $0x20,%r8 */
1965         0x4c, 0x89, 0xc4,       /* movq %r8,%rsp */
1966         0xff, 0xd2,             /* callq *%rdx */
1967         0x48, 0x89, 0xec,       /* movq %rbp,%rsp */
1968         0x5d,                   /* popq %rbp */
1969         0xc3 };                 /* ret */
1970 #endif
1971     DWORD (WINAPI *call_on_stack)( DWORD (WINAPI *func)(void *), void *arg, void *stack );
1972     void *old_stack, *old_stack_base, *old_stack_limit;
1973     void *new_stack, *new_stack_base;
1974     DWORD result;
1975 
1976     call_on_stack = VirtualAlloc( 0, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE );
1977     ok( call_on_stack != NULL, "VirtualAlloc failed %u\n", GetLastError() );
1978     memcpy( call_on_stack, code_call_on_stack, sizeof(code_call_on_stack) );
1979 
1980     /* allocate a new stack, only the first guard page is committed */
1981     new_stack = VirtualAlloc( 0, 0x400000, MEM_RESERVE, PAGE_READWRITE );
1982     ok( new_stack != NULL, "VirtualAlloc failed %u\n", GetLastError() );
1983     new_stack_base = (char *)new_stack + 0x400000;
1984     VirtualAlloc( (char *)new_stack_base - 0x1000, 0x1000, MEM_COMMIT, PAGE_READWRITE | PAGE_GUARD );
1985 
1986     old_stack       = NtCurrentTeb()->DeallocationStack;
1987     old_stack_base  = NtCurrentTeb()->Tib.StackBase;
1988     old_stack_limit = NtCurrentTeb()->Tib.StackLimit;
1989 
1990     NtCurrentTeb()->DeallocationStack  = new_stack;
1991     NtCurrentTeb()->Tib.StackBase      = new_stack_base;
1992     NtCurrentTeb()->Tib.StackLimit     = new_stack_base;
1993 
1994     result = call_on_stack( stack_commit_func, (void *)0xdeadbeef, new_stack_base );
1995 
1996     NtCurrentTeb()->DeallocationStack  = old_stack;
1997     NtCurrentTeb()->Tib.StackBase      = old_stack_base;
1998     NtCurrentTeb()->Tib.StackLimit     = old_stack_limit;
1999 
2000     ok( result == 42, "expected 42, got %u\n", result );
2001 
2002     VirtualFree( new_stack, 0, MEM_RELEASE );
2003     VirtualFree( call_on_stack, 0, MEM_RELEASE );
2004 }
2005 
2006 #endif  /* defined(__i386__) || defined(__x86_64__) */
2007 #ifdef __i386__
2008 
2009 static LONG num_guard_page_calls;
2010 
2011 static DWORD guard_page_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
2012                                  CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
2013 {
2014     trace( "exception: %08x flags:%x addr:%p\n",
2015            rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
2016 
2017     ok( rec->NumberParameters == 2, "NumberParameters is %d instead of 2\n", rec->NumberParameters );
2018     ok( rec->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION, "ExceptionCode is %08x instead of %08x\n",
2019         rec->ExceptionCode, STATUS_GUARD_PAGE_VIOLATION );
2020 
2021     InterlockedIncrement( &num_guard_page_calls );
2022     *(int *)rec->ExceptionInformation[1] += 0x100;
2023 
2024     return ExceptionContinueExecution;
2025 }
2026 
2027 static void test_guard_page(void)
2028 {
2029     EXCEPTION_REGISTRATION_RECORD frame;
2030     MEMORY_BASIC_INFORMATION info;
2031     DWORD ret, size, old_prot;
2032     int *value, old_value;
2033     void *results[64];
2034     ULONG_PTR count;
2035     ULONG pagesize;
2036     BOOL success;
2037     char *base;
2038 
2039     size = 0x1000;
2040     base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE | PAGE_GUARD );
2041     ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
2042     value = (int *)base;
2043 
2044     /* verify info structure */
2045     ret = VirtualQuery( base, &info, sizeof(info) );
2046     ok( ret, "VirtualQuery failed %u\n", GetLastError());
2047     ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base );
2048     ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "wrong AllocationProtect %x\n", info.AllocationProtect );
2049     ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize );
2050     ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State );
2051     ok( info.Protect == (PAGE_READWRITE | PAGE_GUARD), "wrong Protect 0x%x\n", info.Protect );
2052     ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type );
2053 
2054     /* put some initial value into the memory */
2055     success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2056     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2057     ok( old_prot == (PAGE_READWRITE | PAGE_GUARD), "wrong old prot %x\n", old_prot );
2058 
2059     *value       = 1;
2060     *(value + 1) = 2;
2061 
2062     success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
2063     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2064     ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
2065 
2066     /* test behaviour of VirtualLock - first attempt should fail */
2067     SetLastError( 0xdeadbeef );
2068     success = VirtualLock( base, size );
2069     ok( !success, "VirtualLock unexpectedly succeeded\n" );
2070     todo_wine
2071     ok( GetLastError() == STATUS_GUARD_PAGE_VIOLATION, "wrong error %u\n", GetLastError() );
2072 
2073     success = VirtualLock( base, size );
2074     todo_wine
2075     ok( success, "VirtualLock failed %u\n", GetLastError() );
2076     if (success)
2077     {
2078         ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%x\n", *value );
2079         success = VirtualUnlock( base, size );
2080         ok( success, "VirtualUnlock failed %u\n", GetLastError() );
2081     }
2082 
2083     /* check info structure again, PAGE_GUARD should be removed now */
2084     ret = VirtualQuery( base, &info, sizeof(info) );
2085     ok( ret, "VirtualQuery failed %u\n", GetLastError());
2086     ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base );
2087     ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "wrong AllocationProtect %x\n", info.AllocationProtect );
2088     ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize );
2089     ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State );
2090     todo_wine
2091     ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect );
2092     ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type );
2093 
2094     success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
2095     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2096     todo_wine
2097     ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
2098 
2099     /* test directly accessing the memory - we need to setup an exception handler first */
2100     frame.Handler = guard_page_handler;
2101     frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
2102     NtCurrentTeb()->Tib.ExceptionList = &frame;
2103 
2104     InterlockedExchange( &num_guard_page_calls, 0 );
2105     InterlockedExchange( &old_value, *value ); /* exception handler increments value by 0x100 */
2106     *value = 2;
2107     ok( old_value == 0x101, "memory block contains wrong value, expected 0x101, got 0x%x\n", old_value );
2108     ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls );
2109 
2110     NtCurrentTeb()->Tib.ExceptionList = frame.Prev;
2111 
2112     /* check info structure again, PAGE_GUARD should be removed now */
2113     ret = VirtualQuery( base, &info, sizeof(info) );
2114     ok( ret, "VirtualQuery failed %u\n", GetLastError());
2115     ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect );
2116 
2117     success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
2118     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2119     ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
2120 
2121     /* test accessing second integer in memory */
2122     frame.Handler = guard_page_handler;
2123     frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
2124     NtCurrentTeb()->Tib.ExceptionList = &frame;
2125 
2126     InterlockedExchange( &num_guard_page_calls, 0 );
2127     old_value = *(value + 1);
2128     ok( old_value == 0x102, "memory block contains wrong value, expected 0x102, got 0x%x\n", old_value );
2129     ok( *value == 2, "memory block contains wrong value, expected 2, got 0x%x\n", *value );
2130     ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls );
2131 
2132     NtCurrentTeb()->Tib.ExceptionList = frame.Prev;
2133 
2134     success = VirtualLock( base, size );
2135     ok( success, "VirtualLock failed %u\n", GetLastError() );
2136     if (success)
2137     {
2138         ok( *value == 2, "memory block contains wrong value, expected 2, got 0x%x\n", *value );
2139         success = VirtualUnlock( base, size );
2140         ok( success, "VirtualUnlock failed %u\n", GetLastError() );
2141     }
2142 
2143     VirtualFree( base, 0, MEM_RELEASE );
2144 
2145     /* combined guard page / write watch tests */
2146     if (!pGetWriteWatch || !pResetWriteWatch)
2147     {
2148         win_skip( "GetWriteWatch not supported, skipping combined guard page / write watch tests\n" );
2149         return;
2150     }
2151 
2152     base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT | MEM_WRITE_WATCH, PAGE_READWRITE | PAGE_GUARD  );
2153     if (!base && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_NOT_SUPPORTED))
2154     {
2155         win_skip( "MEM_WRITE_WATCH not supported\n" );
2156         return;
2157     }
2158     ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
2159     value = (int *)base;
2160 
2161     ret = VirtualQuery( base, &info, sizeof(info) );
2162     ok( ret, "VirtualQuery failed %u\n", GetLastError() );
2163     ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base );
2164     ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "wrong AllocationProtect %x\n", info.AllocationProtect );
2165     ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize );
2166     ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State );
2167     ok( info.Protect == (PAGE_READWRITE | PAGE_GUARD), "wrong Protect 0x%x\n", info.Protect );
2168     ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type );
2169 
2170     count = 64;
2171     ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
2172     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2173     ok( count == 0, "wrong count %lu\n", count );
2174 
2175     /* writing to a page should trigger should trigger guard page, even if write watch is set */
2176     frame.Handler = guard_page_handler;
2177     frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
2178     NtCurrentTeb()->Tib.ExceptionList = &frame;
2179 
2180     InterlockedExchange( &num_guard_page_calls, 0 );
2181     *value       = 1;
2182     *(value + 1) = 2;
2183     ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls );
2184 
2185     NtCurrentTeb()->Tib.ExceptionList = frame.Prev;
2186 
2187     count = 64;
2188     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2189     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2190     ok( count == 1, "wrong count %lu\n", count );
2191     ok( results[0] == base, "wrong result %p\n", results[0] );
2192 
2193     success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
2194     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2195 
2196     /* write watch is triggered from inside of the guard page handler */
2197     frame.Handler = guard_page_handler;
2198     frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
2199     NtCurrentTeb()->Tib.ExceptionList = &frame;
2200 
2201     InterlockedExchange( &num_guard_page_calls, 0 );
2202     old_value = *(value + 1); /* doesn't trigger write watch */
2203     ok( old_value == 0x102, "memory block contains wrong value, expected 0x102, got 0x%x\n", old_value );
2204     ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%x\n", *value );
2205     ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls );
2206 
2207     NtCurrentTeb()->Tib.ExceptionList = frame.Prev;
2208 
2209     count = 64;
2210     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2211     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2212     ok( count == 1, "wrong count %lu\n", count );
2213     ok( results[0] == base, "wrong result %p\n", results[0] );
2214 
2215     success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
2216     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2217 
2218     /* test behaviour of VirtualLock - first attempt should fail without triggering write watches */
2219     SetLastError( 0xdeadbeef );
2220     success = VirtualLock( base, size );
2221     ok( !success, "VirtualLock unexpectedly succeeded\n" );
2222     todo_wine
2223     ok( GetLastError() == STATUS_GUARD_PAGE_VIOLATION, "wrong error %u\n", GetLastError() );
2224 
2225     count = 64;
2226     ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
2227     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2228     ok( count == 0, "wrong count %lu\n", count );
2229 
2230     success = VirtualLock( base, size );
2231     todo_wine
2232     ok( success, "VirtualLock failed %u\n", GetLastError() );
2233     if (success)
2234     {
2235         ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%x\n", *value );
2236         success = VirtualUnlock( base, size );
2237         ok( success, "VirtualUnlock failed %u\n", GetLastError() );
2238     }
2239 
2240     count = 64;
2241     results[0] = (void *)0xdeadbeef;
2242     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2243     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2244     todo_wine
2245     ok( count == 1 || broken(count == 0) /* Windows 8 */, "wrong count %lu\n", count );
2246     todo_wine
2247     ok( results[0] == base || broken(results[0] == (void *)0xdeadbeef) /* Windows 8 */, "wrong result %p\n", results[0] );
2248 
2249     VirtualFree( base, 0, MEM_RELEASE );
2250 }
2251 
2252 static LONG num_execute_fault_calls;
2253 
2254 static DWORD execute_fault_seh_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
2255                                         CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
2256 {
2257     ULONG flags = MEM_EXECUTE_OPTION_ENABLE;
2258     DWORD err;
2259 
2260     trace( "exception: %08x flags:%x addr:%p info[0]:%ld info[1]:%p\n",
2261            rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
2262            rec->ExceptionInformation[0], (void *)rec->ExceptionInformation[1] );
2263 
2264     ok( rec->NumberParameters == 2, "NumberParameters is %d instead of 2\n", rec->NumberParameters );
2265     ok( rec->ExceptionCode == STATUS_ACCESS_VIOLATION || rec->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION,
2266         "ExceptionCode is %08x instead of STATUS_ACCESS_VIOLATION or STATUS_GUARD_PAGE_VIOLATION\n", rec->ExceptionCode );
2267 
2268     NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags), NULL );
2269 
2270     if (rec->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION)
2271     {
2272 
2273         err = IsProcessorFeaturePresent( PF_NX_ENABLED ) ? EXCEPTION_EXECUTE_FAULT : EXCEPTION_READ_FAULT;
2274         ok( rec->ExceptionInformation[0] == err, "ExceptionInformation[0] is %d instead of %d\n",
2275             (DWORD)rec->ExceptionInformation[0], err );
2276 
2277         InterlockedIncrement( &num_guard_page_calls );
2278     }
2279     else if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION)
2280     {
2281         DWORD old_prot;
2282         BOOL success;
2283 
2284         err = (flags & MEM_EXECUTE_OPTION_DISABLE) ? EXCEPTION_EXECUTE_FAULT : EXCEPTION_READ_FAULT;
2285         ok( rec->ExceptionInformation[0] == err, "ExceptionInformation[0] is %d instead of %d\n",
2286             (DWORD)rec->ExceptionInformation[0], err );
2287 
2288         success = VirtualProtect( (void *)rec->ExceptionInformation[1], 16, PAGE_EXECUTE_READWRITE, &old_prot );
2289         ok( success, "VirtualProtect failed %u\n", GetLastError() );
2290         ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
2291 
2292         InterlockedIncrement( &num_execute_fault_calls );
2293     }
2294 
2295     return ExceptionContinueExecution;
2296 }
2297 
2298 static LONG CALLBACK execute_fault_vec_handler( EXCEPTION_POINTERS *ExceptionInfo )
2299 {
2300     PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord;
2301     DWORD old_prot;
2302     BOOL success;
2303 
2304     trace( "exception: %08x flags:%x addr:%p info[0]:%ld info[1]:%p\n",
2305            rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
2306            rec->ExceptionInformation[0], (void *)rec->ExceptionInformation[1] );
2307 
2308     ok( rec->NumberParameters == 2, "NumberParameters is %d instead of 2\n", rec->NumberParameters );
2309     ok( rec->ExceptionCode == STATUS_ACCESS_VIOLATION,
2310         "ExceptionCode is %08x instead of STATUS_ACCESS_VIOLATION\n", rec->ExceptionCode );
2311 
2312     if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION)
2313         InterlockedIncrement( &num_execute_fault_calls );
2314 
2315     if (rec->ExceptionInformation[0] == EXCEPTION_READ_FAULT)
2316         return EXCEPTION_CONTINUE_SEARCH;
2317 
2318     success = VirtualProtect( (void *)rec->ExceptionInformation[1], 16, PAGE_EXECUTE_READWRITE, &old_prot );
2319     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2320     ok( old_prot == PAGE_NOACCESS, "wrong old prot %x\n", old_prot );
2321 
2322     return EXCEPTION_CONTINUE_EXECUTION;
2323 }
2324 
2325 static inline DWORD send_message_excpt( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
2326 {
2327     EXCEPTION_REGISTRATION_RECORD frame;
2328     DWORD ret;
2329 
2330     frame.Handler = execute_fault_seh_handler;
2331     frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
2332     NtCurrentTeb()->Tib.ExceptionList = &frame;
2333 
2334     InterlockedExchange( &num_guard_page_calls, 0 );
2335     InterlockedExchange( &num_execute_fault_calls, 0 );
2336     ret = SendMessageA( hWnd, uMsg, wParam, lParam );
2337 
2338     NtCurrentTeb()->Tib.ExceptionList = frame.Prev;
2339 
2340     return ret;
2341 }
2342 
2343 static inline DWORD call_proc_excpt( DWORD (CALLBACK *code)(void *), void *arg )
2344 {
2345     EXCEPTION_REGISTRATION_RECORD frame;
2346     DWORD ret;
2347 
2348     frame.Handler = execute_fault_seh_handler;
2349     frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
2350     NtCurrentTeb()->Tib.ExceptionList = &frame;
2351 
2352     InterlockedExchange( &num_guard_page_calls, 0 );
2353     InterlockedExchange( &num_execute_fault_calls, 0 );
2354     ret = code( arg );
2355 
2356     NtCurrentTeb()->Tib.ExceptionList = frame.Prev;
2357 
2358     return ret;
2359 }
2360 
2361 static LRESULT CALLBACK jmp_test_func( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
2362 {
2363     if (uMsg == WM_USER)
2364         return 42;
2365 
2366     return DefWindowProcA( hWnd, uMsg, wParam, lParam );
2367 }
2368 
2369 static LRESULT CALLBACK atl_test_func( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
2370 {
2371     DWORD arg = (DWORD)hWnd;
2372     if (uMsg == WM_USER)
2373         ok( arg == 0x11223344, "arg is 0x%08x instead of 0x11223344\n", arg );
2374     else
2375         ok( arg != 0x11223344, "arg is unexpectedly 0x11223344\n" );
2376     return 43;
2377 }
2378 
2379 static DWORD CALLBACK atl5_test_func( void )
2380 {
2381     return 44;
2382 }
2383 
2384 static void test_atl_thunk_emulation( ULONG dep_flags )
2385 {
2386     static const char code_jmp[] = {0xE9, 0x00, 0x00, 0x00, 0x00};
2387     static const char code_atl1[] = {0xC7, 0x44, 0x24, 0x04, 0x44, 0x33, 0x22, 0x11, 0xE9, 0x00, 0x00, 0x00, 0x00};
2388     static const char code_atl2[] = {0xB9, 0x44, 0x33, 0x22, 0x11, 0xE9, 0x00, 0x00, 0x00, 0x00};
2389     static const char code_atl3[] = {0xBA, 0x44, 0x33, 0x22, 0x11, 0xB9, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE1};
2390     static const char code_atl4[] = {0xB9, 0x44, 0x33, 0x22, 0x11, 0xB8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0};
2391     static const char code_atl5[] = {0x59, 0x58, 0x51, 0xFF, 0x60, 0x04};
2392     static const char cls_name[] = "atl_thunk_class";
2393     DWORD ret, size, old_prot;
2394     ULONG old_flags = MEM_EXECUTE_OPTION_ENABLE;
2395     BOOL success, restore_flags = FALSE;
2396     void *results[64];
2397     ULONG_PTR count;
2398     ULONG pagesize;
2399     WNDCLASSEXA wc;
2400     char *base;
2401     HWND hWnd;
2402 
2403     trace( "Running DEP tests with ProcessExecuteFlags = %d\n", dep_flags );
2404 
2405     NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &old_flags, sizeof(old_flags), NULL );
2406     if (old_flags != dep_flags)
2407     {
2408         ret = NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &dep_flags, sizeof(dep_flags) );
2409         if (ret == STATUS_INVALID_INFO_CLASS) /* Windows 2000 */
2410         {
2411             win_skip( "Skipping DEP tests with ProcessExecuteFlags = %d\n", dep_flags );
2412             return;
2413         }
2414         ok( !ret, "NtSetInformationProcess failed with status %08x\n", ret );
2415         restore_flags = TRUE;
2416     }
2417 
2418     size = 0x1000;
2419     base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
2420     ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
2421 
2422     /* Check result of GetProcessDEPPolicy */
2423     if (!pGetProcessDEPPolicy)
2424         win_skip( "GetProcessDEPPolicy not supported\n" );
2425     else
2426     {
2427         BOOL (WINAPI *get_dep_policy)(HANDLE, LPDWORD, PBOOL) = (void *)base;
2428         BOOL policy_permanent = 0xdeadbeef;
2429         DWORD policy_flags = 0xdeadbeef;
2430 
2431         /* GetProcessDEPPolicy crashes on Windows when a NULL pointer is passed.
2432          * Moreover this function has a bug on Windows 8, which has the effect that
2433          * policy_permanent is set to the content of the CL register instead of 0,
2434          * when the policy is not permanent. To detect that we use an assembler
2435          * wrapper to call the function. */
2436 
2437         memcpy( base, code_atl2, sizeof(code_atl2) );
2438         *(DWORD *)(base + 6) = (DWORD_PTR)pGetProcessDEPPolicy - (DWORD_PTR)(base + 10);
2439 
2440         success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot );
2441         ok( success, "VirtualProtect failed %u\n", GetLastError() );
2442 
2443         success = get_dep_policy( GetCurrentProcess(), &policy_flags, &policy_permanent );
2444         ok( success, "GetProcessDEPPolicy failed %u\n", GetLastError() );
2445 
2446         ret = 0;
2447         if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
2448             ret |= PROCESS_DEP_ENABLE;
2449         if (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)
2450             ret |= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION;
2451 
2452         ok( policy_flags == ret, "expected policy flags %d, got %d\n", ret, policy_flags );
2453         ok( !policy_permanent || broken(policy_permanent == 0x44),
2454             "expected policy permanent FALSE, got %d\n", policy_permanent );
2455     }
2456 
2457     memcpy( base, code_jmp, sizeof(code_jmp) );
2458     *(DWORD *)(base + 1) = (DWORD_PTR)jmp_test_func - (DWORD_PTR)(base + 5);
2459 
2460     /* On Windows, the ATL Thunk emulation is only enabled while running WndProc functions,
2461      * whereas in Wine such a limitation doesn't exist yet. We want to test in a scenario
2462      * where it is active, so that application which depend on that still work properly.
2463      * We have no exception handler enabled yet, so give proper EXECUTE permissions to
2464      * prevent crashes while creating the window. */
2465 
2466     success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot );
2467     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2468 
2469     memset( &wc, 0, sizeof(wc) );
2470     wc.cbSize        = sizeof(wc);
2471     wc.style         = CS_VREDRAW | CS_HREDRAW;
2472     wc.hInstance     = GetModuleHandleA( 0 );
2473     wc.hCursor       = LoadCursorA( NULL, (LPCSTR)IDC_ARROW );
2474     wc.hbrBackground = NULL;
2475     wc.lpszClassName = cls_name;
2476     wc.lpfnWndProc   = (WNDPROC)base;
2477     success = RegisterClassExA(&wc) != 0;
2478     ok( success, "RegisterClassExA failed %u\n", GetLastError() );
2479 
2480     hWnd = CreateWindowExA(0, cls_name, "Test", WS_TILEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
2481     ok( hWnd != 0, "CreateWindowExA failed %u\n", GetLastError() );
2482 
2483     ret = SendMessageA(hWnd, WM_USER, 0, 0);
2484     ok( ret == 42, "SendMessage returned unexpected result %d\n", ret );
2485 
2486     /* At first try with an instruction which is not recognized as proper ATL thunk
2487      * by the Windows ATL Thunk Emulator. Removing execute permissions will lead to
2488      * STATUS_ACCESS_VIOLATION exceptions when DEP is enabled. */
2489 
2490     success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2491     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2492 
2493     ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2494     ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
2495     ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2496     if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && !IsProcessorFeaturePresent( PF_NX_ENABLED ))
2497     {
2498         trace( "DEP hardware support is not available\n" );
2499         ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2500         dep_flags = MEM_EXECUTE_OPTION_ENABLE;
2501     }
2502     else if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
2503     {
2504         trace( "DEP hardware support is available\n" );
2505         ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2506     }
2507     else
2508         ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2509 
2510     /* Now a bit more complicated, the page containing the code is protected with
2511      * PAGE_GUARD memory protection. */
2512 
2513     success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
2514     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2515 
2516     ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2517     ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
2518     ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2519     if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
2520         ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2521     else
2522         ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2523 
2524     ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2525     ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
2526     ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2527     ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2528 
2529     /* Now test with a proper ATL thunk instruction. */
2530 
2531     memcpy( base, code_atl1, sizeof(code_atl1) );
2532     *(DWORD *)(base + 9) = (DWORD_PTR)atl_test_func - (DWORD_PTR)(base + 13);
2533 
2534     success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot );
2535     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2536 
2537     ret = SendMessageA(hWnd, WM_USER, 0, 0);
2538     ok( ret == 43, "SendMessage returned unexpected result %d\n", ret );
2539 
2540     /* Try executing with PAGE_READWRITE protection. */
2541 
2542     success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2543     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2544 
2545     ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2546     ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2547     ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2548     if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2549         ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2550     else
2551         ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2552 
2553     /* Now a bit more complicated, the page containing the code is protected with
2554      * PAGE_GUARD memory protection. */
2555 
2556     success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
2557     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2558 
2559     /* the same, but with PAGE_GUARD set */
2560     ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2561     ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2562     ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2563     if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2564         ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2565     else
2566         ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2567 
2568     ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2569     ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2570     ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2571     ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2572 
2573     /* The following test shows that on Windows, even a vectored exception handler
2574      * cannot intercept internal exceptions thrown by the ATL thunk emulation layer. */
2575 
2576     if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && !(dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2577     {
2578         if (pRtlAddVectoredExceptionHandler && pRtlRemoveVectoredExceptionHandler)
2579         {
2580             PVOID vectored_handler;
2581 
2582             success = VirtualProtect( base, size, PAGE_NOACCESS, &old_prot );
2583             ok( success, "VirtualProtect failed %u\n", GetLastError() );
2584 
2585             vectored_handler = pRtlAddVectoredExceptionHandler( TRUE, &execute_fault_vec_handler );
2586             ok( vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n" );
2587 
2588             ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2589 
2590             pRtlRemoveVectoredExceptionHandler( vectored_handler );
2591 
2592             ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2593             ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2594         }
2595         else
2596             win_skip( "RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler not found\n" );
2597     }
2598 
2599     /* Test alternative ATL thunk instructions. */
2600 
2601     memcpy( base, code_atl2, sizeof(code_atl2) );
2602     *(DWORD *)(base + 6) = (DWORD_PTR)atl_test_func - (DWORD_PTR)(base + 10);
2603 
2604     success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2605     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2606 
2607     ret = send_message_excpt( hWnd, WM_USER + 1, 0, 0 );
2608     /* FIXME: we don't check the content of the register ECX yet */
2609     ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2610     ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2611     if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2612         ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2613     else
2614         ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2615 
2616     memcpy( base, code_atl3, sizeof(code_atl3) );
2617     *(DWORD *)(base + 6) = (DWORD_PTR)atl_test_func;
2618 
2619     success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2620     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2621 
2622     ret = send_message_excpt( hWnd, WM_USER + 1, 0, 0 );
2623     /* FIXME: we don't check the content of the registers ECX/EDX yet */
2624     ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2625     ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2626     if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2627         ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2628     else
2629         ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2630 
2631     memcpy( base, code_atl4, sizeof(code_atl4) );
2632     *(DWORD *)(base + 6) = (DWORD_PTR)atl_test_func;
2633 
2634     success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2635     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2636 
2637     ret = send_message_excpt( hWnd, WM_USER + 1, 0, 0 );
2638     /* FIXME: We don't check the content of the registers EAX/ECX yet */
2639     ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2640     ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2641     if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2642         ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2643     else if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
2644         ok( num_execute_fault_calls == 0 || broken(num_execute_fault_calls == 1) /* Windows XP */,
2645             "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2646     else
2647         ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2648 
2649     memcpy( base, code_atl5, sizeof(code_atl5) );
2650 
2651     success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2652     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2653 
2654     ret = (DWORD_PTR)atl5_test_func;
2655     ret = call_proc_excpt( (void *)base, &ret - 1 );
2656     /* FIXME: We don't check the content of the registers EAX/ECX yet */
2657     ok( ret == 44, "call returned wrong result, expected 44, got %d\n", ret );
2658     ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2659     if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2660         ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2661     else if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
2662         ok( num_execute_fault_calls == 0 || broken(num_execute_fault_calls == 1) /* Windows XP */,
2663             "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2664     else
2665         ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2666 
2667     /* Restore the JMP instruction, set to executable, and then destroy the Window */
2668 
2669     memcpy( base, code_jmp, sizeof(code_jmp) );
2670     *(DWORD *)(base + 1) = (DWORD_PTR)jmp_test_func - (DWORD_PTR)(base + 5);
2671 
2672     success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot );
2673     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2674 
2675     DestroyWindow( hWnd );
2676 
2677     success = UnregisterClassA( cls_name, GetModuleHandleA(0) );
2678     ok( success, "UnregisterClass failed %u\n", GetLastError() );
2679 
2680     VirtualFree( base, 0, MEM_RELEASE );
2681 
2682     /* Repeat the tests from above with MEM_WRITE_WATCH protected memory. */
2683 
2684     base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT | MEM_WRITE_WATCH, PAGE_READWRITE  );
2685     if (!base && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_NOT_SUPPORTED))
2686     {
2687         win_skip( "MEM_WRITE_WATCH not supported\n" );
2688         goto out;
2689     }
2690     ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
2691 
2692     count = 64;
2693     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2694     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2695     ok( count == 0, "wrong count %lu\n", count );
2696 
2697     memcpy( base, code_jmp, sizeof(code_jmp) );
2698     *(DWORD *)(base + 1) = (DWORD_PTR)jmp_test_func - (DWORD_PTR)(base + 5);
2699 
2700     count = 64;
2701     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2702     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2703     ok( count == 1, "wrong count %lu\n", count );
2704     ok( results[0] == base, "wrong result %p\n", results[0] );
2705 
2706     /* Create a new window class and associated Window (see above) */
2707 
2708     success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot );
2709     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2710 
2711     memset( &wc, 0, sizeof(wc) );
2712     wc.cbSize        = sizeof(wc);
2713     wc.style         = CS_VREDRAW | CS_HREDRAW;
2714     wc.hInstance     = GetModuleHandleA( 0 );
2715     wc.hCursor       = LoadCursorA( NULL, (LPCSTR)IDC_ARROW );
2716     wc.hbrBackground = NULL;
2717     wc.lpszClassName = cls_name;
2718     wc.lpfnWndProc   = (WNDPROC)base;
2719     success = RegisterClassExA(&wc) != 0;
2720     ok( success, "RegisterClassExA failed %u\n", GetLastError() );
2721 
2722     hWnd = CreateWindowExA(0, cls_name, "Test", WS_TILEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
2723     ok( hWnd != 0, "CreateWindowExA failed %u\n", GetLastError() );
2724 
2725     ret = SendMessageA(hWnd, WM_USER, 0, 0);
2726     ok( ret == 42, "SendMessage returned unexpected result %d\n", ret );
2727 
2728     count = 64;
2729     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2730     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2731     ok( count == 0, "wrong count %lu\n", count );
2732 
2733     /* At first try with an instruction which is not recognized as proper ATL thunk
2734      * by the Windows ATL Thunk Emulator. Removing execute permissions will lead to
2735      * STATUS_ACCESS_VIOLATION exceptions when DEP is enabled. */
2736 
2737     success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2738     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2739 
2740     ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2741     ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
2742     ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2743     if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
2744         ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2745     else
2746         ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2747 
2748     count = 64;
2749     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2750     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2751     ok( count == 0, "wrong count %lu\n", count );
2752 
2753     ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2754     ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
2755     ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2756     ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2757 
2758     /* Now a bit more complicated, the page containing the code is protected with
2759      * PAGE_GUARD memory protection. */
2760 
2761     success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
2762     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2763 
2764     ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2765     ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
2766     ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2767     if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
2768         ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2769     else
2770         ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2771 
2772     ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2773     ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
2774     ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2775     ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2776 
2777     count = 64;
2778     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2779     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2780     ok( count == 0 || broken(count == 1) /* Windows 8 */, "wrong count %lu\n", count );
2781 
2782     /* Now test with a proper ATL thunk instruction. */
2783 
2784     memcpy( base, code_atl1, sizeof(code_atl1) );
2785     *(DWORD *)(base + 9) = (DWORD_PTR)atl_test_func - (DWORD_PTR)(base + 13);
2786 
2787     count = 64;
2788     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2789     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2790     ok( count == 1, "wrong count %lu\n", count );
2791     ok( results[0] == base, "wrong result %p\n", results[0] );
2792 
2793     success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot );
2794     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2795 
2796     ret = SendMessageA(hWnd, WM_USER, 0, 0);
2797     ok( ret == 43, "SendMessage returned unexpected result %d\n", ret );
2798 
2799     /* Try executing with PAGE_READWRITE protection. */
2800 
2801     success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2802     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2803 
2804     ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2805     ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2806     ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2807     if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2808         ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2809     else
2810         ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2811 
2812     count = 64;
2813     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2814     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2815     ok( count == 0, "wrong count %lu\n", count );
2816 
2817     ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2818     ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2819     ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2820     ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2821 
2822     /* Now a bit more complicated, the page containing the code is protected with
2823      * PAGE_GUARD memory protection. */
2824 
2825     success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
2826     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2827 
2828     /* the same, but with PAGE_GUARD set */
2829     ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2830     ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2831     ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2832     if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2833         ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2834     else
2835         ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2836 
2837     ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2838     ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2839     ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2840     ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2841 
2842     count = 64;
2843     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2844     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2845     ok( count == 0 || broken(count == 1) /* Windows 8 */, "wrong count %lu\n", count );
2846 
2847     /* Restore the JMP instruction, set to executable, and then destroy the Window */
2848 
2849     memcpy( base, code_jmp, sizeof(code_jmp) );
2850     *(DWORD *)(base + 1) = (DWORD_PTR)jmp_test_func - (DWORD_PTR)(base + 5);
2851 
2852     count = 64;
2853     ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2854     ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2855     ok( count == 1, "wrong count %lu\n", count );
2856     ok( results[0] == base, "wrong result %p\n", results[0] );
2857 
2858     success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot );
2859     ok( success, "VirtualProtect failed %u\n", GetLastError() );
2860 
2861     DestroyWindow( hWnd );
2862 
2863     success = UnregisterClassA( cls_name, GetModuleHandleA(0) );
2864     ok( success, "UnregisterClass failed %u\n", GetLastError() );
2865 
2866     VirtualFree( base, 0, MEM_RELEASE );
2867 
2868 out:
2869     if (restore_flags)
2870     {
2871         ret = NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &old_flags, sizeof(old_flags) );
2872         ok( !ret, "NtSetInformationProcess failed with status %08x\n", ret );
2873     }
2874 }
2875 
2876 #endif  /* __i386__ */
2877 
2878 static void test_VirtualProtect(void)
2879 {
2880     static const struct test_data
2881     {
2882         DWORD prot_set, prot_get;
2883     } td[] =
2884     {
2885         { 0, 0 }, /* 0x00 */
2886         { PAGE_NOACCESS, PAGE_NOACCESS }, /* 0x01 */
2887         { PAGE_READONLY, PAGE_READONLY }, /* 0x02 */
2888         { PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x03 */
2889         { PAGE_READWRITE, PAGE_READWRITE }, /* 0x04 */
2890         { PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x05 */
2891         { PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x06 */
2892         { PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x07 */
2893         { PAGE_WRITECOPY, 0 }, /* 0x08 */
2894         { PAGE_WRITECOPY | PAGE_NOACCESS, 0 }, /* 0x09 */
2895         { PAGE_WRITECOPY | PAGE_READONLY, 0 }, /* 0x0a */
2896         { PAGE_WRITECOPY | PAGE_NOACCESS | PAGE_READONLY, 0 }, /* 0x0b */
2897         { PAGE_WRITECOPY | PAGE_READWRITE, 0 }, /* 0x0c */
2898         { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x0d */
2899         { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x0e */
2900         { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x0f */
2901 
2902         { PAGE_EXECUTE, PAGE_EXECUTE }, /* 0x10 */
2903         { PAGE_EXECUTE_READ, PAGE_EXECUTE_READ }, /* 0x20 */
2904         { PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x30 */
2905         { PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_READWRITE }, /* 0x40 */
2906         { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0x50 */
2907         { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0x60 */
2908         { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x70 */
2909         { PAGE_EXECUTE_WRITECOPY, 0 }, /* 0x80 */
2910         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE, 0 }, /* 0x90 */
2911         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ, 0 }, /* 0xa0 */
2912         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0xb0 */
2913         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE, 0 }, /* 0xc0 */
2914         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0xd0 */
2915         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0xe0 */
2916         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 } /* 0xf0 */
2917     };
2918     char *base, *ptr;
2919     DWORD ret, old_prot, rw_prot, exec_prot, i, j;
2920     MEMORY_BASIC_INFORMATION info;
2921     SYSTEM_INFO si;
2922     void *addr;
2923     SIZE_T size;
2924     NTSTATUS status;
2925 
2926     GetSystemInfo(&si);
2927     trace("system page size %#x\n", si.dwPageSize);
2928 
2929     SetLastError(0xdeadbeef);
2930     base = VirtualAlloc(0, si.dwPageSize, MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
2931     ok(base != NULL, "VirtualAlloc failed %d\n", GetLastError());
2932 
2933     SetLastError(0xdeadbeef);
2934     ret = VirtualProtect(base, si.dwPageSize, PAGE_READONLY, NULL);
2935     ok(!ret, "VirtualProtect should fail\n");
2936     ok(GetLastError() == ERROR_NOACCESS, "expected ERROR_NOACCESS, got %d\n", GetLastError());
2937     old_prot = 0xdeadbeef;
2938     ret = VirtualProtect(base, si.dwPageSize, PAGE_NOACCESS, &old_prot);
2939     ok(ret, "VirtualProtect failed %d\n", GetLastError());
2940     ok(old_prot == PAGE_NOACCESS, "got %#x != expected PAGE_NOACCESS\n", old_prot);
2941 
2942     addr = base;
2943     size = si.dwPageSize;
2944     status = pNtProtectVirtualMemory(GetCurrentProcess(), &addr, &size, PAGE_READONLY, NULL);
2945     ok(status == STATUS_ACCESS_VIOLATION, "NtProtectVirtualMemory should fail, got %08x\n", status);
2946     addr = base;
2947     size = si.dwPageSize;
2948     old_prot = 0xdeadbeef;
2949     status = pNtProtectVirtualMemory(GetCurrentProcess(), &addr, &size, PAGE_NOACCESS, &old_prot);
2950     ok(status == STATUS_SUCCESS, "NtProtectVirtualMemory should succeed, got %08x\n", status);
2951     ok(old_prot == PAGE_NOACCESS, "got %#x != expected PAGE_NOACCESS\n", old_prot);
2952 
2953     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
2954     {
2955         SetLastError(0xdeadbeef);
2956         ret = VirtualQuery(base, &info, sizeof(info));
2957         ok(ret, "VirtualQuery failed %d\n", GetLastError());
2958         ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base);
2959         ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
2960         ok(info.Protect == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, info.Protect);
2961         ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
2962         ok(info.AllocationProtect == PAGE_NOACCESS, "%d: %#x != PAGE_NOACCESS\n", i, info.AllocationProtect);
2963         ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
2964         ok(info.Type == MEM_PRIVATE, "%d: %#x != MEM_PRIVATE\n", i, info.Type);
2965 
2966         old_prot = 0xdeadbeef;
2967         SetLastError(0xdeadbeef);
2968         ret = VirtualProtect(base, si.dwPageSize, td[i].prot_set, &old_prot);
2969         if (td[i].prot_get)
2970         {
2971             ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
2972             ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
2973 
2974             SetLastError(0xdeadbeef);
2975             ret = VirtualQuery(base, &info, sizeof(info));
2976             ok(ret, "VirtualQuery failed %d\n", GetLastError());
2977             ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base);
2978             ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
2979             ok(info.Protect == td[i].prot_get, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_get);
2980             ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
2981             ok(info.AllocationProtect == PAGE_NOACCESS, "%d: %#x != PAGE_NOACCESS\n", i, info.AllocationProtect);
2982             ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
2983             ok(info.Type == MEM_PRIVATE, "%d: %#x != MEM_PRIVATE\n", i, info.Type);
2984         }
2985         else
2986         {
2987             ok(!ret, "%d: VirtualProtect should fail\n", i);
2988             ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
2989         }
2990 
2991         old_prot = 0xdeadbeef;
2992         SetLastError(0xdeadbeef);
2993         ret = VirtualProtect(base, si.dwPageSize, PAGE_NOACCESS, &old_prot);
2994         ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
2995         if (td[i].prot_get)
2996             ok(old_prot == td[i].prot_get, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_get);
2997         else
2998             ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
2999     }
3000 
3001     exec_prot = 0;
3002 
3003     for (i = 0; i <= 4; i++)
3004     {
3005         rw_prot = 0;
3006 
3007         for (j = 0; j <= 4; j++)
3008         {
3009             DWORD prot = exec_prot | rw_prot;
3010 
3011             SetLastError(0xdeadbeef);
3012             ptr = VirtualAlloc(base, si.dwPageSize, MEM_COMMIT, prot);
3013             if ((rw_prot && exec_prot) || (!rw_prot && !exec_prot))
3014             {
3015                 ok(!ptr, "VirtualAlloc(%02x) should fail\n", prot);
3016                 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3017             }
3018             else
3019             {
3020                 if (prot & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY))
3021                 {
3022                     ok(!ptr, "VirtualAlloc(%02x) should fail\n", prot);
3023                     ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3024                 }
3025                 else
3026                 {
3027                     ok(ptr != NULL, "VirtualAlloc(%02x) error %d\n", prot, GetLastError());
3028                     ok(ptr == base, "expected %p, got %p\n", base, ptr);
3029                 }
3030             }
3031 
3032             SetLastError(0xdeadbeef);
3033             ret = VirtualProtect(base, si.dwPageSize, prot, &old_prot);
3034             if ((rw_prot && exec_prot) || (!rw_prot && !exec_prot))
3035             {
3036                 ok(!ret, "VirtualProtect(%02x) should fail\n", prot);
3037                 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3038             }
3039             else
3040             {
3041                 if (prot & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY))
3042                 {
3043                     ok(!ret, "VirtualProtect(%02x) should fail\n", prot);
3044                     ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3045                 }
3046                 else
3047                     ok(ret, "VirtualProtect(%02x) error %d\n", prot, GetLastError());
3048             }
3049 
3050             rw_prot = 1 << j;
3051         }
3052 
3053         exec_prot = 1 << (i + 4);
3054     }
3055 
3056     VirtualFree(base, 0, MEM_RELEASE);
3057 }
3058 
3059 static BOOL is_mem_writable(DWORD prot)
3060 {
3061     switch (prot & 0xff)
3062     {
3063         case PAGE_READWRITE:
3064         case PAGE_WRITECOPY:
3065         case PAGE_EXECUTE_READWRITE:
3066         case PAGE_EXECUTE_WRITECOPY:
3067             return TRUE;
3068 
3069         default:
3070             return FALSE;
3071     }
3072 }
3073 
3074 static void test_VirtualAlloc_protection(void)
3075 {
3076     static const struct test_data
3077     {
3078         DWORD prot;
3079         BOOL success;
3080     } td[] =
3081     {
3082         { 0, FALSE }, /* 0x00 */
3083         { PAGE_NOACCESS, TRUE }, /* 0x01 */
3084         { PAGE_READONLY, TRUE }, /* 0x02 */
3085         { PAGE_READONLY | PAGE_NOACCESS, FALSE }, /* 0x03 */
3086         { PAGE_READWRITE, TRUE }, /* 0x04 */
3087         { PAGE_READWRITE | PAGE_NOACCESS, FALSE }, /* 0x05 */
3088         { PAGE_READWRITE | PAGE_READONLY, FALSE }, /* 0x06 */
3089         { PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, FALSE }, /* 0x07 */
3090         { PAGE_WRITECOPY, FALSE }, /* 0x08 */
3091         { PAGE_WRITECOPY | PAGE_NOACCESS, FALSE }, /* 0x09 */
3092         { PAGE_WRITECOPY | PAGE_READONLY, FALSE }, /* 0x0a */
3093         { PAGE_WRITECOPY | PAGE_NOACCESS | PAGE_READONLY, FALSE }, /* 0x0b */
3094         { PAGE_WRITECOPY | PAGE_READWRITE, FALSE }, /* 0x0c */
3095         { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_NOACCESS, FALSE }, /* 0x0d */
3096         { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY, FALSE }, /* 0x0e */
3097         { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, FALSE }, /* 0x0f */
3098 
3099         { PAGE_EXECUTE, TRUE }, /* 0x10 */
3100         { PAGE_EXECUTE_READ, TRUE }, /* 0x20 */
3101         { PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE }, /* 0x30 */
3102         { PAGE_EXECUTE_READWRITE, TRUE }, /* 0x40 */
3103         { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, FALSE }, /* 0x50 */
3104         { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, FALSE }, /* 0x60 */
3105         { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE }, /* 0x70 */
3106         { PAGE_EXECUTE_WRITECOPY, FALSE }, /* 0x80 */
3107         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE, FALSE }, /* 0x90 */
3108         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ, FALSE }, /* 0xa0 */
3109         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE }, /* 0xb0 */
3110         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE, FALSE }, /* 0xc0 */
3111         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, FALSE }, /* 0xd0 */
3112         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, FALSE }, /* 0xe0 */
3113         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE } /* 0xf0 */
3114     };
3115     char *base, *ptr;
3116     DWORD ret, i;
3117     MEMORY_BASIC_INFORMATION info;
3118     SYSTEM_INFO si;
3119 
3120     GetSystemInfo(&si);
3121     trace("system page size %#x\n", si.dwPageSize);
3122 
3123     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
3124     {
3125         SetLastError(0xdeadbeef);
3126         base = VirtualAlloc(0, si.dwPageSize, MEM_COMMIT, td[i].prot);
3127 
3128         if (td[i].success)
3129         {
3130             ok(base != NULL, "%d: VirtualAlloc failed %d\n", i, GetLastError());
3131 
3132             SetLastError(0xdeadbeef);
3133             ret = VirtualQuery(base, &info, sizeof(info));
3134             ok(ret, "VirtualQuery failed %d\n", GetLastError());
3135             ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base);
3136             ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
3137             ok(info.Protect == td[i].prot, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot);
3138             ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
3139             ok(info.AllocationProtect == td[i].prot, "%d: %#x != %#x\n", i, info.AllocationProtect, td[i].prot);
3140             ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
3141             ok(info.Type == MEM_PRIVATE, "%d: %#x != MEM_PRIVATE\n", i, info.Type);
3142 
3143             if (is_mem_writable(info.Protect))
3144             {
3145                 base[0] = 0xfe;
3146 
3147                 SetLastError(0xdeadbeef);
3148                 ret = VirtualQuery(base, &info, sizeof(info));
3149                 ok(ret, "VirtualQuery failed %d\n", GetLastError());
3150                 ok(info.Protect == td[i].prot, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot);
3151             }
3152 
3153             SetLastError(0xdeadbeef);
3154             ptr = VirtualAlloc(base, si.dwPageSize, MEM_COMMIT, td[i].prot);
3155             ok(ptr == base, "%d: VirtualAlloc failed %d\n", i, GetLastError());
3156 
3157             VirtualFree(base, 0, MEM_RELEASE);
3158         }
3159         else
3160         {
3161             ok(!base, "%d: VirtualAlloc should fail\n", i);
3162             ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
3163         }
3164     }
3165 }
3166 
3167 static void test_CreateFileMapping_protection(void)
3168 {
3169     static const struct test_data
3170     {
3171         DWORD prot;
3172         BOOL success;
3173         DWORD prot_after_write;
3174     } td[] =
3175     {
3176         { 0, FALSE, 0 }, /* 0x00 */
3177         { PAGE_NOACCESS, FALSE, PAGE_NOACCESS }, /* 0x01 */
3178         { PAGE_READONLY, TRUE, PAGE_READONLY }, /* 0x02 */
3179         { PAGE_READONLY | PAGE_NOACCESS, FALSE, PAGE_NOACCESS }, /* 0x03 */
3180         { PAGE_READWRITE, TRUE, PAGE_READWRITE }, /* 0x04 */
3181         { PAGE_READWRITE | PAGE_NOACCESS, FALSE, PAGE_NOACCESS }, /* 0x05 */
3182         { PAGE_READWRITE | PAGE_READONLY, FALSE, PAGE_NOACCESS }, /* 0x06 */
3183         { PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, FALSE, PAGE_NOACCESS }, /* 0x07 */
3184         { PAGE_WRITECOPY, TRUE, PAGE_READWRITE }, /* 0x08 */
3185         { PAGE_WRITECOPY | PAGE_NOACCESS, FALSE, PAGE_NOACCESS }, /* 0x09 */
3186         { PAGE_WRITECOPY | PAGE_READONLY, FALSE, PAGE_NOACCESS }, /* 0x0a */
3187         { PAGE_WRITECOPY | PAGE_NOACCESS | PAGE_READONLY, FALSE, PAGE_NOACCESS }, /* 0x0b */
3188         { PAGE_WRITECOPY | PAGE_READWRITE, FALSE, PAGE_NOACCESS }, /* 0x0c */
3189         { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_NOACCESS, FALSE, PAGE_NOACCESS }, /* 0x0d */
3190         { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY, FALSE, PAGE_NOACCESS }, /* 0x0e */
3191         { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, FALSE, PAGE_NOACCESS }, /* 0x0f */
3192 
3193         { PAGE_EXECUTE, FALSE, PAGE_EXECUTE }, /* 0x10 */
3194         { PAGE_EXECUTE_READ, TRUE, PAGE_EXECUTE_READ }, /* 0x20 */
3195         { PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE, PAGE_EXECUTE_READ }, /* 0x30 */
3196         { PAGE_EXECUTE_READWRITE, TRUE, PAGE_EXECUTE_READWRITE }, /* 0x40 */
3197         { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, FALSE, PAGE_NOACCESS }, /* 0x50 */
3198         { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, FALSE, PAGE_NOACCESS }, /* 0x60 */
3199         { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE, PAGE_NOACCESS }, /* 0x70 */
3200         { PAGE_EXECUTE_WRITECOPY, TRUE, PAGE_EXECUTE_READWRITE }, /* 0x80 */
3201         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE, FALSE, PAGE_NOACCESS }, /* 0x90 */
3202         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ, FALSE, PAGE_NOACCESS }, /* 0xa0 */
3203         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE, PAGE_NOACCESS }, /* 0xb0 */
3204         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE, FALSE, PAGE_NOACCESS }, /* 0xc0 */
3205         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, FALSE, PAGE_NOACCESS }, /* 0xd0 */
3206         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, FALSE, PAGE_NOACCESS }, /* 0xe0 */
3207         { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE, PAGE_NOACCESS } /* 0xf0 */
3208     };
3209     char *base, *ptr;
3210     DWORD ret, i, alloc_prot, prot, old_prot;
3211     MEMORY_BASIC_INFORMATION info;
3212     SYSTEM_INFO si;
3213     char temp_path[MAX_PATH];
3214     char file_name[MAX_PATH];
3215     HANDLE hfile, hmap;
3216     BOOL page_exec_supported = TRUE;
3217 
3218     GetSystemInfo(&si);
3219     trace("system page size %#x\n", si.dwPageSize);
3220 
3221     GetTempPathA(MAX_PATH, temp_path);
3222     GetTempFileNameA(temp_path, "map", 0, file_name);
3223 
3224     SetLastError(0xdeadbeef);
3225     hfile = CreateFileA(file_name, GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE, 0, NULL, CREATE_ALWAYS, 0, 0);
3226     ok(hfile != INVALID_HANDLE_VALUE, "CreateFile(%s) error %d\n", file_name, GetLastError());
3227     SetFilePointer(hfile, si.dwPageSize, NULL, FILE_BEGIN);
3228     SetEndOfFile(hfile);
3229 
3230     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
3231     {
3232         SetLastError(0xdeadbeef);
3233         hmap = CreateFileMappingW(hfile, NULL, td[i].prot | SEC_COMMIT, 0, si.dwPageSize, NULL);
3234 
3235         if (td[i].success)
3236         {
3237             if (!hmap)
3238             {
3239                 trace("%d: CreateFileMapping(%04x) failed: %d\n", i, td[i].prot, GetLastError());
3240                 /* NT4 and win2k don't support EXEC on file mappings */
3241                 if (td[i].prot == PAGE_EXECUTE_READ || td[i].prot == PAGE_EXECUTE_READWRITE)
3242                 {
3243                     page_exec_supported = FALSE;
3244                     ok(broken(!hmap), "%d: CreateFileMapping doesn't support PAGE_EXECUTE\n", i);
3245                     continue;
3246                 }
3247                 /* Vista+ supports PAGE_EXECUTE_WRITECOPY, earlier versions don't */
3248                 if (td[i].prot == PAGE_EXECUTE_WRITECOPY)
3249                 {
3250                     page_exec_supported = FALSE;
3251                     ok(broken(!hmap), "%d: CreateFileMapping doesn't support PAGE_EXECUTE_WRITECOPY\n", i);
3252                     continue;
3253                 }
3254             }
3255             ok(hmap != 0, "%d: CreateFileMapping(%04x) error %d\n", i, td[i].prot, GetLastError());
3256 
3257             base = MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0);
3258             ok(base != NULL, "%d: MapViewOfFile failed %d\n", i, GetLastError());
3259 
3260             SetLastError(0xdeadbeef);
3261             ret = VirtualQuery(base, &info, sizeof(info));
3262             ok(ret, "VirtualQuery failed %d\n", GetLastError());
3263             ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base);
3264             ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
3265             ok(info.Protect == PAGE_READONLY, "%d: got %#x != expected PAGE_READONLY\n", i, info.Protect);
3266             ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
3267             ok(info.AllocationProtect == PAGE_READONLY, "%d: %#x != PAGE_READONLY\n", i, info.AllocationProtect);
3268             ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
3269             ok(info.Type == MEM_MAPPED, "%d: %#x != MEM_MAPPED\n", i, info.Type);
3270 
3271             if (is_mem_writable(info.Protect))
3272             {
3273                 base[0] = 0xfe;
3274 
3275                 SetLastError(0xdeadbeef);
3276                 ret = VirtualQuery(base, &info, sizeof(info));
3277                 ok(ret, "VirtualQuery failed %d\n", GetLastError());
3278                 ok(info.Protect == td[i].prot, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot);
3279             }
3280 
3281             SetLastError(0xdeadbeef);
3282             ptr = VirtualAlloc(base, si.dwPageSize, MEM_COMMIT, td[i].prot);
3283             ok(!ptr, "%d: VirtualAlloc(%02x) should fail\n", i, td[i].prot);
3284             /* FIXME: remove once Wine is fixed */
3285             todo_wine_if (td[i].prot == PAGE_WRITECOPY || td[i].prot == PAGE_EXECUTE_WRITECOPY)
3286                 ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError());
3287 
3288             SetLastError(0xdeadbeef);
3289             ret = VirtualProtect(base, si.dwPageSize, td[i].prot, &old_prot);
3290             if (td[i].prot == PAGE_READONLY || td[i].prot == PAGE_WRITECOPY)
3291                 ok(ret, "%d: VirtualProtect(%02x) error %d\n", i, td[i].prot, GetLastError());
3292             else
3293             {
3294                 ok(!ret, "%d: VirtualProtect(%02x) should fail\n", i, td[i].prot);
3295                 ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
3296             }
3297 
3298             UnmapViewOfFile(base);
3299             CloseHandle(hmap);
3300         }
3301         else
3302         {
3303             ok(!hmap, "%d: CreateFileMapping should fail\n", i);
3304             ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
3305         }
3306     }
3307 
3308     if (page_exec_supported) alloc_prot = PAGE_EXECUTE_READWRITE;
3309     else alloc_prot = PAGE_READWRITE;
3310     SetLastError(0xdeadbeef);
3311     hmap = CreateFileMappingW(hfile, NULL, alloc_prot, 0, si.dwPageSize, NULL);
3312     ok(hmap != 0, "%d: CreateFileMapping error %d\n", i, GetLastError());
3313 
3314     SetLastError(0xdeadbeef);
3315     base = MapViewOfFile(hmap, FILE_MAP_READ | FILE_MAP_WRITE | (page_exec_supported ? FILE_MAP_EXECUTE : 0), 0, 0, 0);
3316     ok(base != NULL, "MapViewOfFile failed %d\n", GetLastError());
3317 
3318     old_prot = 0xdeadbeef;
3319     SetLastError(0xdeadbeef);
3320     ret = VirtualProtect(base, si.dwPageSize, PAGE_NOACCESS, &old_prot);
3321     ok(ret, "VirtualProtect error %d\n", GetLastError());
3322     ok(old_prot == alloc_prot, "got %#x != expected %#x\n", old_prot, alloc_prot);
3323 
3324     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
3325     {
3326         SetLastError(0xdeadbeef);
3327         ret = VirtualQuery(base, &info, sizeof(info));
3328         ok(ret, "VirtualQuery failed %d\n", GetLastError());
3329         ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base);
3330         ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
3331         ok(info.Protect == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, info.Protect);
3332         ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
3333         ok(info.AllocationProtect == alloc_prot, "%d: %#x != %#x\n", i, info.AllocationProtect, alloc_prot);
3334         ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
3335         ok(info.Type == MEM_MAPPED, "%d: %#x != MEM_MAPPED\n", i, info.Type);
3336 
3337         old_prot = 0xdeadbeef;
3338         SetLastError(0xdeadbeef);
3339         ret = VirtualProtect(base, si.dwPageSize, td[i].prot, &old_prot);
3340         if (td[i].success || td[i].prot == PAGE_NOACCESS || td[i].prot == PAGE_EXECUTE)
3341         {
3342             if (!ret)
3343             {
3344                 /* win2k and XP don't support EXEC on file mappings */
3345                 if (td[i].prot == PAGE_EXECUTE)
3346                 {
3347                     ok(broken(!ret), "%d: VirtualProtect doesn't support PAGE_EXECUTE\n", i);
3348                     continue;
3349                 }
3350                 /* NT4 and win2k don't support EXEC on file mappings */
3351                 if (td[i].prot == PAGE_EXECUTE_READ || td[i].prot == PAGE_EXECUTE_READWRITE)
3352                 {
3353                     ok(broken(!ret), "%d: VirtualProtect doesn't support PAGE_EXECUTE\n", i);
3354                     continue;
3355                 }
3356                 /* Vista+ supports PAGE_EXECUTE_WRITECOPY, earlier versions don't */
3357                 if (td[i].prot == PAGE_EXECUTE_WRITECOPY)
3358                 {
3359                     ok(broken(!ret), "%d: VirtualProtect doesn't support PAGE_EXECUTE_WRITECOPY\n", i);
3360                     continue;
3361                 }
3362             }
3363 
3364             ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
3365             ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
3366 
3367             prot = td[i].prot;
3368             /* looks strange but Windows doesn't do this for PAGE_WRITECOPY */
3369             if (prot == PAGE_EXECUTE_WRITECOPY) prot = PAGE_EXECUTE_READWRITE;
3370 
3371             SetLastError(0xdeadbeef);
3372             ret = VirtualQuery(base, &info, sizeof(info));
3373             ok(ret, "VirtualQuery failed %d\n", GetLastError());
3374             ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base);
3375             ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
3376             /* FIXME: remove the condition below once Wine is fixed */
3377             todo_wine_if (td[i].prot == PAGE_EXECUTE_WRITECOPY)
3378                 ok(info.Protect == prot, "%d: got %#x != expected %#x\n", i, info.Protect, prot);
3379             ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
3380             ok(info.AllocationProtect == alloc_prot, "%d: %#x != %#x\n", i, info.AllocationProtect, alloc_prot);
3381             ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
3382             ok(info.Type == MEM_MAPPED, "%d: %#x != MEM_MAPPED\n", i, info.Type);
3383 
3384             if (is_mem_writable(info.Protect))
3385             {
3386                 base[0] = 0xfe;
3387 
3388                 SetLastError(0xdeadbeef);
3389                 ret = VirtualQuery(base, &info, sizeof(info));
3390                 ok(ret, "VirtualQuery failed %d\n", GetLastError());
3391                 /* FIXME: remove the condition below once Wine is fixed */
3392                 todo_wine_if (td[i].prot == PAGE_WRITECOPY || td[i].prot == PAGE_EXECUTE_WRITECOPY)
3393                     ok(info.Protect == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_after_write);
3394             }
3395         }
3396         else
3397         {
3398             ok(!ret, "%d: VirtualProtect should fail\n", i);
3399             ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
3400             continue;
3401         }
3402 
3403         old_prot = 0xdeadbeef;
3404         SetLastError(0xdeadbeef);
3405         ret = VirtualProtect(base, si.dwPageSize, PAGE_NOACCESS, &old_prot);
3406         ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
3407         /* FIXME: remove the condition below once Wine is fixed */
3408         todo_wine_if (td[i].prot == PAGE_WRITECOPY || td[i].prot == PAGE_EXECUTE_WRITECOPY)
3409             ok(old_prot == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_after_write);
3410     }
3411 
3412     UnmapViewOfFile(base);
3413     CloseHandle(hmap);
3414 
3415     CloseHandle(hfile);
3416     DeleteFileA(file_name);
3417 }
3418 
3419 #define ACCESS_READ      0x01
3420 #define ACCESS_WRITE     0x02
3421 #define ACCESS_EXECUTE   0x04
3422 #define ACCESS_WRITECOPY 0x08
3423 
3424 static DWORD page_prot_to_access(DWORD prot)
3425 {
3426     switch (prot)
3427     {
3428     case PAGE_READWRITE:
3429         return ACCESS_READ | ACCESS_WRITE;
3430 
3431     case PAGE_EXECUTE:
3432     case PAGE_EXECUTE_READ:
3433         return ACCESS_READ | ACCESS_EXECUTE;
3434 
3435     case PAGE_EXECUTE_READWRITE:
3436         return ACCESS_READ | ACCESS_WRITE | ACCESS_WRITECOPY | ACCESS_EXECUTE;
3437 
3438     case PAGE_EXECUTE_WRITECOPY:
3439         return ACCESS_READ | ACCESS_WRITECOPY | ACCESS_EXECUTE;
3440 
3441     case PAGE_READONLY:
3442         return ACCESS_READ;
3443 
3444     case PAGE_WRITECOPY:
3445         return ACCESS_READ;
3446 
3447     default:
3448         return 0;
3449     }
3450 }
3451 
3452 static BOOL is_compatible_protection(DWORD map_prot, DWORD view_prot, DWORD prot)
3453 {
3454     DWORD map_access, view_access, prot_access;
3455 
3456     map_access = page_prot_to_access(map_prot);
3457     view_access = page_prot_to_access(view_prot);
3458     prot_access = page_prot_to_access(prot);
3459 
3460     if (view_access == prot_access) return TRUE;
3461     if (!view_access) return FALSE;
3462 
3463     if ((view_access & prot_access) != prot_access) return FALSE;
3464     if ((map_access & prot_access) == prot_access) return TRUE;
3465 
3466     return FALSE;
3467 }
3468 
3469 static DWORD map_prot_to_access(DWORD prot)
3470 {
3471     switch (prot)
3472     {
3473     case PAGE_READWRITE:
3474     case PAGE_EXECUTE_READWRITE:
3475         return SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE | SECTION_MAP_EXECUTE_EXPLICIT | SECTION_QUERY;
3476     case PAGE_READONLY:
3477     case PAGE_WRITECOPY:
3478     case PAGE_EXECUTE:
3479     case PAGE_EXECUTE_READ:
3480     case PAGE_EXECUTE_WRITECOPY:
3481         return SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_MAP_EXECUTE_EXPLICIT | SECTION_QUERY;
3482     default:
3483         return 0;
3484     }
3485 }
3486 
3487 static BOOL is_compatible_access(DWORD map_prot, DWORD view_prot)
3488 {
3489     DWORD access = map_prot_to_access(map_prot);
3490     if (!view_prot) view_prot = SECTION_MAP_READ;
3491     return (view_prot & access) == view_prot;
3492 }
3493 
3494 static void *map_view_of_file(HANDLE handle, DWORD access)
3495 {
3496     NTSTATUS status;
3497     LARGE_INTEGER offset;
3498     SIZE_T count;
3499     ULONG protect;
3500     BOOL exec;
3501     void *addr;
3502 
3503     if (!pNtMapViewOfSection) return NULL;
3504 
3505     count = 0;
3506     offset.u.LowPart  = 0;
3507     offset.u.HighPart = 0;
3508 
3509     exec = access & FILE_MAP_EXECUTE;
3510     access &= ~FILE_MAP_EXECUTE;
3511 
3512     if (access == FILE_MAP_COPY)
3513     {
3514         if (exec)
3515             protect = PAGE_EXECUTE_WRITECOPY;
3516         else
3517             protect = PAGE_WRITECOPY;
3518     }
3519     else if (access & FILE_MAP_WRITE)
3520     {
3521         if (exec)
3522             protect = PAGE_EXECUTE_READWRITE;
3523         else
3524             protect = PAGE_READWRITE;
3525     }
3526     else if (access & FILE_MAP_READ)
3527     {
3528         if (exec)
3529             protect = PAGE_EXECUTE_READ;
3530         else
3531             protect = PAGE_READONLY;
3532     }
3533     else protect = PAGE_NOACCESS;
3534 
3535     addr = NULL;
3536     status = pNtMapViewOfSection(handle, GetCurrentProcess(), &addr, 0, 0, &offset,
3537                                  &count, 1 /* ViewShare */, 0, protect);
3538     if (status)
3539     {
3540         /* for simplicity */
3541         SetLastError(ERROR_ACCESS_DENIED);
3542         addr = NULL;
3543     }
3544     return addr;
3545 }
3546 
3547 static void test_mapping(void)
3548 {
3549     static const DWORD page_prot[] =
3550     {
3551         PAGE_NOACCESS, PAGE_READONLY, PAGE_READWRITE, PAGE_WRITECOPY,
3552         PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY
3553     };
3554     static const struct
3555     {
3556         DWORD access, prot;
3557     } view[] =
3558     {
3559         { 0, PAGE_NOACCESS }, /* 0x00 */
3560         { FILE_MAP_COPY, PAGE_WRITECOPY }, /* 0x01 */
3561         { FILE_MAP_WRITE, PAGE_READWRITE }, /* 0x02 */
3562         { FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_READWRITE }, /* 0x03 */
3563         { FILE_MAP_READ, PAGE_READONLY }, /* 0x04 */
3564         { FILE_MAP_READ | FILE_MAP_COPY, PAGE_READONLY }, /* 0x05 */
3565         { FILE_MAP_READ | FILE_MAP_WRITE, PAGE_READWRITE }, /* 0x06 */
3566         { FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_READWRITE }, /* 0x07 */
3567         { SECTION_MAP_EXECUTE, PAGE_NOACCESS }, /* 0x08 */
3568         { SECTION_MAP_EXECUTE | FILE_MAP_COPY, PAGE_NOACCESS }, /* 0x09 */
3569         { SECTION_MAP_EXECUTE | FILE_MAP_WRITE, PAGE_READWRITE }, /* 0x0a */
3570         { SECTION_MAP_EXECUTE | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_READWRITE }, /* 0x0b */
3571         { SECTION_MAP_EXECUTE | FILE_MAP_READ, PAGE_READONLY }, /* 0x0c */
3572         { SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_COPY, PAGE_READONLY }, /* 0x0d */
3573         { SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE, PAGE_READWRITE }, /* 0x0e */
3574         { SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_READWRITE }, /* 0x0f */
3575         { FILE_MAP_EXECUTE, PAGE_NOACCESS }, /* 0x20 */
3576         { FILE_MAP_EXECUTE | FILE_MAP_COPY, PAGE_EXECUTE_WRITECOPY }, /* 0x21 */
3577         { FILE_MAP_EXECUTE | FILE_MAP_WRITE, PAGE_EXECUTE_READWRITE }, /* 0x22 */
3578         { FILE_MAP_EXECUTE | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_EXECUTE_READWRITE }, /* 0x23 */
3579         { FILE_MAP_EXECUTE | FILE_MAP_READ, PAGE_EXECUTE_READ }, /* 0x24 */
3580         { FILE_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_COPY, PAGE_EXECUTE_READ }, /* 0x25 */
3581         { FILE_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE, PAGE_EXECUTE_READWRITE }, /* 0x26 */
3582         { FILE_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_EXECUTE_READWRITE }, /* 0x27 */
3583         { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE, PAGE_NOACCESS }, /* 0x28 */
3584         { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_COPY, PAGE_NOACCESS }, /* 0x29 */
3585         { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_WRITE, PAGE_EXECUTE_READWRITE }, /* 0x2a */
3586         { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_EXECUTE_READWRITE }, /* 0x2b */
3587         { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_READ, PAGE_EXECUTE_READ }, /* 0x2c */
3588         { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_COPY, PAGE_EXECUTE_READ }, /* 0x2d */
3589         { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE, PAGE_EXECUTE_READWRITE }, /* 0x2e */
3590         { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_EXECUTE_READWRITE } /* 0x2f */
3591     };
3592     void *base, *nt_base, *ptr;
3593     DWORD i, j, k, ret, old_prot, prev_prot;
3594     SYSTEM_INFO si;
3595     char temp_path[MAX_PATH];
3596     char file_name[MAX_PATH];
3597     HANDLE hfile, hmap;
3598     MEMORY_BASIC_INFORMATION info, nt_info;
3599 
3600     GetSystemInfo(&si);
3601     trace("system page size %#x\n", si.dwPageSize);
3602 
3603     GetTempPathA(MAX_PATH, temp_path);
3604     GetTempFileNameA(temp_path, "map", 0, file_name);
3605 
3606     SetLastError(0xdeadbeef);
3607     hfile = CreateFileA(file_name, GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE, 0, NULL, CREATE_ALWAYS, 0, 0);
3608     ok(hfile != INVALID_HANDLE_VALUE, "CreateFile(%s) error %d\n", file_name, GetLastError());
3609     SetFilePointer(hfile, si.dwPageSize, NULL, FILE_BEGIN);
3610     SetEndOfFile(hfile);
3611 
3612     for (i = 0; i < sizeof(page_prot)/sizeof(page_prot[0]); i++)
3613     {
3614         SetLastError(0xdeadbeef);
3615         hmap = CreateFileMappingW(hfile, NULL, page_prot[i] | SEC_COMMIT, 0, si.dwPageSize, NULL);
3616 
3617         if (page_prot[i] == PAGE_NOACCESS)
3618         {
3619             HANDLE hmap2;
3620 
3621             ok(!hmap, "CreateFileMapping(PAGE_NOACCESS) should fail\n");
3622             ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3623 
3624             /* A trick to create a not accessible mapping */
3625             SetLastError(0xdeadbeef);
3626             hmap = CreateFileMappingW(hfile, NULL, PAGE_READWRITE | SEC_COMMIT, 0, si.dwPageSize, NULL);
3627             ok(hmap != 0, "CreateFileMapping(PAGE_READWRITE) error %d\n", GetLastError());
3628             SetLastError(0xdeadbeef);
3629             ret = DuplicateHandle(GetCurrentProcess(), hmap, GetCurrentProcess(), &hmap2, 0, FALSE, 0);
3630             ok(ret, "DuplicateHandle error %d\n", GetLastError());
3631             CloseHandle(hmap);
3632             hmap = hmap2;
3633         }
3634 
3635         if (!hmap)
3636         {
3637             trace("%d: CreateFileMapping(%04x) failed: %d\n", i, page_prot[i], GetLastError());
3638 
3639             /* NT4 and win2k don't support EXEC on file mappings */
3640             if (page_prot[i] == PAGE_EXECUTE_READ || page_prot[i] == PAGE_EXECUTE_READWRITE)
3641             {
3642                 ok(broken(!hmap), "%d: CreateFileMapping doesn't support PAGE_EXECUTE\n", i);
3643                 continue;
3644             }
3645             /* Vista+ supports PAGE_EXECUTE_WRITECOPY, earlier versions don't */
3646             if (page_prot[i] == PAGE_EXECUTE_WRITECOPY)
3647             {
3648                 ok(broken(!hmap), "%d: CreateFileMapping doesn't support PAGE_EXECUTE_WRITECOPY\n", i);
3649                 continue;
3650             }
3651         }
3652 
3653         ok(hmap != 0, "%d: CreateFileMapping(%04x) error %d\n", i, page_prot[i], GetLastError());
3654 
3655         for (j = 0; j < sizeof(view)/sizeof(view[0]); j++)
3656         {
3657             nt_base = map_view_of_file(hmap, view[j].access);
3658             if (nt_base)
3659             {
3660                 SetLastError(0xdeadbeef);
3661                 ret = VirtualQuery(nt_base, &nt_info, sizeof(nt_info));
3662                 ok(ret, "%d: VirtualQuery failed %d\n", j, GetLastError());
3663                 UnmapViewOfFile(nt_base);
3664             }
3665 
3666             SetLastError(0xdeadbeef);
3667             base = MapViewOfFile(hmap, view[j].access, 0, 0, 0);
3668 
3669             /* Vista+ supports FILE_MAP_EXECUTE properly, earlier versions don't */
3670             ok(!nt_base == !base ||
3671                broken((view[j].access & FILE_MAP_EXECUTE) && !nt_base != !base),
3672                "%d: (%04x/%04x) NT %p kernel %p\n", j, page_prot[i], view[j].access, nt_base, base);
3673 
3674             if (!is_compatible_access(page_prot[i], view[j].access))
3675             {
3676                 ok(!base, "%d: MapViewOfFile(%04x/%04x) should fail\n", j, page_prot[i], view[j].access);
3677                 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
3678                 continue;
3679             }
3680 
3681             /* Vista+ properly supports FILE_MAP_EXECUTE, earlier versions don't */
3682             if (!base && (view[j].access & FILE_MAP_EXECUTE))
3683             {
3684                 ok(broken(!base), "%d: MapViewOfFile(%04x/%04x) failed %d\n", j, page_prot[i], view[j].access, GetLastError());
3685                 continue;
3686             }
3687 
3688             ok(base != NULL, "%d: MapViewOfFile(%04x/%04x) failed %d\n", j, page_prot[i], view[j].access, GetLastError());
3689 
3690             SetLastError(0xdeadbeef);
3691             ret = VirtualQuery(base, &info, sizeof(info));
3692             ok(ret, "%d: VirtualQuery failed %d\n", j, GetLastError());
3693             ok(info.BaseAddress == base, "%d: (%04x) got %p, expected %p\n", j, view[j].access, info.BaseAddress, base);
3694             ok(info.RegionSize == si.dwPageSize, "%d: (%04x) got %#lx != expected %#x\n", j, view[j].access, info.RegionSize, si.dwPageSize);
3695             ok(info.Protect == view[j].prot ||
3696                broken(view[j].prot == PAGE_EXECUTE_READ && info.Protect == PAGE_READONLY) || /* win2k */
3697                broken(view[j].prot == PAGE_EXECUTE_READWRITE && info.Protect == PAGE_READWRITE) || /* win2k */
3698                broken(view[j].prot == PAGE_EXECUTE_WRITECOPY && info.Protect == PAGE_NOACCESS), /* XP */
3699                "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, info.Protect, view[j].prot);
3700             ok(info.AllocationBase == base, "%d: (%04x) got %p, expected %p\n", j, view[j].access, info.AllocationBase, base);
3701             ok(info.AllocationProtect == info.Protect, "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, info.AllocationProtect, info.Protect);
3702             ok(info.State == MEM_COMMIT, "%d: (%04x) got %#x, expected MEM_COMMIT\n", j, view[j].access, info.State);
3703             ok(info.Type == MEM_MAPPED, "%d: (%04x) got %#x, expected MEM_MAPPED\n", j, view[j].access, info.Type);
3704 
3705             if (nt_base && base)
3706             {
3707                 ok(nt_info.RegionSize == info.RegionSize, "%d: (%04x) got %#lx != expected %#lx\n", j, view[j].access, nt_info.RegionSize, info.RegionSize);
3708                 ok(nt_info.Protect == info.Protect /* Vista+ */ ||
3709                    broken(nt_info.AllocationProtect == PAGE_EXECUTE_WRITECOPY && info.Protect == PAGE_NOACCESS), /* XP */
3710                    "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, nt_info.Protect, info.Protect);
3711                 ok(nt_info.AllocationProtect == info.AllocationProtect /* Vista+ */ ||
3712                    broken(nt_info.AllocationProtect == PAGE_EXECUTE_WRITECOPY && info.Protect == PAGE_NOACCESS), /* XP */
3713                    "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, nt_info.AllocationProtect, info.AllocationProtect);
3714                 ok(nt_info.State == info.State, "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, nt_info.State, info.State);
3715                 ok(nt_info.Type == info.Type, "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, nt_info.Type, info.Type);
3716             }
3717 
3718             prev_prot = info.Protect;
3719 
3720             for (k = 0; k < sizeof(page_prot)/sizeof(page_prot[0]); k++)
3721             {
3722                 /*trace("map %#x, view %#x, requested prot %#x\n", page_prot[i], view[j].prot, page_prot[k]);*/
3723                 SetLastError(0xdeadbeef);
3724                 old_prot = 0xdeadbeef;
3725                 ret = VirtualProtect(base, si.dwPageSize, page_prot[k], &old_prot);
3726                 if (is_compatible_protection(page_prot[i], view[j].prot, page_prot[k]))
3727                 {
3728                     /* win2k and XP don't support EXEC on file mappings */
3729                     if (!ret && page_prot[k] == PAGE_EXECUTE)
3730                     {
3731                         ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE\n");
3732                         continue;
3733                     }
3734                     /* NT4 and win2k don't support EXEC on file mappings */
3735                     if (!ret && (page_prot[k] == PAGE_EXECUTE_READ || page_prot[k] == PAGE_EXECUTE_READWRITE))
3736                     {
3737                         ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE\n");
3738                         continue;
3739                     }
3740                     /* Vista+ supports PAGE_EXECUTE_WRITECOPY, earlier versions don't */
3741                     if (!ret && page_prot[k] == PAGE_EXECUTE_WRITECOPY)
3742                     {
3743                         ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE_WRITECOPY\n");
3744                         continue;
3745                     }
3746                     /* win2k and XP don't support PAGE_EXECUTE_WRITECOPY views properly  */
3747                     if (!ret && view[j].prot == PAGE_EXECUTE_WRITECOPY)
3748                     {
3749                         ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE_WRITECOPY view properly\n");
3750                         continue;
3751                     }
3752 
3753                     ok(ret, "VirtualProtect error %d, map %#x, view %#x, requested prot %#x\n", GetLastError(), page_prot[i], view[j].prot, page_prot[k]);
3754                     ok(old_prot == prev_prot, "got %#x, expected %#x\n", old_prot, prev_prot);
3755                     prev_prot = page_prot[k];
3756                 }
3757                 else
3758                 {
3759                     /* NT4 doesn't fail on incompatible map and view */
3760                     if (ret)
3761                     {
3762                         ok(broken(ret), "VirtualProtect should fail, map %#x, view %#x, requested prot %#x\n", page_prot[i], view[j].prot, page_prot[k]);
3763                         skip("Incompatible map and view are not properly handled on this platform\n");
3764                         break; /* NT4 won't pass remaining tests */
3765                     }
3766 
3767                     ok(!ret, "VirtualProtect should fail, map %#x, view %#x, requested prot %#x\n", page_prot[i], view[j].prot, page_prot[k]);
3768                     ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3769                 }
3770             }
3771 
3772             for (k = 0; k < sizeof(page_prot)/sizeof(page_prot[0]); k++)
3773             {
3774                 /*trace("map %#x, view %#x, requested prot %#x\n", page_prot[i], view[j].prot, page_prot[k]);*/
3775                 SetLastError(0xdeadbeef);
3776                 ptr = VirtualAlloc(base, si.dwPageSize, MEM_COMMIT, page_prot[k]);
3777                 ok(!ptr, "VirtualAlloc(%02x) should fail\n", page_prot[k]);
3778                 /* FIXME: remove once Wine is fixed */
3779                 todo_wine_if (page_prot[k] == PAGE_WRITECOPY || page_prot[k] == PAGE_EXECUTE_WRITECOPY)
3780                     ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
3781             }
3782 
3783             UnmapViewOfFile(base);
3784         }
3785 
3786         CloseHandle(hmap);
3787     }
3788 
3789     CloseHandle(hfile);
3790     DeleteFileA(file_name);
3791 }
3792 
3793 static void test_shared_memory(BOOL is_child)
3794 {
3795     HANDLE mapping;
3796     LONG *p;
3797 
3798     SetLastError(0xdeadbef);
3799     mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_virtual.c");
3800     ok(mapping != 0, "CreateFileMapping error %d\n", GetLastError());
3801     if (is_child)
3802         ok(GetLastError() == ERROR_ALREADY_EXISTS, "expected ERROR_ALREADY_EXISTS, got %d\n", GetLastError());
3803 
3804     SetLastError(0xdeadbef);
3805     p = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 4096);
3806     ok(p != NULL, "MapViewOfFile error %d\n", GetLastError());
3807 
3808     if (is_child)
3809     {
3810         ok(*p == 0x1a2b3c4d, "expected 0x1a2b3c4d in child, got %#x\n", *p);
3811     }
3812     else
3813     {
3814         char **argv;
3815         char cmdline[MAX_PATH];
3816         PROCESS_INFORMATION pi;
3817         STARTUPINFOA si = { sizeof(si) };
3818         DWORD ret;
3819 
3820         *p = 0x1a2b3c4d;
3821 
3822         winetest_get_mainargs(&argv);
3823         sprintf(cmdline, "\"%s\" virtual sharedmem", argv[0]);
3824         ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3825         ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
3826         winetest_wait_child_process(pi.hProcess);
3827         CloseHandle(pi.hThread);
3828         CloseHandle(pi.hProcess);
3829     }
3830 
3831     UnmapViewOfFile(p);
3832     CloseHandle(mapping);
3833 }
3834 
3835 static void test_shared_memory_ro(BOOL is_child, DWORD child_access)
3836 {
3837     HANDLE mapping;
3838     LONG *p;
3839 
3840     SetLastError(0xdeadbef);
3841     mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_virtual.c_ro");
3842     ok(mapping != 0, "CreateFileMapping error %d\n", GetLastError());
3843     if (is_child)
3844         ok(GetLastError() == ERROR_ALREADY_EXISTS, "expected ERROR_ALREADY_EXISTS, got %d\n", GetLastError());
3845 
3846     SetLastError(0xdeadbef);
3847     p = MapViewOfFile(mapping, is_child ? child_access : FILE_MAP_READ, 0, 0, 4096);
3848     ok(p != NULL, "MapViewOfFile error %d\n", GetLastError());
3849 
3850     if (is_child)
3851     {
3852         *p = 0xdeadbeef;
3853     }
3854     else
3855     {
3856         char **argv;
3857         char cmdline[MAX_PATH];
3858         PROCESS_INFORMATION pi;
3859         STARTUPINFOA si = { sizeof(si) };
3860         DWORD ret;
3861 
3862         winetest_get_mainargs(&argv);
3863         sprintf(cmdline, "\"%s\" virtual sharedmemro %x", argv[0], child_access);
3864         ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3865         ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
3866         winetest_wait_child_process(pi.hProcess);
3867         CloseHandle(pi.hThread);
3868         CloseHandle(pi.hProcess);
3869 
3870         if(child_access & FILE_MAP_WRITE)
3871             ok(*p == 0xdeadbeef, "*p = %x, expected 0xdeadbeef\n", *p);
3872         else
3873             ok(!*p, "*p = %x, expected 0\n", *p);
3874     }
3875 
3876     UnmapViewOfFile(p);
3877     CloseHandle(mapping);
3878 }
3879 
3880 static void test_NtQuerySection(void)
3881 {
3882     char path[MAX_PATH];
3883     HANDLE file, mapping;
3884     void *p;
3885     NTSTATUS status;
3886     union
3887     {
3888         SECTION_BASIC_INFORMATION basic;
3889         SECTION_IMAGE_INFORMATION image;
3890         char buf[1024];
3891     } info;
3892     IMAGE_NT_HEADERS *nt;
3893     ULONG ret;
3894     SIZE_T fsize, image_size;
3895     SYSTEM_INFO si;
3896 
3897     if (!pNtQuerySection)
3898     {
3899         win_skip("NtQuerySection is not available\n");
3900         return;
3901     }
3902 
3903     GetSystemInfo(&si);
3904     page_mask = si.dwPageSize - 1;
3905 
3906     GetSystemDirectoryA(path, sizeof(path));
3907     strcat(path, "\\kernel32.dll");
3908 
3909     SetLastError(0xdeadbef);
3910     file = CreateFileA(path, GENERIC_READ|GENERIC_EXECUTE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
3911     ok(file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError());
3912 
3913     fsize = GetFileSize(file, NULL);
3914 
3915     SetLastError(0xdeadbef);
3916     mapping = CreateFileMappingA(file, NULL, PAGE_EXECUTE_READ, 0, 0, NULL);
3917     /* NT4 and win2k don't support EXEC on file mappings */
3918     if (!mapping)
3919         mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
3920     ok(mapping != 0, "CreateFileMapping error %u\n", GetLastError());
3921 
3922     status = pNtQuerySection(mapping, SectionBasicInformation, NULL, sizeof(info), &ret);
3923     ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %#x\n", status);
3924 
3925     status = pNtQuerySection(mapping, SectionBasicInformation, &info, 0, NULL);
3926     ok(status == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %#x\n", status);
3927 
3928     status = pNtQuerySection(mapping, SectionBasicInformation, &info, 0, &ret);
3929     ok(status == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %#x\n", status);
3930 
3931     memset(&info, 0x55, sizeof(info));
3932     ret = 0xdeadbeef;
3933     status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret);
3934     ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status);
3935     ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret);
3936     ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress);
3937     ok(info.basic.Attributes == SEC_FILE, "expected SEC_FILE, got %#x\n", info.basic.Attributes);
3938     ok(info.basic.Size.QuadPart == fsize, "expected %#lx, got %#x/%08x\n", fsize, info.basic.Size.HighPart, info.basic.Size.LowPart);
3939 
3940     status = pNtQuerySection(mapping, SectionImageInformation, &info, sizeof(info.basic), &ret);
3941     ok(status == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %#x\n", status);
3942 
3943     status = pNtQuerySection(mapping, SectionImageInformation, &info, sizeof(info), &ret);
3944     ok(status == STATUS_SECTION_NOT_IMAGE, "expected STATUS_SECTION_NOT_IMAGE, got %#x\n", status);
3945 
3946     SetLastError(0xdeadbef);
3947     p = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3948     ok(p != NULL, "MapViewOfFile error %u\n", GetLastError());
3949 
3950     nt = image_nt_header(p);
3951     image_size = ROUND_SIZE(p, nt->OptionalHeader.SizeOfImage);
3952 
3953     memset(&info, 0x55, sizeof(info));
3954     ret = 0xdeadbeef;
3955     status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret);
3956     ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status);
3957     ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret);
3958     ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress);
3959     ok(info.basic.Attributes == SEC_FILE, "expected SEC_FILE, got %#x\n", info.basic.Attributes);
3960     ok(info.basic.Size.QuadPart == fsize, "expected %#lx, got %#x/%08x\n", fsize, info.basic.Size.HighPart, info.basic.Size.LowPart);
3961 
3962     UnmapViewOfFile(p);
3963     CloseHandle(mapping);
3964 
3965     SetLastError(0xdeadbef);
3966     mapping = CreateFileMappingA(file, NULL, PAGE_EXECUTE_READ|SEC_IMAGE, 0, 0, NULL);
3967     /* NT4 and win2k don't support EXEC on file mappings */
3968     if (!mapping)
3969         mapping = CreateFileMappingA(file, NULL, PAGE_READONLY|SEC_IMAGE, 0, 0, NULL);
3970     ok(mapping != 0, "CreateFileMapping error %u\n", GetLastError());
3971 
3972     memset(&info, 0x55, sizeof(info));
3973     ret = 0xdeadbeef;
3974     status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret);
3975     ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status);
3976     ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret);
3977     ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress);
3978     ok(info.basic.Attributes == (SEC_FILE|SEC_IMAGE), "expected SEC_FILE|SEC_IMAGE, got %#x\n", info.basic.Attributes);
3979     ok(info.basic.Size.QuadPart == image_size, "expected %#lx, got %#x/%08x\n", image_size, info.basic.Size.HighPart, info.basic.Size.LowPart);
3980 
3981     status = pNtQuerySection(mapping, SectionImageInformation, NULL, sizeof(info), &ret);
3982     ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got %#x\n", status);
3983 
3984     status = pNtQuerySection(mapping, SectionImageInformation, &info, 0, NULL);
3985     ok(status == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %#x\n", status);
3986 
3987     status = pNtQuerySection(mapping, SectionImageInformation, &info, 0, &ret);
3988     ok(status == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %#x\n", status);
3989 
3990     status = pNtQuerySection(mapping, SectionImageInformation, &info, sizeof(info.basic), &ret);
3991     ok(status == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %#x\n", status);
3992 
3993     SetLastError(0xdeadbef);
3994     p = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3995     ok(p != NULL, "MapViewOfFile error %u\n", GetLastError());
3996 
3997     nt = image_nt_header(p);
3998 
3999     memset(&info, 0x55, sizeof(info));
4000     ret = 0xdeadbeef;
4001     status = pNtQuerySection(mapping, SectionImageInformation, &info, sizeof(info), &ret);
4002     ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status);
4003     ok(ret == sizeof(info.image), "wrong returned size %u\n", ret);
4004     ok((ULONG_PTR)info.image.TransferAddress == nt->OptionalHeader.ImageBase + nt->OptionalHeader.AddressOfEntryPoint,
4005        "expected %#lx, got %p\n", (SIZE_T)(nt->OptionalHeader.ImageBase + nt->OptionalHeader.AddressOfEntryPoint), info.image.TransferAddress);
4006     ok(info.image.ZeroBits == 0, "expected 0, got %#x\n", info.image.ZeroBits);
4007     ok(info.image.MaximumStackSize == nt->OptionalHeader.SizeOfStackReserve, "expected %#lx, got %#lx\n", (SIZE_T)nt->OptionalHeader.SizeOfStackReserve, info.image.MaximumStackSize);
4008     ok(info.image.CommittedStackSize == nt->OptionalHeader.SizeOfStackCommit, "expected %#lx, got %#lx\n", (SIZE_T)nt->OptionalHeader.SizeOfStackCommit, info.image.CommittedStackSize);
4009     ok(info.image.SubSystemType == nt->OptionalHeader.Subsystem, "expected %#x, got %#x\n", nt->OptionalHeader.Subsystem, info.image.SubSystemType);
4010     ok(info.image.SubsystemVersionLow == nt->OptionalHeader.MinorSubsystemVersion, "expected %#x, got %#x\n", nt->OptionalHeader.MinorSubsystemVersion, info.image.SubsystemVersionLow);
4011     ok(info.image.SubsystemVersionHigh == nt->OptionalHeader.MajorSubsystemVersion, "expected %#x, got %#x\n", nt->OptionalHeader.MajorSubsystemVersion, info.image.SubsystemVersionHigh);
4012     ok(info.image.ImageCharacteristics == nt->FileHeader.Characteristics, "expected %#x, got %#x\n", nt->FileHeader.Characteristics, info.image.ImageCharacteristics);
4013     ok(info.image.DllCharacteristics == nt->OptionalHeader.DllCharacteristics, "expected %#x, got %#x\n", nt->OptionalHeader.DllCharacteristics, info.image.DllCharacteristics);
4014     ok(info.image.Machine == nt->FileHeader.Machine, "expected %#x, got %#x\n", nt->FileHeader.Machine, info.image.Machine);
4015 todo_wine
4016     ok(info.image.ImageContainsCode == TRUE, "expected 1, got %#x\n", info.image.ImageContainsCode);
4017 
4018     memset(&info, 0x55, sizeof(info));
4019     ret = 0xdeadbeef;
4020     status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret);
4021     ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status);
4022     ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret);
4023     ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress);
4024     ok(info.basic.Attributes == (SEC_FILE|SEC_IMAGE), "expected SEC_FILE|SEC_IMAGE, got %#x\n", info.basic.Attributes);
4025     ok(info.basic.Size.QuadPart == image_size, "expected %#lx, got %#x/%08x\n", image_size, info.basic.Size.HighPart, info.basic.Size.LowPart);
4026 
4027     UnmapViewOfFile(p);
4028     CloseHandle(mapping);
4029 
4030     SetLastError(0xdeadbef);
4031     mapping = CreateFileMappingA(file, NULL, PAGE_READONLY|SEC_COMMIT|SEC_NOCACHE, 0, 0, NULL);
4032     ok(mapping != 0, "CreateFileMapping error %u\n", GetLastError());
4033 
4034     memset(&info, 0x55, sizeof(info));
4035     ret = 0xdeadbeef;
4036     status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret);
4037     ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status);
4038     ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret);
4039     ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress);
4040 todo_wine
4041     ok(info.basic.Attributes == SEC_FILE, "expected SEC_FILE, got %#x\n", info.basic.Attributes);
4042     ok(info.basic.Size.QuadPart == fsize, "expected %#lx, got %#x/%08x\n", fsize, info.basic.Size.HighPart, info.basic.Size.LowPart);
4043 
4044     CloseHandle(mapping);
4045 
4046     SetLastError(0xdeadbef);
4047     mapping = CreateFileMappingA(file, NULL, PAGE_READONLY|SEC_RESERVE, 0, 0, NULL);
4048     ok(mapping != 0, "CreateFileMapping error %u\n", GetLastError());
4049 
4050     memset(&info, 0x55, sizeof(info));
4051     ret = 0xdeadbeef;
4052     status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret);
4053     ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status);
4054     ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret);
4055     ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress);
4056     ok(info.basic.Attributes == SEC_FILE, "expected SEC_FILE, got %#x\n", info.basic.Attributes);
4057     ok(info.basic.Size.QuadPart == fsize, "expected %#lx, got %#x/%08x\n", fsize, info.basic.Size.HighPart, info.basic.Size.LowPart);
4058 
4059     CloseHandle(mapping);
4060     CloseHandle(file);
4061 
4062     SetLastError(0xdeadbef);
4063     mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE|SEC_COMMIT, 0, 4096, NULL);
4064     ok(mapping != 0, "CreateFileMapping error %u\n", GetLastError());
4065 
4066     memset(&info, 0x55, sizeof(info));
4067     ret = 0xdeadbeef;
4068     status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret);
4069     ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status);
4070     ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret);
4071     ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress);
4072     ok(info.basic.Attributes == SEC_COMMIT, "expected SEC_COMMIT, got %#x\n", info.basic.Attributes);
4073     ok(info.basic.Size.QuadPart == 4096, "expected 4096, got %#x/%08x\n", info.basic.Size.HighPart, info.basic.Size.LowPart);
4074 
4075     SetLastError(0xdeadbef);
4076     p = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 0);
4077     ok(p != NULL, "MapViewOfFile error %u\n", GetLastError());
4078 
4079     memset(&info, 0x55, sizeof(info));
4080     ret = 0xdeadbeef;
4081     status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret);
4082     ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status);
4083     ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret);
4084     ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress);
4085     ok(info.basic.Attributes == SEC_COMMIT, "expected SEC_COMMIT, got %#x\n", info.basic.Attributes);
4086     ok(info.basic.Size.QuadPart == 4096, "expected 4096, got %#x/%08x\n", info.basic.Size.HighPart, info.basic.Size.LowPart);
4087 
4088     UnmapViewOfFile(p);
4089     CloseHandle(mapping);
4090 
4091     SetLastError(0xdeadbef);
4092     mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READONLY|SEC_RESERVE, 0, 4096, NULL);
4093     ok(mapping != 0, "CreateFileMapping error %u\n", GetLastError());
4094 
4095     memset(&info, 0x55, sizeof(info));
4096     ret = 0xdeadbeef;
4097     status = pNtQuerySection(mapping, SectionBasicInformation, &info, sizeof(info), &ret);
4098     ok(status == STATUS_SUCCESS, "NtQuerySection error %#x\n", status);
4099     ok(ret == sizeof(info.basic), "wrong returned size %u\n", ret);
4100     ok(info.basic.BaseAddress == NULL, "expected NULL, got %p\n", info.basic.BaseAddress);
4101     ok(info.basic.Attributes == SEC_RESERVE, "expected SEC_RESERVE, got %#x\n", info.basic.Attributes);
4102     ok(info.basic.Size.QuadPart == 4096, "expected 4096, got %#x/%08x\n", info.basic.Size.HighPart, info.basic.Size.LowPart);
4103 
4104     CloseHandle(mapping);
4105 }
4106 
4107 START_TEST(virtual)
4108 {
4109     int argc;
4110     char **argv;
4111     argc = winetest_get_mainargs( &argv );
4112 
4113     if (argc >= 3)
4114     {
4115         if (!strcmp(argv[2], "sleep"))
4116         {
4117             Sleep(5000); /* spawned process runs for at most 5 seconds */
4118             return;
4119         }
4120         if (!strcmp(argv[2], "sharedmem"))
4121         {
4122             test_shared_memory(TRUE);
4123             return;
4124         }
4125         if (!strcmp(argv[2], "sharedmemro"))
4126         {
4127             test_shared_memory_ro(TRUE, strtol(argv[3], NULL, 16));
4128             return;
4129         }
4130         while (1)
4131         {
4132             void *mem;
4133             BOOL ret;
4134             mem = VirtualAlloc(NULL, 1<<20, MEM_COMMIT|MEM_RESERVE,
4135                                PAGE_EXECUTE_READWRITE);
4136             ok(mem != NULL, "VirtualAlloc failed %u\n", GetLastError());
4137             if (mem == NULL) break;
4138             ret = VirtualFree(mem, 0, MEM_RELEASE);
4139             ok(ret, "VirtualFree failed %u\n", GetLastError());
4140             if (!ret) break;
4141         }
4142         return;
4143     }
4144 
4145     hkernel32 = GetModuleHandleA("kernel32.dll");
4146     hntdll    = GetModuleHandleA("ntdll.dll");
4147 
4148     pVirtualAllocEx = (void *) GetProcAddress(hkernel32, "VirtualAllocEx");
4149     pVirtualFreeEx = (void *) GetProcAddress(hkernel32, "VirtualFreeEx");
4150     pGetWriteWatch = (void *) GetProcAddress(hkernel32, "GetWriteWatch");
4151     pResetWriteWatch = (void *) GetProcAddress(hkernel32, "ResetWriteWatch");
4152     pGetProcessDEPPolicy = (void *)GetProcAddress( hkernel32, "GetProcessDEPPolicy" );
4153     pIsWow64Process = (void *)GetProcAddress( hkernel32, "IsWow64Process" );
4154     pNtAreMappedFilesTheSame = (void *)GetProcAddress( hntdll, "NtAreMappedFilesTheSame" );
4155     pNtCreateSection = (void *)GetProcAddress( hntdll, "NtCreateSection" );
4156     pNtMapViewOfSection = (void *)GetProcAddress( hntdll, "NtMapViewOfSection" );
4157     pNtUnmapViewOfSection = (void *)GetProcAddress( hntdll, "NtUnmapViewOfSection" );
4158     pNtQuerySection = (void *)GetProcAddress( hntdll, "NtQuerySection" );
4159     pRtlAddVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlAddVectoredExceptionHandler" );
4160     pRtlRemoveVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlRemoveVectoredExceptionHandler" );
4161     pNtProtectVirtualMemory = (void *)GetProcAddress( hntdll, "NtProtectVirtualMemory" );
4162     pNtAllocateVirtualMemory = (void *)GetProcAddress( hntdll, "NtAllocateVirtualMemory" );
4163     pNtFreeVirtualMemory = (void *)GetProcAddress( hntdll, "NtFreeVirtualMemory" );
4164 
4165     test_shared_memory(FALSE);
4166     test_shared_memory_ro(FALSE, FILE_MAP_READ|FILE_MAP_WRITE);
4167     test_shared_memory_ro(FALSE, FILE_MAP_COPY);
4168     test_shared_memory_ro(FALSE, FILE_MAP_COPY|FILE_MAP_WRITE);
4169     test_mapping();
4170     test_NtQuerySection();
4171     test_CreateFileMapping_protection();
4172     test_VirtualAlloc_protection();
4173     test_VirtualProtect();
4174     test_VirtualAllocEx();
4175     test_VirtualAlloc();
4176     test_MapViewOfFile();
4177     test_NtMapViewOfSection();
4178     test_NtAreMappedFilesTheSame();
4179     test_CreateFileMapping();
4180     test_IsBadReadPtr();
4181     test_IsBadWritePtr();
4182     test_IsBadCodePtr();
4183     test_write_watch();
4184 #if defined(__i386__) || defined(__x86_64__)
4185     test_stack_commit();
4186 #endif
4187 #ifdef __i386__
4188     test_guard_page();
4189     /* The following tests should be executed as a last step, and in exactly this
4190      * order, since ATL thunk emulation cannot be enabled anymore on Windows. */
4191     test_atl_thunk_emulation( MEM_EXECUTE_OPTION_ENABLE );
4192     test_atl_thunk_emulation( MEM_EXECUTE_OPTION_DISABLE );
4193     test_atl_thunk_emulation( MEM_EXECUTE_OPTION_DISABLE | MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION );
4194 #endif
4195 }
4196