kernel32/tests: Fix a spelling typo in a virtual comment.
[wine.git] / dlls / kernel32 / tests / virtual.c
blob37206b5505af8a7275171cc07227417431071a65
1 /*
2 * Unit test suite for Virtual* family of APIs.
4 * Copyright 2004 Dmitry Timoshkov
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.
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.
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
21 #include <stdarg.h>
22 #include <stdio.h>
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnt.h"
29 #include "winternl.h"
30 #include "winerror.h"
31 #include "winuser.h"
32 #include "excpt.h"
33 #include "wine/test.h"
35 #define NUM_THREADS 4
36 #define MAPPING_SIZE 0x100000
38 static HINSTANCE hkernel32, hntdll;
39 static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
40 static BOOL (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD);
41 static UINT (WINAPI *pGetWriteWatch)(DWORD,LPVOID,SIZE_T,LPVOID*,ULONG_PTR*,ULONG*);
42 static UINT (WINAPI *pResetWriteWatch)(LPVOID,SIZE_T);
43 static NTSTATUS (WINAPI *pNtAreMappedFilesTheSame)(PVOID,PVOID);
44 static NTSTATUS (WINAPI *pNtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG, SIZE_T, const LARGE_INTEGER *, SIZE_T *, ULONG, ULONG, ULONG);
45 static DWORD (WINAPI *pNtUnmapViewOfSection)(HANDLE, PVOID);
46 static PVOID (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG, PVECTORED_EXCEPTION_HANDLER);
47 static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID);
48 static BOOL (WINAPI *pGetProcessDEPPolicy)(HANDLE, LPDWORD, PBOOL);
49 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
50 static NTSTATUS (WINAPI *pNtProtectVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG, ULONG *);
51 static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG, SIZE_T *, ULONG, ULONG);
52 static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG);
54 /* ############################### */
56 static HANDLE create_target_process(const char *arg)
58 char **argv;
59 char cmdline[MAX_PATH];
60 PROCESS_INFORMATION pi;
61 BOOL ret;
62 STARTUPINFOA si = { 0 };
63 si.cb = sizeof(si);
65 winetest_get_mainargs( &argv );
66 sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg);
67 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
68 ok(ret, "error: %u\n", GetLastError());
69 ret = CloseHandle(pi.hThread);
70 ok(ret, "error %u\n", GetLastError());
71 return pi.hProcess;
74 static void test_VirtualAllocEx(void)
76 const unsigned int alloc_size = 1<<15;
77 char *src, *dst;
78 SIZE_T bytes_written = 0, bytes_read = 0, i;
79 void *addr1, *addr2;
80 BOOL b;
81 DWORD old_prot;
82 MEMORY_BASIC_INFORMATION info;
83 HANDLE hProcess;
85 /* not exported in all windows-versions */
86 if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) {
87 win_skip("Virtual{Alloc,Free}Ex not available\n");
88 return;
91 hProcess = create_target_process("sleep");
92 ok(hProcess != NULL, "Can't start process\n");
94 SetLastError(0xdeadbeef);
95 addr1 = pVirtualAllocEx(hProcess, NULL, alloc_size, MEM_COMMIT,
96 PAGE_EXECUTE_READWRITE);
97 if (!addr1 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
98 { /* Win9x */
99 win_skip("VirtualAllocEx not implemented\n");
100 TerminateProcess(hProcess, 0);
101 CloseHandle(hProcess);
102 return;
105 src = VirtualAlloc( NULL, alloc_size, MEM_COMMIT, PAGE_READWRITE );
106 dst = VirtualAlloc( NULL, alloc_size, MEM_COMMIT, PAGE_READWRITE );
107 for (i = 0; i < alloc_size; i++)
108 src[i] = i & 0xff;
110 ok(addr1 != NULL, "VirtualAllocEx error %u\n", GetLastError());
111 b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
112 ok(b && (bytes_written == alloc_size), "%lu bytes written\n",
113 bytes_written);
114 b = ReadProcessMemory(hProcess, addr1, dst, alloc_size, &bytes_read);
115 ok(b && (bytes_read == alloc_size), "%lu bytes read\n", bytes_read);
116 ok(!memcmp(src, dst, alloc_size), "Data from remote process differs\n");
118 /* test invalid source buffers */
120 b = VirtualProtect( src + 0x2000, 0x2000, PAGE_NOACCESS, &old_prot );
121 ok( b, "VirtualProtect failed error %u\n", GetLastError() );
122 b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
123 ok( !b, "WriteProcessMemory succeeded\n" );
124 ok( GetLastError() == ERROR_NOACCESS ||
125 GetLastError() == ERROR_PARTIAL_COPY, /* vista */
126 "wrong error %u\n", GetLastError() );
127 ok( bytes_written == 0, "%lu bytes written\n", bytes_written );
128 b = ReadProcessMemory(hProcess, addr1, src, alloc_size, &bytes_read);
129 ok( !b, "ReadProcessMemory succeeded\n" );
130 ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
131 ok( bytes_read == 0, "%lu bytes written\n", bytes_read );
133 b = VirtualProtect( src, 0x2000, PAGE_NOACCESS, &old_prot );
134 ok( b, "VirtualProtect failed error %u\n", GetLastError() );
135 b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
136 ok( !b, "WriteProcessMemory succeeded\n" );
137 ok( GetLastError() == ERROR_NOACCESS ||
138 GetLastError() == ERROR_PARTIAL_COPY, /* vista */
139 "wrong error %u\n", GetLastError() );
140 ok( bytes_written == 0, "%lu bytes written\n", bytes_written );
141 b = ReadProcessMemory(hProcess, addr1, src, alloc_size, &bytes_read);
142 ok( !b, "ReadProcessMemory succeeded\n" );
143 ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
144 ok( bytes_read == 0, "%lu bytes written\n", bytes_read );
146 b = pVirtualFreeEx(hProcess, addr1, 0, MEM_RELEASE);
147 ok(b != 0, "VirtualFreeEx, error %u\n", GetLastError());
149 VirtualFree( src, 0, MEM_RELEASE );
150 VirtualFree( dst, 0, MEM_RELEASE );
153 * The following tests parallel those in test_VirtualAlloc()
156 SetLastError(0xdeadbeef);
157 addr1 = pVirtualAllocEx(hProcess, 0, 0, MEM_RESERVE, PAGE_NOACCESS);
158 ok(addr1 == NULL, "VirtualAllocEx should fail on zero-sized allocation\n");
159 ok(GetLastError() == ERROR_INVALID_PARAMETER /* NT */ ||
160 GetLastError() == ERROR_NOT_ENOUGH_MEMORY, /* Win9x */
161 "got %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
163 addr1 = pVirtualAllocEx(hProcess, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
164 ok(addr1 != NULL, "VirtualAllocEx failed\n");
166 /* test a not committed memory */
167 memset(&info, 'q', sizeof(info));
168 ok(VirtualQueryEx(hProcess, addr1, &info, sizeof(info)) == sizeof(info), "VirtualQueryEx failed\n");
169 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
170 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
171 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
172 ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
173 ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
174 /* NT reports Protect == 0 for a not committed memory block */
175 ok(info.Protect == 0 /* NT */ ||
176 info.Protect == PAGE_NOACCESS, /* Win9x */
177 "%x != PAGE_NOACCESS\n", info.Protect);
178 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
180 SetLastError(0xdeadbeef);
181 ok(!VirtualProtectEx(hProcess, addr1, 0xFFFC, PAGE_READONLY, &old_prot),
182 "VirtualProtectEx should fail on a not committed memory\n");
183 ok(GetLastError() == ERROR_INVALID_ADDRESS /* NT */ ||
184 GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x */
185 "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError());
187 addr2 = pVirtualAllocEx(hProcess, addr1, 0x1000, MEM_COMMIT, PAGE_NOACCESS);
188 ok(addr1 == addr2, "VirtualAllocEx failed\n");
190 /* test a committed memory */
191 ok(VirtualQueryEx(hProcess, addr1, &info, sizeof(info)) == sizeof(info),
192 "VirtualQueryEx failed\n");
193 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
194 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
195 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
196 ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize);
197 ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State);
198 /* this time NT reports PAGE_NOACCESS as well */
199 ok(info.Protect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.Protect);
200 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
202 /* this should fail, since not the whole range is committed yet */
203 SetLastError(0xdeadbeef);
204 ok(!VirtualProtectEx(hProcess, addr1, 0xFFFC, PAGE_READONLY, &old_prot),
205 "VirtualProtectEx should fail on a not committed memory\n");
206 ok(GetLastError() == ERROR_INVALID_ADDRESS /* NT */ ||
207 GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x */
208 "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError());
210 old_prot = 0;
211 ok(VirtualProtectEx(hProcess, addr1, 0x1000, PAGE_READONLY, &old_prot), "VirtualProtectEx failed\n");
212 ok(old_prot == PAGE_NOACCESS, "wrong old protection: got %04x instead of PAGE_NOACCESS\n", old_prot);
214 old_prot = 0;
215 ok(VirtualProtectEx(hProcess, addr1, 0x1000, PAGE_READWRITE, &old_prot), "VirtualProtectEx failed\n");
216 ok(old_prot == PAGE_READONLY, "wrong old protection: got %04x instead of PAGE_READONLY\n", old_prot);
218 ok(!pVirtualFreeEx(hProcess, addr1, 0x10000, 0),
219 "VirtualFreeEx should fail with type 0\n");
220 ok(GetLastError() == ERROR_INVALID_PARAMETER,
221 "got %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
223 ok(pVirtualFreeEx(hProcess, addr1, 0x10000, MEM_DECOMMIT), "VirtualFreeEx failed\n");
225 /* if the type is MEM_RELEASE, size must be 0 */
226 ok(!pVirtualFreeEx(hProcess, addr1, 1, MEM_RELEASE),
227 "VirtualFreeEx should fail\n");
228 ok(GetLastError() == ERROR_INVALID_PARAMETER,
229 "got %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
231 ok(pVirtualFreeEx(hProcess, addr1, 0, MEM_RELEASE), "VirtualFreeEx failed\n");
233 TerminateProcess(hProcess, 0);
234 CloseHandle(hProcess);
237 static void test_VirtualAlloc(void)
239 void *addr1, *addr2;
240 DWORD old_prot;
241 MEMORY_BASIC_INFORMATION info;
242 NTSTATUS status;
243 SIZE_T size;
245 SetLastError(0xdeadbeef);
246 addr1 = VirtualAlloc(0, 0, MEM_RESERVE, PAGE_NOACCESS);
247 ok(addr1 == NULL, "VirtualAlloc should fail on zero-sized allocation\n");
248 ok(GetLastError() == ERROR_INVALID_PARAMETER /* NT */ ||
249 GetLastError() == ERROR_NOT_ENOUGH_MEMORY, /* Win9x */
250 "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError());
252 addr1 = VirtualAlloc(0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
253 ok(addr1 != NULL, "VirtualAlloc failed\n");
255 /* test a not committed memory */
256 ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info),
257 "VirtualQuery failed\n");
258 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
259 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
260 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
261 ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
262 ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
263 /* NT reports Protect == 0 for a not committed memory block */
264 ok(info.Protect == 0 /* NT */ ||
265 info.Protect == PAGE_NOACCESS, /* Win9x */
266 "%x != PAGE_NOACCESS\n", info.Protect);
267 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
269 SetLastError(0xdeadbeef);
270 ok(!VirtualProtect(addr1, 0xFFFC, PAGE_READONLY, &old_prot),
271 "VirtualProtect should fail on a not committed memory\n");
272 ok(GetLastError() == ERROR_INVALID_ADDRESS /* NT */ ||
273 GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x */
274 "got %d, expected ERROR_INVALID_ADDRESS\n", GetLastError());
276 addr2 = VirtualAlloc(addr1, 0x1000, MEM_COMMIT, PAGE_NOACCESS);
277 ok(addr1 == addr2, "VirtualAlloc failed\n");
279 /* test a committed memory */
280 ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info),
281 "VirtualQuery failed\n");
282 ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
283 ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
284 ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
285 ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize);
286 ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State);
287 /* this time NT reports PAGE_NOACCESS as well */
288 ok(info.Protect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.Protect);
289 ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
291 /* this should fail, since not the whole range is committed yet */
292 SetLastError(0xdeadbeef);
293 ok(!VirtualProtect(addr1, 0xFFFC, PAGE_READONLY, &old_prot),
294 "VirtualProtect should fail on a not committed memory\n");
295 ok(GetLastError() == ERROR_INVALID_ADDRESS /* NT */ ||
296 GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x */
297 "got %d, expected ERROR_INVALID_ADDRESS\n", GetLastError());
299 ok(VirtualProtect(addr1, 0x1000, PAGE_READONLY, &old_prot), "VirtualProtect failed\n");
300 ok(old_prot == PAGE_NOACCESS,
301 "wrong old protection: got %04x instead of PAGE_NOACCESS\n", old_prot);
303 ok(VirtualProtect(addr1, 0x1000, PAGE_READWRITE, &old_prot), "VirtualProtect failed\n");
304 ok(old_prot == PAGE_READONLY,
305 "wrong old protection: got %04x instead of PAGE_READONLY\n", old_prot);
307 ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info),
308 "VirtualQuery failed\n");
309 ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize);
310 ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State);
311 ok(info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect);
312 memset( addr1, 0x55, 20 );
313 ok( *(DWORD *)addr1 == 0x55555555, "wrong data %x\n", *(DWORD *)addr1 );
315 addr2 = VirtualAlloc( addr1, 0x1000, MEM_RESET, PAGE_NOACCESS );
316 ok( addr2 == addr1 || broken( !addr2 && GetLastError() == ERROR_INVALID_PARAMETER), /* win9x */
317 "VirtualAlloc failed err %u\n", GetLastError() );
318 ok( *(DWORD *)addr1 == 0x55555555 || *(DWORD *)addr1 == 0, "wrong data %x\n", *(DWORD *)addr1 );
319 if (addr2)
321 ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info),
322 "VirtualQuery failed\n");
323 ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize);
324 ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State);
325 ok(info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect);
327 addr2 = VirtualAlloc( (char *)addr1 + 0x1000, 0x1000, MEM_RESET, PAGE_NOACCESS );
328 ok( (char *)addr2 == (char *)addr1 + 0x1000, "VirtualAlloc failed\n" );
330 ok(VirtualQuery(addr2, &info, sizeof(info)) == sizeof(info),
331 "VirtualQuery failed\n");
332 ok(info.RegionSize == 0xf000, "%lx != 0xf000\n", info.RegionSize);
333 ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
334 ok(info.Protect == 0, "%x != 0\n", info.Protect);
336 addr2 = VirtualAlloc( (char *)addr1 + 0xf000, 0x2000, MEM_RESET, PAGE_NOACCESS );
337 ok( !addr2, "VirtualAlloc failed\n" );
338 ok( GetLastError() == ERROR_INVALID_ADDRESS, "wrong error %u\n", GetLastError() );
341 /* invalid protection values */
342 SetLastError(0xdeadbeef);
343 addr2 = VirtualAlloc(NULL, 0x1000, MEM_RESERVE, 0);
344 ok(!addr2, "VirtualAlloc succeeded\n");
345 ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());
347 SetLastError(0xdeadbeef);
348 addr2 = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, 0);
349 ok(!addr2, "VirtualAlloc succeeded\n");
350 ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());
352 SetLastError(0xdeadbeef);
353 addr2 = VirtualAlloc(addr1, 0x1000, MEM_COMMIT, PAGE_READONLY | PAGE_EXECUTE);
354 ok(!addr2, "VirtualAlloc succeeded\n");
355 ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());
357 SetLastError(0xdeadbeef);
358 ok(!VirtualProtect(addr1, 0x1000, PAGE_READWRITE | PAGE_EXECUTE_WRITECOPY, &old_prot),
359 "VirtualProtect succeeded\n");
360 ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());
362 SetLastError(0xdeadbeef);
363 ok(!VirtualProtect(addr1, 0x1000, 0, &old_prot), "VirtualProtect succeeded\n");
364 ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());
366 SetLastError(0xdeadbeef);
367 ok(!VirtualFree(addr1, 0x10000, 0), "VirtualFree should fail with type 0\n");
368 ok(GetLastError() == ERROR_INVALID_PARAMETER,
369 "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError());
371 SetLastError(0xdeadbeef);
372 ok(!VirtualFree(addr1, 0, MEM_FREE), "VirtualFree should fail with type MEM_FREE\n");
373 ok(GetLastError() == ERROR_INVALID_PARAMETER,
374 "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError());
376 ok(VirtualFree(addr1, 0x10000, MEM_DECOMMIT), "VirtualFree failed\n");
378 /* if the type is MEM_RELEASE, size must be 0 */
379 ok(!VirtualFree(addr1, 1, MEM_RELEASE), "VirtualFree should fail\n");
380 ok(GetLastError() == ERROR_INVALID_PARAMETER,
381 "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError());
383 ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
385 /* memory returned by VirtualAlloc should be aligned to 64k */
386 addr1 = VirtualAlloc(0, 0x2000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
387 ok(addr1 != NULL, "VirtualAlloc failed\n");
388 ok(!((ULONG_PTR)addr1 & 0xffff), "returned memory %p is not aligned to 64k\n", addr1);
389 ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
390 addr2 = VirtualAlloc(addr1, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
391 ok(addr2 == addr1, "VirtualAlloc returned %p, expected %p\n", addr2, addr1);
393 /* allocation conflicts because of 64k align */
394 size = 0x1000;
395 addr2 = (char *)addr1 + 0x1000;
396 status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 0, &size,
397 MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
398 ok(status == STATUS_CONFLICTING_ADDRESSES, "NtAllocateVirtualMemory returned %08x\n", status);
400 /* it should conflict, even when zero_bits is explicitly set */
401 size = 0x1000;
402 addr2 = (char *)addr1 + 0x1000;
403 status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 12, &size,
404 MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
405 todo_wine
406 ok(status == STATUS_CONFLICTING_ADDRESSES, "NtAllocateVirtualMemory returned %08x\n", status);
407 if (status == STATUS_SUCCESS) ok(VirtualFree(addr2, 0, MEM_RELEASE), "VirtualFree failed\n");
409 /* AT_ROUND_TO_PAGE flag is not supported for VirtualAlloc */
410 SetLastError(0xdeadbeef);
411 addr2 = VirtualAlloc(addr1, 0x1000, MEM_RESERVE | MEM_COMMIT | AT_ROUND_TO_PAGE, PAGE_EXECUTE_READWRITE);
412 ok(!addr2, "VirtualAlloc unexpectedly succeeded\n");
413 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError());
415 /* AT_ROUND_TO_PAGE flag is not supported for NtAllocateVirtualMemory */
416 size = 0x1000;
417 addr2 = (char *)addr1 + 0x1000;
418 status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 0, &size, MEM_RESERVE |
419 MEM_COMMIT | AT_ROUND_TO_PAGE, PAGE_EXECUTE_READWRITE);
420 todo_wine
421 ok(status == STATUS_INVALID_PARAMETER_5, "NtAllocateVirtualMemory returned %08x\n", status);
423 ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
426 static void test_MapViewOfFile(void)
428 static const char testfile[] = "testfile.xxx";
429 const char *name;
430 HANDLE file, mapping, map2;
431 void *ptr, *ptr2, *addr;
432 MEMORY_BASIC_INFORMATION info;
433 BOOL ret;
435 SetLastError(0xdeadbeef);
436 file = CreateFileA( testfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 );
437 ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() );
438 SetFilePointer( file, 4096, NULL, FILE_BEGIN );
439 SetEndOfFile( file );
441 /* read/write mapping */
443 SetLastError(0xdeadbeef);
444 mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
445 ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() );
447 SetLastError(0xdeadbeef);
448 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
449 ok( ptr != NULL, "MapViewOfFile FILE_MAPE_READ error %u\n", GetLastError() );
450 UnmapViewOfFile( ptr );
452 /* this fails on win9x but succeeds on NT */
453 SetLastError(0xdeadbeef);
454 ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 );
455 if (ptr) UnmapViewOfFile( ptr );
456 else ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %d\n", GetLastError() );
458 SetLastError(0xdeadbeef);
459 ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 );
460 ok( ptr != NULL, "MapViewOfFile 0 error %u\n", GetLastError() );
461 UnmapViewOfFile( ptr );
463 SetLastError(0xdeadbeef);
464 ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 );
465 ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() );
466 UnmapViewOfFile( ptr );
468 ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2,
469 FILE_MAP_READ|FILE_MAP_WRITE, FALSE, 0 );
470 ok( ret, "DuplicateHandle failed error %u\n", GetLastError());
471 ptr = MapViewOfFile( map2, FILE_MAP_WRITE, 0, 0, 4096 );
472 ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() );
473 UnmapViewOfFile( ptr );
474 CloseHandle( map2 );
476 ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2,
477 FILE_MAP_READ, FALSE, 0 );
478 ok( ret, "DuplicateHandle failed error %u\n", GetLastError());
479 SetLastError(0xdeadbeef);
480 ptr = MapViewOfFile( map2, FILE_MAP_WRITE, 0, 0, 4096 );
481 if (!ptr)
483 ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
484 CloseHandle( map2 );
485 ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2, 0, FALSE, 0 );
486 ok( ret, "DuplicateHandle failed error %u\n", GetLastError());
487 SetLastError(0xdeadbeef);
488 ptr = MapViewOfFile( map2, 0, 0, 0, 4096 );
489 ok( !ptr, "MapViewOfFile succeeded\n" );
490 ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
491 CloseHandle( map2 );
492 ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2,
493 FILE_MAP_READ, FALSE, 0 );
494 ok( ret, "DuplicateHandle failed error %u\n", GetLastError());
495 ptr = MapViewOfFile( map2, 0, 0, 0, 4096 );
496 ok( ptr != NULL, "MapViewOfFile NO_ACCESS error %u\n", GetLastError() );
498 else win_skip( "no access checks on win9x\n" );
500 UnmapViewOfFile( ptr );
501 CloseHandle( map2 );
502 CloseHandle( mapping );
504 /* read-only mapping */
506 SetLastError(0xdeadbeef);
507 mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL );
508 ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() );
510 SetLastError(0xdeadbeef);
511 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
512 ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
513 UnmapViewOfFile( ptr );
515 /* this fails on win9x but succeeds on NT */
516 SetLastError(0xdeadbeef);
517 ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 );
518 if (ptr) UnmapViewOfFile( ptr );
519 else ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %d\n", GetLastError() );
521 SetLastError(0xdeadbeef);
522 ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 );
523 ok( ptr != NULL, "MapViewOfFile 0 error %u\n", GetLastError() );
524 UnmapViewOfFile( ptr );
526 SetLastError(0xdeadbeef);
527 ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 );
528 ok( !ptr, "MapViewOfFile FILE_MAP_WRITE succeeded\n" );
529 ok( GetLastError() == ERROR_INVALID_PARAMETER ||
530 GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
531 CloseHandle( mapping );
533 /* copy-on-write mapping */
535 SetLastError(0xdeadbeef);
536 mapping = CreateFileMappingA( file, NULL, PAGE_WRITECOPY, 0, 4096, NULL );
537 ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() );
539 SetLastError(0xdeadbeef);
540 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
541 ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
542 UnmapViewOfFile( ptr );
544 SetLastError(0xdeadbeef);
545 ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 );
546 ok( ptr != NULL, "MapViewOfFile FILE_MAP_COPY error %u\n", GetLastError() );
547 UnmapViewOfFile( ptr );
549 SetLastError(0xdeadbeef);
550 ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 );
551 ok( ptr != NULL, "MapViewOfFile 0 error %u\n", GetLastError() );
552 UnmapViewOfFile( ptr );
554 SetLastError(0xdeadbeef);
555 ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 );
556 ok( !ptr, "MapViewOfFile FILE_MAP_WRITE succeeded\n" );
557 ok( GetLastError() == ERROR_INVALID_PARAMETER ||
558 GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
559 CloseHandle( mapping );
561 /* no access mapping */
563 SetLastError(0xdeadbeef);
564 mapping = CreateFileMappingA( file, NULL, PAGE_NOACCESS, 0, 4096, NULL );
565 /* fails on NT but succeeds on win9x */
566 if (!mapping) ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %d\n", GetLastError() );
567 else
569 SetLastError(0xdeadbeef);
570 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
571 ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
572 UnmapViewOfFile( ptr );
574 SetLastError(0xdeadbeef);
575 ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 );
576 ok( !ptr, "MapViewOfFile FILE_MAP_COPY succeeded\n" );
577 ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %d\n", GetLastError() );
579 SetLastError(0xdeadbeef);
580 ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 );
581 ok( ptr != NULL, "MapViewOfFile 0 error %u\n", GetLastError() );
582 UnmapViewOfFile( ptr );
584 SetLastError(0xdeadbeef);
585 ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 );
586 ok( !ptr, "MapViewOfFile FILE_MAP_WRITE succeeded\n" );
587 ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %d\n", GetLastError() );
589 CloseHandle( mapping );
592 CloseHandle( file );
594 /* now try read-only file */
596 SetLastError(0xdeadbeef);
597 file = CreateFileA( testfile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0 );
598 ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() );
600 SetLastError(0xdeadbeef);
601 mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
602 ok( !mapping, "CreateFileMapping PAGE_READWRITE succeeded\n" );
603 ok( GetLastError() == ERROR_INVALID_PARAMETER ||
604 GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
606 SetLastError(0xdeadbeef);
607 mapping = CreateFileMappingA( file, NULL, PAGE_WRITECOPY, 0, 4096, NULL );
608 ok( mapping != 0, "CreateFileMapping PAGE_WRITECOPY error %u\n", GetLastError() );
609 CloseHandle( mapping );
611 SetLastError(0xdeadbeef);
612 mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL );
613 ok( mapping != 0, "CreateFileMapping PAGE_READONLY error %u\n", GetLastError() );
614 CloseHandle( mapping );
615 CloseHandle( file );
617 /* now try no access file */
619 SetLastError(0xdeadbeef);
620 file = CreateFileA( testfile, 0, 0, NULL, OPEN_EXISTING, 0, 0 );
621 ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() );
623 SetLastError(0xdeadbeef);
624 mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
625 ok( !mapping, "CreateFileMapping PAGE_READWRITE succeeded\n" );
626 ok( GetLastError() == ERROR_INVALID_PARAMETER ||
627 GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
629 SetLastError(0xdeadbeef);
630 mapping = CreateFileMappingA( file, NULL, PAGE_WRITECOPY, 0, 4096, NULL );
631 ok( !mapping, "CreateFileMapping PAGE_WRITECOPY succeeded\n" );
632 ok( GetLastError() == ERROR_INVALID_PARAMETER ||
633 GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
635 SetLastError(0xdeadbeef);
636 mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL );
637 ok( !mapping, "CreateFileMapping PAGE_READONLY succeeded\n" );
638 ok( GetLastError() == ERROR_INVALID_PARAMETER ||
639 GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
641 CloseHandle( file );
642 DeleteFileA( testfile );
644 SetLastError(0xdeadbeef);
645 name = "Local\\Foo";
646 file = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, name );
647 /* nt4 doesn't have Local\\ */
648 if (!file && GetLastError() == ERROR_PATH_NOT_FOUND)
650 name = "Foo";
651 file = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, name );
653 ok( file != 0, "CreateFileMapping PAGE_READWRITE error %u\n", GetLastError() );
655 SetLastError(0xdeadbeef);
656 mapping = OpenFileMappingA( FILE_MAP_READ, FALSE, name );
657 ok( mapping != 0, "OpenFileMapping FILE_MAP_READ error %u\n", GetLastError() );
658 SetLastError(0xdeadbeef);
659 ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 );
660 if (!ptr)
662 SIZE_T size;
663 ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
664 SetLastError(0xdeadbeef);
665 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
666 ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
667 SetLastError(0xdeadbeef);
668 size = VirtualQuery( ptr, &info, sizeof(info) );
669 ok( size == sizeof(info),
670 "VirtualQuery error %u\n", GetLastError() );
671 ok( info.BaseAddress == ptr, "%p != %p\n", info.BaseAddress, ptr );
672 ok( info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr );
673 ok( info.AllocationProtect == PAGE_READONLY, "%x != PAGE_READONLY\n", info.AllocationProtect );
674 ok( info.RegionSize == 4096, "%lx != 4096\n", info.RegionSize );
675 ok( info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State );
676 ok( info.Protect == PAGE_READONLY, "%x != PAGE_READONLY\n", info.Protect );
678 else win_skip( "no access checks on win9x\n" );
679 UnmapViewOfFile( ptr );
680 CloseHandle( mapping );
682 SetLastError(0xdeadbeef);
683 mapping = OpenFileMappingA( FILE_MAP_WRITE, FALSE, name );
684 ok( mapping != 0, "OpenFileMapping FILE_MAP_WRITE error %u\n", GetLastError() );
685 SetLastError(0xdeadbeef);
686 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
687 if (!ptr)
689 SIZE_T size;
690 ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
691 SetLastError(0xdeadbeef);
692 ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 );
693 ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() );
694 SetLastError(0xdeadbeef);
695 size = VirtualQuery( ptr, &info, sizeof(info) );
696 ok( size == sizeof(info),
697 "VirtualQuery error %u\n", GetLastError() );
698 ok( info.BaseAddress == ptr, "%p != %p\n", info.BaseAddress, ptr );
699 ok( info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr );
700 ok( info.AllocationProtect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.AllocationProtect );
701 ok( info.RegionSize == 4096, "%lx != 4096\n", info.RegionSize );
702 ok( info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State );
703 ok( info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect );
705 else win_skip( "no access checks on win9x\n" );
706 UnmapViewOfFile( ptr );
707 CloseHandle( mapping );
709 CloseHandle( file );
711 /* read/write mapping with SEC_RESERVE */
712 mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_RESERVE, 0, MAPPING_SIZE, NULL);
713 ok(mapping != INVALID_HANDLE_VALUE, "CreateFileMappingA failed with error %d\n", GetLastError());
715 ptr = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
716 ok(ptr != NULL, "MapViewOfFile failed with error %d\n", GetLastError());
718 ptr2 = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
719 /* on NT ptr != ptr2 but on Win9x ptr == ptr2 */
720 ok(ptr2 != NULL, "MapViewOfFile failed with error %d\n", GetLastError());
721 trace("mapping same section resulted in views %p and %p\n", ptr, ptr2);
723 ret = VirtualQuery(ptr, &info, sizeof(info));
724 ok(ret, "VirtualQuery failed with error %d\n", GetLastError());
725 ok(info.BaseAddress == ptr, "BaseAddress should have been %p but was %p instead\n", ptr, info.BaseAddress);
726 ok(info.AllocationBase == ptr, "AllocationBase should have been %p but was %p instead\n", ptr, info.AllocationBase);
727 ok(info.RegionSize == MAPPING_SIZE, "RegionSize should have been 0x%x but was 0x%lx\n", MAPPING_SIZE, info.RegionSize);
728 ok(info.State == MEM_RESERVE, "State should have been MEM_RESERVE instead of 0x%x\n", info.State);
729 if (info.Type == MEM_PRIVATE) /* win9x is different for uncommitted mappings */
731 ok(info.AllocationProtect == PAGE_NOACCESS,
732 "AllocationProtect should have been PAGE_NOACCESS but was 0x%x\n", info.AllocationProtect);
733 ok(info.Protect == PAGE_NOACCESS,
734 "Protect should have been PAGE_NOACCESS instead of 0x%x\n", info.Protect);
736 else
738 ok(info.AllocationProtect == PAGE_READWRITE,
739 "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect);
740 ok(info.Protect == 0, "Protect should have been 0 instead of 0x%x\n", info.Protect);
741 ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type);
744 if (ptr != ptr2)
746 ret = VirtualQuery(ptr2, &info, sizeof(info));
747 ok(ret, "VirtualQuery failed with error %d\n", GetLastError());
748 ok(info.BaseAddress == ptr2,
749 "BaseAddress should have been %p but was %p instead\n", ptr2, info.BaseAddress);
750 ok(info.AllocationBase == ptr2,
751 "AllocationBase should have been %p but was %p instead\n", ptr2, info.AllocationBase);
752 ok(info.AllocationProtect == PAGE_READWRITE,
753 "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect);
754 ok(info.RegionSize == MAPPING_SIZE,
755 "RegionSize should have been 0x%x but was 0x%lx\n", MAPPING_SIZE, info.RegionSize);
756 ok(info.State == MEM_RESERVE,
757 "State should have been MEM_RESERVE instead of 0x%x\n", info.State);
758 ok(info.Protect == 0,
759 "Protect should have been 0 instead of 0x%x\n", info.Protect);
760 ok(info.Type == MEM_MAPPED,
761 "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type);
764 ptr = VirtualAlloc(ptr, 0x10000, MEM_COMMIT, PAGE_READONLY);
765 ok(ptr != NULL, "VirtualAlloc failed with error %d\n", GetLastError());
767 ret = VirtualQuery(ptr, &info, sizeof(info));
768 ok(ret, "VirtualQuery failed with error %d\n", GetLastError());
769 ok(info.BaseAddress == ptr, "BaseAddress should have been %p but was %p instead\n", ptr, info.BaseAddress);
770 ok(info.AllocationBase == ptr, "AllocationBase should have been %p but was %p instead\n", ptr, info.AllocationBase);
771 ok(info.RegionSize == 0x10000, "RegionSize should have been 0x10000 but was 0x%lx\n", info.RegionSize);
772 ok(info.State == MEM_COMMIT, "State should have been MEM_COMMIT instead of 0x%x\n", info.State);
773 ok(info.Protect == PAGE_READONLY, "Protect should have been PAGE_READONLY instead of 0x%x\n", info.Protect);
774 if (info.Type == MEM_PRIVATE) /* win9x is different for uncommitted mappings */
776 ok(info.AllocationProtect == PAGE_NOACCESS,
777 "AllocationProtect should have been PAGE_NOACCESS but was 0x%x\n", info.AllocationProtect);
779 else
781 ok(info.AllocationProtect == PAGE_READWRITE,
782 "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect);
783 ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type);
786 /* shows that the VirtualAlloc above affects the mapping, not just the
787 * virtual memory in this process - it also affects all other processes
788 * with a view of the mapping, but that isn't tested here */
789 if (ptr != ptr2)
791 ret = VirtualQuery(ptr2, &info, sizeof(info));
792 ok(ret, "VirtualQuery failed with error %d\n", GetLastError());
793 ok(info.BaseAddress == ptr2,
794 "BaseAddress should have been %p but was %p instead\n", ptr2, info.BaseAddress);
795 ok(info.AllocationBase == ptr2,
796 "AllocationBase should have been %p but was %p instead\n", ptr2, info.AllocationBase);
797 ok(info.AllocationProtect == PAGE_READWRITE,
798 "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect);
799 ok(info.RegionSize == 0x10000,
800 "RegionSize should have been 0x10000 but was 0x%lx\n", info.RegionSize);
801 ok(info.State == MEM_COMMIT,
802 "State should have been MEM_COMMIT instead of 0x%x\n", info.State);
803 ok(info.Protect == PAGE_READWRITE,
804 "Protect should have been PAGE_READWRITE instead of 0x%x\n", info.Protect);
805 ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type);
808 addr = VirtualAlloc( ptr, MAPPING_SIZE, MEM_RESET, PAGE_READONLY );
809 ok( addr == ptr || broken(!addr && GetLastError() == ERROR_INVALID_PARAMETER), /* win9x */
810 "VirtualAlloc failed with error %u\n", GetLastError() );
812 ret = VirtualFree( ptr, 0x10000, MEM_DECOMMIT );
813 ok( !ret || broken(ret) /* win9x */, "VirtualFree succeeded\n" );
814 if (!ret)
815 ok( GetLastError() == ERROR_INVALID_PARAMETER, "VirtualFree failed with %u\n", GetLastError() );
817 ret = UnmapViewOfFile(ptr2);
818 ok(ret, "UnmapViewOfFile failed with error %d\n", GetLastError());
819 ret = UnmapViewOfFile(ptr);
820 ok(ret, "UnmapViewOfFile failed with error %d\n", GetLastError());
821 CloseHandle(mapping);
823 addr = VirtualAlloc(NULL, 0x10000, MEM_COMMIT, PAGE_READONLY );
824 ok( addr != NULL, "VirtualAlloc failed with error %u\n", GetLastError() );
826 SetLastError(0xdeadbeef);
827 ok( !UnmapViewOfFile(addr), "UnmapViewOfFile should fail on VirtualAlloc mem\n" );
828 ok( GetLastError() == ERROR_INVALID_ADDRESS,
829 "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError());
830 SetLastError(0xdeadbeef);
831 ok( !UnmapViewOfFile((char *)addr + 0x3000), "UnmapViewOfFile should fail on VirtualAlloc mem\n" );
832 ok( GetLastError() == ERROR_INVALID_ADDRESS,
833 "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError());
834 SetLastError(0xdeadbeef);
835 ok( !UnmapViewOfFile((void *)0xdeadbeef), "UnmapViewOfFile should fail on VirtualAlloc mem\n" );
836 ok( GetLastError() == ERROR_INVALID_ADDRESS,
837 "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError());
839 ok( VirtualFree(addr, 0, MEM_RELEASE), "VirtualFree failed\n" );
841 /* close named mapping handle without unmapping */
842 name = "Foo";
843 SetLastError(0xdeadbeef);
844 mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MAPPING_SIZE, name);
845 ok( mapping != 0, "CreateFileMappingA failed with error %d\n", GetLastError() );
846 SetLastError(0xdeadbeef);
847 ptr = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
848 ok( ptr != NULL, "MapViewOfFile failed with error %d\n", GetLastError() );
849 SetLastError(0xdeadbeef);
850 map2 = OpenFileMappingA(FILE_MAP_READ, FALSE, name);
851 ok( map2 != 0, "OpenFileMappingA failed with error %d\n", GetLastError() );
852 SetLastError(0xdeadbeef);
853 ret = CloseHandle(map2);
854 ok(ret, "CloseHandle error %d\n", GetLastError());
855 SetLastError(0xdeadbeef);
856 ret = CloseHandle(mapping);
857 ok(ret, "CloseHandle error %d\n", GetLastError());
859 ret = IsBadReadPtr(ptr, MAPPING_SIZE);
860 ok( !ret, "memory is not accessible\n" );
862 ret = VirtualQuery(ptr, &info, sizeof(info));
863 ok(ret, "VirtualQuery error %d\n", GetLastError());
864 ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr);
865 ok(info.RegionSize == MAPPING_SIZE, "got %#lx != expected %#x\n", info.RegionSize, MAPPING_SIZE);
866 ok(info.Protect == PAGE_READWRITE, "got %#x != expected PAGE_READWRITE\n", info.Protect);
867 ok(info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr);
868 ok(info.AllocationProtect == PAGE_READWRITE, "%#x != PAGE_READWRITE\n", info.AllocationProtect);
869 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
870 ok(info.Type == MEM_MAPPED, "%#x != MEM_MAPPED\n", info.Type);
872 SetLastError(0xdeadbeef);
873 map2 = OpenFileMappingA(FILE_MAP_READ, FALSE, name);
874 todo_wine
875 ok( map2 == 0, "OpenFileMappingA succeeded\n" );
876 todo_wine
877 ok( GetLastError() == ERROR_FILE_NOT_FOUND, "OpenFileMappingA set error %d\n", GetLastError() );
878 if (map2) CloseHandle(map2); /* FIXME: remove once Wine is fixed */
879 SetLastError(0xdeadbeef);
880 mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MAPPING_SIZE, name);
881 ok( mapping != 0, "CreateFileMappingA failed\n" );
882 todo_wine
883 ok( GetLastError() == ERROR_SUCCESS, "CreateFileMappingA set error %d\n", GetLastError() );
884 SetLastError(0xdeadbeef);
885 ret = CloseHandle(mapping);
886 ok(ret, "CloseHandle error %d\n", GetLastError());
888 ret = IsBadReadPtr(ptr, MAPPING_SIZE);
889 ok( !ret, "memory is not accessible\n" );
891 ret = VirtualQuery(ptr, &info, sizeof(info));
892 ok(ret, "VirtualQuery error %d\n", GetLastError());
893 ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr);
894 ok(info.RegionSize == MAPPING_SIZE, "got %#lx != expected %#x\n", info.RegionSize, MAPPING_SIZE);
895 ok(info.Protect == PAGE_READWRITE, "got %#x != expected PAGE_READWRITE\n", info.Protect);
896 ok(info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr);
897 ok(info.AllocationProtect == PAGE_READWRITE, "%#x != PAGE_READWRITE\n", info.AllocationProtect);
898 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
899 ok(info.Type == MEM_MAPPED, "%#x != MEM_MAPPED\n", info.Type);
901 SetLastError(0xdeadbeef);
902 ret = UnmapViewOfFile(ptr);
903 ok( ret, "UnmapViewOfFile failed with error %d\n", GetLastError() );
905 ret = IsBadReadPtr(ptr, MAPPING_SIZE);
906 ok( ret, "memory is accessible\n" );
908 ret = VirtualQuery(ptr, &info, sizeof(info));
909 ok(ret, "VirtualQuery error %d\n", GetLastError());
910 ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr);
911 ok(info.Protect == PAGE_NOACCESS, "got %#x != expected PAGE_NOACCESS\n", info.Protect);
912 ok(info.AllocationBase == NULL, "%p != NULL\n", info.AllocationBase);
913 ok(info.AllocationProtect == 0, "%#x != 0\n", info.AllocationProtect);
914 ok(info.State == MEM_FREE, "%#x != MEM_FREE\n", info.State);
915 ok(info.Type == 0, "%#x != 0\n", info.Type);
917 SetLastError(0xdeadbeef);
918 file = CreateFileA(testfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
919 ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() );
920 SetFilePointer(file, 4096, NULL, FILE_BEGIN);
921 SetEndOfFile(file);
923 SetLastError(0xdeadbeef);
924 mapping = CreateFileMappingA(file, NULL, PAGE_READWRITE, 0, MAPPING_SIZE, name);
925 ok( mapping != 0, "CreateFileMappingA failed with error %d\n", GetLastError() );
926 SetLastError(0xdeadbeef);
927 ptr = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
928 ok( ptr != NULL, "MapViewOfFile failed with error %d\n", GetLastError() );
929 SetLastError(0xdeadbeef);
930 map2 = OpenFileMappingA(FILE_MAP_READ, FALSE, name);
931 ok( map2 != 0, "OpenFileMappingA failed with error %d\n", GetLastError() );
932 SetLastError(0xdeadbeef);
933 ret = CloseHandle(map2);
934 ok(ret, "CloseHandle error %d\n", GetLastError());
935 SetLastError(0xdeadbeef);
936 ret = CloseHandle(mapping);
937 ok(ret, "CloseHandle error %d\n", GetLastError());
939 ret = IsBadReadPtr(ptr, MAPPING_SIZE);
940 ok( !ret, "memory is not accessible\n" );
942 ret = VirtualQuery(ptr, &info, sizeof(info));
943 ok(ret, "VirtualQuery error %d\n", GetLastError());
944 ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr);
945 ok(info.RegionSize == MAPPING_SIZE, "got %#lx != expected %#x\n", info.RegionSize, MAPPING_SIZE);
946 ok(info.Protect == PAGE_READWRITE, "got %#x != expected PAGE_READWRITE\n", info.Protect);
947 ok(info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr);
948 ok(info.AllocationProtect == PAGE_READWRITE, "%#x != PAGE_READWRITE\n", info.AllocationProtect);
949 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
950 ok(info.Type == MEM_MAPPED, "%#x != MEM_MAPPED\n", info.Type);
952 SetLastError(0xdeadbeef);
953 map2 = OpenFileMappingA(FILE_MAP_READ, FALSE, name);
954 todo_wine
955 ok( map2 == 0, "OpenFileMappingA succeeded\n" );
956 todo_wine
957 ok( GetLastError() == ERROR_FILE_NOT_FOUND, "OpenFileMappingA set error %d\n", GetLastError() );
958 CloseHandle(map2);
959 SetLastError(0xdeadbeef);
960 mapping = CreateFileMappingA(file, NULL, PAGE_READWRITE, 0, MAPPING_SIZE, name);
961 ok( mapping != 0, "CreateFileMappingA failed\n" );
962 todo_wine
963 ok( GetLastError() == ERROR_SUCCESS, "CreateFileMappingA set error %d\n", GetLastError() );
964 SetLastError(0xdeadbeef);
965 ret = CloseHandle(mapping);
966 ok(ret, "CloseHandle error %d\n", GetLastError());
968 ret = IsBadReadPtr(ptr, MAPPING_SIZE);
969 ok( !ret, "memory is not accessible\n" );
971 ret = VirtualQuery(ptr, &info, sizeof(info));
972 ok(ret, "VirtualQuery error %d\n", GetLastError());
973 ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr);
974 ok(info.RegionSize == MAPPING_SIZE, "got %#lx != expected %#x\n", info.RegionSize, MAPPING_SIZE);
975 ok(info.Protect == PAGE_READWRITE, "got %#x != expected PAGE_READWRITE\n", info.Protect);
976 ok(info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr);
977 ok(info.AllocationProtect == PAGE_READWRITE, "%#x != PAGE_READWRITE\n", info.AllocationProtect);
978 ok(info.State == MEM_COMMIT, "%#x != MEM_COMMIT\n", info.State);
979 ok(info.Type == MEM_MAPPED, "%#x != MEM_MAPPED\n", info.Type);
981 SetLastError(0xdeadbeef);
982 ret = UnmapViewOfFile(ptr);
983 ok( ret, "UnmapViewOfFile failed with error %d\n", GetLastError() );
985 ret = IsBadReadPtr(ptr, MAPPING_SIZE);
986 ok( ret, "memory is accessible\n" );
988 ret = VirtualQuery(ptr, &info, sizeof(info));
989 ok(ret, "VirtualQuery error %d\n", GetLastError());
990 ok(info.BaseAddress == ptr, "got %p != expected %p\n", info.BaseAddress, ptr);
991 ok(info.Protect == PAGE_NOACCESS, "got %#x != expected PAGE_NOACCESS\n", info.Protect);
992 ok(info.AllocationBase == NULL, "%p != NULL\n", info.AllocationBase);
993 ok(info.AllocationProtect == 0, "%#x != 0\n", info.AllocationProtect);
994 ok(info.State == MEM_FREE, "%#x != MEM_FREE\n", info.State);
995 ok(info.Type == 0, "%#x != 0\n", info.Type);
997 CloseHandle(file);
998 DeleteFileA(testfile);
1001 static void test_NtMapViewOfSection(void)
1003 HANDLE hProcess;
1005 static const char testfile[] = "testfile.xxx";
1006 static const char data[] = "test data for NtMapViewOfSection";
1007 char buffer[sizeof(data)];
1008 HANDLE file, mapping;
1009 void *ptr, *ptr2;
1010 BOOL is_wow64, ret;
1011 DWORD status, written;
1012 SIZE_T size, result;
1013 LARGE_INTEGER offset;
1015 if (!pNtMapViewOfSection || !pNtUnmapViewOfSection)
1017 win_skip( "NtMapViewOfSection not available\n" );
1018 return;
1021 file = CreateFileA( testfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 );
1022 ok( file != INVALID_HANDLE_VALUE, "Failed to create test file\n" );
1023 WriteFile( file, data, sizeof(data), &written, NULL );
1024 SetFilePointer( file, 4096, NULL, FILE_BEGIN );
1025 SetEndOfFile( file );
1027 /* read/write mapping */
1029 mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
1030 ok( mapping != 0, "CreateFileMapping failed\n" );
1032 hProcess = create_target_process("sleep");
1033 ok(hProcess != NULL, "Can't start process\n");
1035 ptr = NULL;
1036 size = 0;
1037 offset.QuadPart = 0;
1038 status = pNtMapViewOfSection( mapping, hProcess, &ptr, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1039 ok( !status, "NtMapViewOfSection failed status %x\n", status );
1040 ok( !((ULONG_PTR)ptr & 0xffff), "returned memory %p is not aligned to 64k\n", ptr );
1042 ret = ReadProcessMemory( hProcess, ptr, buffer, sizeof(buffer), &result );
1043 ok( ret, "ReadProcessMemory failed\n" );
1044 ok( result == sizeof(buffer), "ReadProcessMemory didn't read all data (%lx)\n", result );
1045 ok( !memcmp( buffer, data, sizeof(buffer) ), "Wrong data read\n" );
1047 /* for some unknown reason NtMapViewOfSection fails with STATUS_NO_MEMORY when zero_bits != 0 ? */
1048 ptr2 = NULL;
1049 size = 0;
1050 offset.QuadPart = 0;
1051 status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 12, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1052 todo_wine
1053 ok( status == STATUS_NO_MEMORY, "NtMapViewOfSection returned %x\n", status );
1054 if (status == STATUS_SUCCESS)
1056 status = pNtUnmapViewOfSection( hProcess, ptr2 );
1057 ok( !status, "NtUnmapViewOfSection failed status %x\n", status );
1060 ptr2 = NULL;
1061 size = 0;
1062 status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 16, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1063 todo_wine
1064 ok( status == STATUS_NO_MEMORY, "NtMapViewOfSection returned %x\n", status );
1065 if (status == STATUS_SUCCESS)
1067 status = pNtUnmapViewOfSection( hProcess, ptr2 );
1068 ok( !status, "NtUnmapViewOfSection failed status %x\n", status );
1071 /* mapping at the same page conflicts */
1072 ptr2 = ptr;
1073 size = 0;
1074 offset.QuadPart = 0;
1075 status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1076 ok( status == STATUS_CONFLICTING_ADDRESSES, "NtMapViewOfSection returned %x\n", status );
1078 /* offset has to be aligned */
1079 ptr2 = ptr;
1080 size = 0;
1081 offset.QuadPart = 1;
1082 status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1083 ok( status == STATUS_MAPPED_ALIGNMENT, "NtMapViewOfSection returned %x\n", status );
1085 /* ptr has to be aligned */
1086 ptr2 = (char *)ptr + 42;
1087 size = 0;
1088 offset.QuadPart = 0;
1089 status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1090 ok( status == STATUS_MAPPED_ALIGNMENT, "NtMapViewOfSection returned %x\n", status );
1092 /* still not 64k aligned */
1093 ptr2 = (char *)ptr + 0x1000;
1094 size = 0;
1095 offset.QuadPart = 0;
1096 status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1097 ok( status == STATUS_MAPPED_ALIGNMENT, "NtMapViewOfSection returned %x\n", status );
1099 /* zero_bits != 0 is not allowed when an address is set */
1100 ptr2 = (char *)ptr + 0x1000;
1101 size = 0;
1102 offset.QuadPart = 0;
1103 status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 12, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1104 ok( status == STATUS_INVALID_PARAMETER_4, "NtMapViewOfSection returned %x\n", status );
1106 ptr2 = (char *)ptr + 0x1000;
1107 size = 0;
1108 offset.QuadPart = 0;
1109 status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 16, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1110 ok( status == STATUS_INVALID_PARAMETER_4, "NtMapViewOfSection returned %x\n", status );
1112 ptr2 = (char *)ptr + 0x1001;
1113 size = 0;
1114 offset.QuadPart = 0;
1115 status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 16, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1116 ok( status == STATUS_INVALID_PARAMETER_4, "NtMapViewOfSection returned %x\n", status );
1118 ptr2 = (char *)ptr + 0x1000;
1119 size = 0;
1120 offset.QuadPart = 1;
1121 status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 16, 0, &offset, &size, 1, 0, PAGE_READWRITE );
1122 ok( status == STATUS_INVALID_PARAMETER_4, "NtMapViewOfSection returned %x\n", status );
1124 if (sizeof(void *) == sizeof(int) && (!pIsWow64Process ||
1125 !pIsWow64Process( GetCurrentProcess(), &is_wow64 ) || !is_wow64))
1127 /* new memory region conflicts with previous mapping */
1128 ptr2 = ptr;
1129 size = 0;
1130 offset.QuadPart = 0;
1131 status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset,
1132 &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE );
1133 ok( status == STATUS_CONFLICTING_ADDRESSES, "NtMapViewOfSection returned %x\n", status );
1135 ptr2 = (char *)ptr + 42;
1136 size = 0;
1137 offset.QuadPart = 0;
1138 status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset,
1139 &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE );
1140 ok( status == STATUS_CONFLICTING_ADDRESSES, "NtMapViewOfSection returned %x\n", status );
1142 /* in contrary to regular NtMapViewOfSection, only 4kb align is enforced */
1143 ptr2 = (char *)ptr + 0x1000;
1144 size = 0;
1145 offset.QuadPart = 0;
1146 status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset,
1147 &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE );
1148 ok( status == STATUS_SUCCESS, "NtMapViewOfSection returned %x\n", status );
1149 ok( (char *)ptr2 == (char *)ptr + 0x1000,
1150 "expected address %p, got %p\n", (char *)ptr + 0x1000, ptr2 );
1151 status = pNtUnmapViewOfSection( hProcess, ptr2 );
1152 ok( !status, "NtUnmapViewOfSection failed status %x\n", status );
1154 /* the address is rounded down if not on a page boundary */
1155 ptr2 = (char *)ptr + 0x1001;
1156 size = 0;
1157 offset.QuadPart = 0;
1158 status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset,
1159 &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE );
1160 ok( status == STATUS_SUCCESS, "NtMapViewOfSection returned %x\n", status );
1161 ok( (char *)ptr2 == (char *)ptr + 0x1000,
1162 "expected address %p, got %p\n", (char *)ptr + 0x1000, ptr2 );
1163 status = pNtUnmapViewOfSection( hProcess, ptr2 );
1164 ok( !status, "NtUnmapViewOfSection failed status %x\n", status );
1166 ptr2 = (char *)ptr + 0x2000;
1167 size = 0;
1168 offset.QuadPart = 0;
1169 status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset,
1170 &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE );
1171 ok( status == STATUS_SUCCESS, "NtMapViewOfSection returned %x\n", status );
1172 ok( (char *)ptr2 == (char *)ptr + 0x2000,
1173 "expected address %p, got %p\n", (char *)ptr + 0x2000, ptr2 );
1174 status = pNtUnmapViewOfSection( hProcess, ptr2 );
1175 ok( !status, "NtUnmapViewOfSection failed status %x\n", status );
1177 else
1179 ptr2 = (char *)ptr + 0x1000;
1180 size = 0;
1181 offset.QuadPart = 0;
1182 status = pNtMapViewOfSection( mapping, hProcess, &ptr2, 0, 0, &offset,
1183 &size, 1, AT_ROUND_TO_PAGE, PAGE_READWRITE );
1184 todo_wine
1185 ok( status == STATUS_INVALID_PARAMETER_9, "NtMapViewOfSection returned %x\n", status );
1188 status = pNtUnmapViewOfSection( hProcess, ptr );
1189 ok( !status, "NtUnmapViewOfSection failed status %x\n", status );
1191 CloseHandle( mapping );
1192 CloseHandle( file );
1193 DeleteFileA( testfile );
1195 TerminateProcess(hProcess, 0);
1196 CloseHandle(hProcess);
1199 static void test_NtAreMappedFilesTheSame(void)
1201 static const char testfile[] = "testfile.xxx";
1202 HANDLE file, file2, mapping, map2;
1203 void *ptr, *ptr2;
1204 NTSTATUS status;
1205 char path[MAX_PATH];
1207 if (!pNtAreMappedFilesTheSame)
1209 win_skip( "NtAreMappedFilesTheSame not available\n" );
1210 return;
1213 file = CreateFileA( testfile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1214 NULL, CREATE_ALWAYS, 0, 0 );
1215 ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() );
1216 SetFilePointer( file, 4096, NULL, FILE_BEGIN );
1217 SetEndOfFile( file );
1219 mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
1220 ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() );
1222 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
1223 ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
1225 file2 = CreateFileA( testfile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
1226 NULL, OPEN_EXISTING, 0, 0 );
1227 ok( file2 != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() );
1229 map2 = CreateFileMappingA( file2, NULL, PAGE_READONLY, 0, 4096, NULL );
1230 ok( map2 != 0, "CreateFileMapping error %u\n", GetLastError() );
1231 ptr2 = MapViewOfFile( map2, FILE_MAP_READ, 0, 0, 4096 );
1232 ok( ptr2 != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
1233 status = pNtAreMappedFilesTheSame( ptr, ptr2 );
1234 ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status );
1235 UnmapViewOfFile( ptr2 );
1237 ptr2 = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
1238 ok( ptr2 != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
1239 status = pNtAreMappedFilesTheSame( ptr, ptr2 );
1240 ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status );
1241 UnmapViewOfFile( ptr2 );
1242 CloseHandle( map2 );
1244 map2 = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL );
1245 ok( map2 != 0, "CreateFileMapping error %u\n", GetLastError() );
1246 ptr2 = MapViewOfFile( map2, FILE_MAP_READ, 0, 0, 4096 );
1247 ok( ptr2 != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
1248 status = pNtAreMappedFilesTheSame( ptr, ptr2 );
1249 ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status );
1250 UnmapViewOfFile( ptr2 );
1251 CloseHandle( map2 );
1252 CloseHandle( file2 );
1254 status = pNtAreMappedFilesTheSame( ptr, ptr );
1255 ok( status == STATUS_SUCCESS || broken(status == STATUS_NOT_SAME_DEVICE),
1256 "NtAreMappedFilesTheSame returned %x\n", status );
1258 status = pNtAreMappedFilesTheSame( ptr, (char *)ptr + 30 );
1259 ok( status == STATUS_SUCCESS || broken(status == STATUS_NOT_SAME_DEVICE),
1260 "NtAreMappedFilesTheSame returned %x\n", status );
1262 status = pNtAreMappedFilesTheSame( ptr, GetModuleHandleA("kernel32.dll") );
1263 ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status );
1265 status = pNtAreMappedFilesTheSame( ptr, (void *)0xdeadbeef );
1266 ok( status == STATUS_CONFLICTING_ADDRESSES || status == STATUS_INVALID_ADDRESS,
1267 "NtAreMappedFilesTheSame returned %x\n", status );
1269 status = pNtAreMappedFilesTheSame( ptr, NULL );
1270 ok( status == STATUS_INVALID_ADDRESS, "NtAreMappedFilesTheSame returned %x\n", status );
1272 status = pNtAreMappedFilesTheSame( ptr, (void *)GetProcessHeap() );
1273 ok( status == STATUS_CONFLICTING_ADDRESSES, "NtAreMappedFilesTheSame returned %x\n", status );
1275 status = pNtAreMappedFilesTheSame( NULL, NULL );
1276 ok( status == STATUS_INVALID_ADDRESS, "NtAreMappedFilesTheSame returned %x\n", status );
1278 ptr2 = VirtualAlloc( NULL, 0x10000, MEM_COMMIT, PAGE_READWRITE );
1279 ok( ptr2 != NULL, "VirtualAlloc error %u\n", GetLastError() );
1280 status = pNtAreMappedFilesTheSame( ptr, ptr2 );
1281 ok( status == STATUS_CONFLICTING_ADDRESSES, "NtAreMappedFilesTheSame returned %x\n", status );
1282 VirtualFree( ptr2, 0, MEM_RELEASE );
1284 UnmapViewOfFile( ptr );
1285 CloseHandle( mapping );
1286 CloseHandle( file );
1288 status = pNtAreMappedFilesTheSame( GetModuleHandleA("ntdll.dll"),
1289 GetModuleHandleA("kernel32.dll") );
1290 ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status );
1291 status = pNtAreMappedFilesTheSame( GetModuleHandleA("kernel32.dll"),
1292 GetModuleHandleA("kernel32.dll") );
1293 ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %x\n", status );
1294 status = pNtAreMappedFilesTheSame( GetModuleHandleA("kernel32.dll"),
1295 (char *)GetModuleHandleA("kernel32.dll") + 4096 );
1296 ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %x\n", status );
1298 GetSystemDirectoryA( path, MAX_PATH );
1299 strcat( path, "\\kernel32.dll" );
1300 file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
1301 ok( file != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() );
1303 mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL );
1304 ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() );
1305 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
1306 ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
1307 status = pNtAreMappedFilesTheSame( ptr, GetModuleHandleA("kernel32.dll") );
1308 ok( status == STATUS_NOT_SAME_DEVICE, "NtAreMappedFilesTheSame returned %x\n", status );
1309 UnmapViewOfFile( ptr );
1310 CloseHandle( mapping );
1312 mapping = CreateFileMappingA( file, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL );
1313 ok( mapping != 0, "CreateFileMapping error %u\n", GetLastError() );
1314 ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
1315 ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
1316 status = pNtAreMappedFilesTheSame( ptr, GetModuleHandleA("kernel32.dll") );
1317 todo_wine
1318 ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %x\n", status );
1320 file2 = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
1321 ok( file2 != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError() );
1322 map2 = CreateFileMappingA( file2, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL );
1323 ok( map2 != 0, "CreateFileMapping error %u\n", GetLastError() );
1324 ptr2 = MapViewOfFile( map2, FILE_MAP_READ, 0, 0, 0 );
1325 ok( ptr2 != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
1326 status = pNtAreMappedFilesTheSame( ptr, ptr2 );
1327 ok( status == STATUS_SUCCESS, "NtAreMappedFilesTheSame returned %x\n", status );
1328 UnmapViewOfFile( ptr2 );
1329 CloseHandle( map2 );
1330 CloseHandle( file2 );
1332 UnmapViewOfFile( ptr );
1333 CloseHandle( mapping );
1335 CloseHandle( file );
1336 DeleteFileA( testfile );
1339 static void test_CreateFileMapping(void)
1341 HANDLE handle, handle2;
1343 /* test case sensitivity */
1345 SetLastError(0xdeadbeef);
1346 handle = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, 0x1000,
1347 "Wine Test Mapping");
1348 ok( handle != NULL, "CreateFileMapping failed with error %u\n", GetLastError());
1349 ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
1351 SetLastError(0xdeadbeef);
1352 handle2 = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, 0x1000,
1353 "Wine Test Mapping");
1354 ok( handle2 != NULL, "CreateFileMapping failed with error %d\n", GetLastError());
1355 ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError());
1356 CloseHandle( handle2 );
1358 SetLastError(0xdeadbeef);
1359 handle2 = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, 0x1000,
1360 "WINE TEST MAPPING");
1361 ok( handle2 != NULL, "CreateFileMapping failed with error %d\n", GetLastError());
1362 ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
1363 CloseHandle( handle2 );
1365 SetLastError(0xdeadbeef);
1366 handle2 = OpenFileMappingA( FILE_MAP_ALL_ACCESS, FALSE, "Wine Test Mapping");
1367 ok( handle2 != NULL, "OpenFileMapping failed with error %d\n", GetLastError());
1368 CloseHandle( handle2 );
1370 SetLastError(0xdeadbeef);
1371 handle2 = OpenFileMappingA( FILE_MAP_ALL_ACCESS, FALSE, "WINE TEST MAPPING");
1372 ok( !handle2, "OpenFileMapping succeeded\n");
1373 ok( GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_INVALID_NAME /* win9x */,
1374 "wrong error %u\n", GetLastError());
1376 CloseHandle( handle );
1379 static void test_IsBadReadPtr(void)
1381 BOOL ret;
1382 void *ptr = (void *)0xdeadbeef;
1383 char stackvar;
1385 ret = IsBadReadPtr(NULL, 0);
1386 ok(ret == FALSE, "Expected IsBadReadPtr to return FALSE, got %d\n", ret);
1388 ret = IsBadReadPtr(NULL, 1);
1389 ok(ret == TRUE, "Expected IsBadReadPtr to return TRUE, got %d\n", ret);
1391 ret = IsBadReadPtr(ptr, 0);
1392 ok(ret == FALSE, "Expected IsBadReadPtr to return FALSE, got %d\n", ret);
1394 ret = IsBadReadPtr(ptr, 1);
1395 ok(ret == TRUE, "Expected IsBadReadPtr to return TRUE, got %d\n", ret);
1397 ret = IsBadReadPtr(&stackvar, 0);
1398 ok(ret == FALSE, "Expected IsBadReadPtr to return FALSE, got %d\n", ret);
1400 ret = IsBadReadPtr(&stackvar, sizeof(char));
1401 ok(ret == FALSE, "Expected IsBadReadPtr to return FALSE, got %d\n", ret);
1404 static void test_IsBadWritePtr(void)
1406 BOOL ret;
1407 void *ptr = (void *)0xdeadbeef;
1408 char stackval;
1410 ret = IsBadWritePtr(NULL, 0);
1411 ok(ret == FALSE, "Expected IsBadWritePtr to return FALSE, got %d\n", ret);
1413 ret = IsBadWritePtr(NULL, 1);
1414 ok(ret == TRUE, "Expected IsBadWritePtr to return TRUE, got %d\n", ret);
1416 ret = IsBadWritePtr(ptr, 0);
1417 ok(ret == FALSE, "Expected IsBadWritePtr to return FALSE, got %d\n", ret);
1419 ret = IsBadWritePtr(ptr, 1);
1420 ok(ret == TRUE, "Expected IsBadWritePtr to return TRUE, got %d\n", ret);
1422 ret = IsBadWritePtr(&stackval, 0);
1423 ok(ret == FALSE, "Expected IsBadWritePtr to return FALSE, got %d\n", ret);
1425 ret = IsBadWritePtr(&stackval, sizeof(char));
1426 ok(ret == FALSE, "Expected IsBadWritePtr to return FALSE, got %d\n", ret);
1429 static void test_IsBadCodePtr(void)
1431 BOOL ret;
1432 void *ptr = (void *)0xdeadbeef;
1433 char stackval;
1435 ret = IsBadCodePtr(NULL);
1436 ok(ret == TRUE, "Expected IsBadCodePtr to return TRUE, got %d\n", ret);
1438 ret = IsBadCodePtr(ptr);
1439 ok(ret == TRUE, "Expected IsBadCodePtr to return TRUE, got %d\n", ret);
1441 ret = IsBadCodePtr((void *)&stackval);
1442 ok(ret == FALSE, "Expected IsBadCodePtr to return FALSE, got %d\n", ret);
1445 static void test_write_watch(void)
1447 static const char pipename[] = "\\\\.\\pipe\\test_write_watch_pipe";
1448 static const char testdata[] = "Hello World";
1449 DWORD ret, size, old_prot, num_bytes;
1450 MEMORY_BASIC_INFORMATION info;
1451 HANDLE readpipe, writepipe;
1452 OVERLAPPED overlapped;
1453 void *results[64];
1454 ULONG_PTR count;
1455 ULONG pagesize;
1456 BOOL success;
1457 char *base;
1459 if (!pGetWriteWatch || !pResetWriteWatch)
1461 win_skip( "GetWriteWatch not supported\n" );
1462 return;
1465 size = 0x10000;
1466 base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT | MEM_WRITE_WATCH, PAGE_READWRITE );
1467 if (!base &&
1468 (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_NOT_SUPPORTED))
1470 win_skip( "MEM_WRITE_WATCH not supported\n" );
1471 return;
1473 ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
1474 ret = VirtualQuery( base, &info, sizeof(info) );
1475 ok(ret, "VirtualQuery failed %u\n", GetLastError());
1476 ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base );
1477 ok( info.AllocationProtect == PAGE_READWRITE, "wrong AllocationProtect %x\n", info.AllocationProtect );
1478 ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize );
1479 ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State );
1480 ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect );
1481 ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type );
1483 count = 64;
1484 SetLastError( 0xdeadbeef );
1485 ret = pGetWriteWatch( 0, NULL, size, results, &count, &pagesize );
1486 ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1487 ok( GetLastError() == ERROR_INVALID_PARAMETER ||
1488 broken( GetLastError() == 0xdeadbeef ), /* win98 */
1489 "wrong error %u\n", GetLastError() );
1491 SetLastError( 0xdeadbeef );
1492 ret = pGetWriteWatch( 0, GetModuleHandleW(NULL), size, results, &count, &pagesize );
1493 if (ret)
1495 ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1496 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1498 else /* win98 */
1500 ok( count == 0, "wrong count %lu\n", count );
1503 ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1504 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1505 ok( count == 0, "wrong count %lu\n", count );
1507 base[pagesize + 1] = 0x44;
1509 count = 64;
1510 ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1511 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1512 ok( count == 1, "wrong count %lu\n", count );
1513 ok( results[0] == base + pagesize, "wrong result %p\n", results[0] );
1515 count = 64;
1516 ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
1517 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1518 ok( count == 1, "wrong count %lu\n", count );
1519 ok( results[0] == base + pagesize, "wrong result %p\n", results[0] );
1521 count = 64;
1522 ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1523 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1524 ok( count == 0, "wrong count %lu\n", count );
1526 base[2*pagesize + 3] = 0x11;
1527 base[4*pagesize + 8] = 0x11;
1529 count = 64;
1530 ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1531 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1532 ok( count == 2, "wrong count %lu\n", count );
1533 ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] );
1534 ok( results[1] == base + 4*pagesize, "wrong result %p\n", results[1] );
1536 count = 64;
1537 ret = pGetWriteWatch( 0, base + 3*pagesize, 2*pagesize, results, &count, &pagesize );
1538 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1539 ok( count == 1, "wrong count %lu\n", count );
1540 ok( results[0] == base + 4*pagesize, "wrong result %p\n", results[0] );
1542 ret = pResetWriteWatch( base, 3*pagesize );
1543 ok( !ret, "pResetWriteWatch failed %u\n", GetLastError() );
1545 count = 64;
1546 ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1547 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1548 ok( count == 1, "wrong count %lu\n", count );
1549 ok( results[0] == base + 4*pagesize, "wrong result %p\n", results[0] );
1551 *(DWORD *)(base + 2*pagesize - 2) = 0xdeadbeef;
1553 count = 64;
1554 ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1555 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1556 ok( count == 3, "wrong count %lu\n", count );
1557 ok( results[0] == base + pagesize, "wrong result %p\n", results[0] );
1558 ok( results[1] == base + 2*pagesize, "wrong result %p\n", results[1] );
1559 ok( results[2] == base + 4*pagesize, "wrong result %p\n", results[2] );
1561 count = 1;
1562 ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
1563 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1564 ok( count == 1, "wrong count %lu\n", count );
1565 ok( results[0] == base + pagesize, "wrong result %p\n", results[0] );
1567 count = 64;
1568 ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1569 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1570 ok( count == 2, "wrong count %lu\n", count );
1571 ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] );
1572 ok( results[1] == base + 4*pagesize, "wrong result %p\n", results[1] );
1574 /* changing protections doesn't affect watches */
1576 ret = VirtualProtect( base, 3*pagesize, PAGE_READONLY, &old_prot );
1577 ok( ret, "VirtualProtect failed error %u\n", GetLastError() );
1578 ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
1580 ret = VirtualQuery( base, &info, sizeof(info) );
1581 ok(ret, "VirtualQuery failed %u\n", GetLastError());
1582 ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base );
1583 ok( info.RegionSize == 3*pagesize, "wrong RegionSize 0x%lx\n", info.RegionSize );
1584 ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State );
1585 ok( info.Protect == PAGE_READONLY, "wrong Protect 0x%x\n", info.Protect );
1587 ret = VirtualProtect( base, 3*pagesize, PAGE_READWRITE, &old_prot );
1588 ok( ret, "VirtualProtect failed error %u\n", GetLastError() );
1589 ok( old_prot == PAGE_READONLY, "wrong old prot %x\n", old_prot );
1591 count = 64;
1592 ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1593 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1594 ok( count == 2, "wrong count %lu\n", count );
1595 ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] );
1596 ok( results[1] == base + 4*pagesize, "wrong result %p\n", results[1] );
1598 ret = VirtualQuery( base, &info, sizeof(info) );
1599 ok(ret, "VirtualQuery failed %u\n", GetLastError());
1600 ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base );
1601 ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize );
1602 ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State );
1603 ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect );
1605 /* ReadFile should trigger write watches */
1607 memset( &overlapped, 0, sizeof(overlapped) );
1608 overlapped.hEvent = CreateEventA( NULL, TRUE, FALSE, NULL );
1610 readpipe = CreateNamedPipeA( pipename, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_INBOUND,
1611 PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1024, 1024,
1612 NMPWAIT_USE_DEFAULT_WAIT, NULL );
1613 ok( readpipe != INVALID_HANDLE_VALUE, "CreateNamedPipeA failed %u\n", GetLastError() );
1615 success = ConnectNamedPipe( readpipe, &overlapped );
1616 ok( !success, "ConnectNamedPipe unexpectedly succeeded\n" );
1617 ok( GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %u\n", GetLastError() );
1619 writepipe = CreateFileA( pipename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL );
1620 ok( writepipe != INVALID_HANDLE_VALUE, "CreateFileA failed %u\n", GetLastError() );
1622 ret = WaitForSingleObject( overlapped.hEvent, 1000 );
1623 ok( ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret );
1625 memset( base, 0, size );
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 == 16, "wrong count %lu\n", count );
1632 success = ReadFile( readpipe, base, size, NULL, &overlapped );
1633 ok( !success, "ReadFile unexpectedly succeeded\n" );
1634 ok( GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %u\n", GetLastError() );
1636 count = 64;
1637 ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
1638 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1639 ok( count == 16, "wrong count %lu\n", count );
1641 num_bytes = 0;
1642 success = WriteFile( writepipe, testdata, sizeof(testdata), &num_bytes, NULL );
1643 ok( success, "WriteFile failed %u\n", GetLastError() );
1644 ok( num_bytes == sizeof(testdata), "wrong number of bytes written\n" );
1646 num_bytes = 0;
1647 success = GetOverlappedResult( readpipe, &overlapped, &num_bytes, TRUE );
1648 todo_wine ok( success, "GetOverlappedResult failed %u\n", GetLastError() );
1649 todo_wine ok( num_bytes == sizeof(testdata), "wrong number of bytes read\n" );
1650 todo_wine ok( !memcmp( base, testdata, sizeof(testdata)), "didn't receive expected data\n" );
1652 count = 64;
1653 memset( results, 0, sizeof(results) );
1654 ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
1655 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1656 todo_wine ok( count == 1, "wrong count %lu\n", count );
1657 todo_wine ok( results[0] == base, "wrong result %p\n", results[0] );
1659 CloseHandle( readpipe );
1660 CloseHandle( writepipe );
1661 CloseHandle( overlapped.hEvent );
1663 /* some invalid parameter tests */
1665 SetLastError( 0xdeadbeef );
1666 count = 0;
1667 ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1668 if (ret)
1670 ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1671 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1673 SetLastError( 0xdeadbeef );
1674 ret = pGetWriteWatch( 0, base, size, results, NULL, &pagesize );
1675 ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1676 ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
1678 SetLastError( 0xdeadbeef );
1679 count = 64;
1680 ret = pGetWriteWatch( 0, base, size, results, &count, NULL );
1681 ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1682 ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
1684 SetLastError( 0xdeadbeef );
1685 count = 64;
1686 ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize );
1687 ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1688 ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
1690 SetLastError( 0xdeadbeef );
1691 count = 0;
1692 ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize );
1693 ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1694 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1696 SetLastError( 0xdeadbeef );
1697 count = 64;
1698 ret = pGetWriteWatch( 0xdeadbeef, base, size, results, &count, &pagesize );
1699 ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1700 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1702 SetLastError( 0xdeadbeef );
1703 count = 64;
1704 ret = pGetWriteWatch( 0, base, 0, results, &count, &pagesize );
1705 ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1706 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1708 SetLastError( 0xdeadbeef );
1709 count = 64;
1710 ret = pGetWriteWatch( 0, base, size * 2, results, &count, &pagesize );
1711 ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1712 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1714 SetLastError( 0xdeadbeef );
1715 count = 64;
1716 ret = pGetWriteWatch( 0, base + size - pagesize, pagesize + 1, results, &count, &pagesize );
1717 ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
1718 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1720 SetLastError( 0xdeadbeef );
1721 ret = pResetWriteWatch( base, 0 );
1722 ok( ret == ~0u, "ResetWriteWatch succeeded %u\n", ret );
1723 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1725 SetLastError( 0xdeadbeef );
1726 ret = pResetWriteWatch( GetModuleHandleW(NULL), size );
1727 ok( ret == ~0u, "ResetWriteWatch succeeded %u\n", ret );
1728 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1730 else /* win98 is completely different */
1732 SetLastError( 0xdeadbeef );
1733 count = 64;
1734 ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize );
1735 ok( ret == ERROR_INVALID_PARAMETER, "GetWriteWatch succeeded %u\n", ret );
1736 ok( GetLastError() == 0xdeadbeef, "wrong error %u\n", GetLastError() );
1738 count = 0;
1739 ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize );
1740 ok( !ret, "GetWriteWatch failed %u\n", ret );
1742 count = 64;
1743 ret = pGetWriteWatch( 0xdeadbeef, base, size, results, &count, &pagesize );
1744 ok( !ret, "GetWriteWatch failed %u\n", ret );
1746 count = 64;
1747 ret = pGetWriteWatch( 0, base, 0, results, &count, &pagesize );
1748 ok( !ret, "GetWriteWatch failed %u\n", ret );
1750 ret = pResetWriteWatch( base, 0 );
1751 ok( !ret, "ResetWriteWatch failed %u\n", ret );
1753 ret = pResetWriteWatch( GetModuleHandleW(NULL), size );
1754 ok( !ret, "ResetWriteWatch failed %u\n", ret );
1757 VirtualFree( base, 0, MEM_RELEASE );
1759 base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_WRITE_WATCH, PAGE_READWRITE );
1760 ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
1761 VirtualFree( base, 0, MEM_RELEASE );
1763 base = VirtualAlloc( 0, size, MEM_WRITE_WATCH, PAGE_READWRITE );
1764 ok( !base, "VirtualAlloc succeeded\n" );
1765 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1767 /* initial protect doesn't matter */
1769 base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_WRITE_WATCH, PAGE_NOACCESS );
1770 ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
1771 base = VirtualAlloc( base, size, MEM_COMMIT, PAGE_NOACCESS );
1772 ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
1774 count = 64;
1775 ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1776 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1777 ok( count == 0, "wrong count %lu\n", count );
1779 ret = VirtualProtect( base, 6*pagesize, PAGE_READWRITE, &old_prot );
1780 ok( ret, "VirtualProtect failed error %u\n", GetLastError() );
1781 ok( old_prot == PAGE_NOACCESS, "wrong old prot %x\n", old_prot );
1783 base[5*pagesize + 200] = 3;
1785 ret = VirtualProtect( base, 6*pagesize, PAGE_NOACCESS, &old_prot );
1786 ok( ret, "VirtualProtect failed error %u\n", GetLastError() );
1787 ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
1789 count = 64;
1790 ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1791 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1792 ok( count == 1, "wrong count %lu\n", count );
1793 ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] );
1795 ret = VirtualFree( base, size, MEM_DECOMMIT );
1796 ok( ret, "VirtualFree failed %u\n", GetLastError() );
1798 count = 64;
1799 ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
1800 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
1801 ok( count == 1 || broken(count == 0), /* win98 */
1802 "wrong count %lu\n", count );
1803 if (count) ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] );
1805 VirtualFree( base, 0, MEM_RELEASE );
1808 #if defined(__i386__) || defined(__x86_64__)
1810 static DWORD WINAPI stack_commit_func( void *arg )
1812 volatile char *p = (char *)&p;
1814 /* trigger all guard pages, to ensure that the pages are committed */
1815 while (p >= (char *)NtCurrentTeb()->DeallocationStack + 4 * 0x1000)
1817 p[0] |= 0;
1818 p -= 0x1000;
1821 ok( arg == (void *)0xdeadbeef, "expected 0xdeadbeef, got %p\n", arg );
1822 return 42;
1825 static void test_stack_commit(void)
1827 #ifdef __i386__
1828 static const char code_call_on_stack[] = {
1829 0x55, /* pushl %ebp */
1830 0x56, /* pushl %esi */
1831 0x89, 0xe6, /* movl %esp,%esi */
1832 0x8b, 0x4c, 0x24, 0x0c, /* movl 12(%esp),%ecx - func */
1833 0x8b, 0x54, 0x24, 0x10, /* movl 16(%esp),%edx - arg */
1834 0x8b, 0x44, 0x24, 0x14, /* movl 20(%esp),%eax - stack */
1835 0x83, 0xe0, 0xf0, /* andl $~15,%eax */
1836 0x83, 0xe8, 0x0c, /* subl $12,%eax */
1837 0x89, 0xc4, /* movl %eax,%esp */
1838 0x52, /* pushl %edx */
1839 0x31, 0xed, /* xorl %ebp,%ebp */
1840 0xff, 0xd1, /* call *%ecx */
1841 0x89, 0xf4, /* movl %esi,%esp */
1842 0x5e, /* popl %esi */
1843 0x5d, /* popl %ebp */
1844 0xc2, 0x0c, 0x00 }; /* ret $12 */
1845 #else
1846 static const char code_call_on_stack[] = {
1847 0x55, /* pushq %rbp */
1848 0x48, 0x89, 0xe5, /* movq %rsp,%rbp */
1849 /* %rcx - func, %rdx - arg, %r8 - stack */
1850 0x48, 0x87, 0xca, /* xchgq %rcx,%rdx */
1851 0x49, 0x83, 0xe0, 0xf0, /* andq $~15,%r8 */
1852 0x49, 0x83, 0xe8, 0x20, /* subq $0x20,%r8 */
1853 0x4c, 0x89, 0xc4, /* movq %r8,%rsp */
1854 0xff, 0xd2, /* callq *%rdx */
1855 0x48, 0x89, 0xec, /* movq %rbp,%rsp */
1856 0x5d, /* popq %rbp */
1857 0xc3 }; /* ret */
1858 #endif
1859 DWORD (WINAPI *call_on_stack)( DWORD (WINAPI *func)(void *), void *arg, void *stack );
1860 void *old_stack, *old_stack_base, *old_stack_limit;
1861 void *new_stack, *new_stack_base;
1862 DWORD result;
1864 call_on_stack = VirtualAlloc( 0, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE );
1865 ok( call_on_stack != NULL, "VirtualAlloc failed %u\n", GetLastError() );
1866 memcpy( call_on_stack, code_call_on_stack, sizeof(code_call_on_stack) );
1868 /* allocate a new stack, only the first guard page is committed */
1869 new_stack = VirtualAlloc( 0, 0x400000, MEM_RESERVE, PAGE_READWRITE );
1870 ok( new_stack != NULL, "VirtualAlloc failed %u\n", GetLastError() );
1871 new_stack_base = (char *)new_stack + 0x400000;
1872 VirtualAlloc( (char *)new_stack_base - 0x1000, 0x1000, MEM_COMMIT, PAGE_READWRITE | PAGE_GUARD );
1874 old_stack = NtCurrentTeb()->DeallocationStack;
1875 old_stack_base = NtCurrentTeb()->Tib.StackBase;
1876 old_stack_limit = NtCurrentTeb()->Tib.StackLimit;
1878 NtCurrentTeb()->DeallocationStack = new_stack;
1879 NtCurrentTeb()->Tib.StackBase = new_stack_base;
1880 NtCurrentTeb()->Tib.StackLimit = new_stack_base;
1882 result = call_on_stack( stack_commit_func, (void *)0xdeadbeef, new_stack_base );
1884 NtCurrentTeb()->DeallocationStack = old_stack;
1885 NtCurrentTeb()->Tib.StackBase = old_stack_base;
1886 NtCurrentTeb()->Tib.StackLimit = old_stack_limit;
1888 ok( result == 42, "expected 42, got %u\n", result );
1890 VirtualFree( new_stack, 0, MEM_RELEASE );
1891 VirtualFree( call_on_stack, 0, MEM_RELEASE );
1894 #endif /* defined(__i386__) || defined(__x86_64__) */
1895 #ifdef __i386__
1897 static LONG num_guard_page_calls;
1899 static DWORD guard_page_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
1900 CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
1902 trace( "exception: %08x flags:%x addr:%p\n",
1903 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
1905 ok( rec->NumberParameters == 2, "NumberParameters is %d instead of 2\n", rec->NumberParameters );
1906 ok( rec->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION, "ExceptionCode is %08x instead of %08x\n",
1907 rec->ExceptionCode, STATUS_GUARD_PAGE_VIOLATION );
1909 InterlockedIncrement( &num_guard_page_calls );
1910 *(int *)rec->ExceptionInformation[1] += 0x100;
1912 return ExceptionContinueExecution;
1915 static void test_guard_page(void)
1917 EXCEPTION_REGISTRATION_RECORD frame;
1918 MEMORY_BASIC_INFORMATION info;
1919 DWORD ret, size, old_prot;
1920 int *value, old_value;
1921 void *results[64];
1922 ULONG_PTR count;
1923 ULONG pagesize;
1924 BOOL success;
1925 char *base;
1927 size = 0x1000;
1928 base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE | PAGE_GUARD );
1929 ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
1930 value = (int *)base;
1932 /* verify info structure */
1933 ret = VirtualQuery( base, &info, sizeof(info) );
1934 ok( ret, "VirtualQuery failed %u\n", GetLastError());
1935 ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base );
1936 ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "wrong AllocationProtect %x\n", info.AllocationProtect );
1937 ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize );
1938 ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State );
1939 ok( info.Protect == (PAGE_READWRITE | PAGE_GUARD), "wrong Protect 0x%x\n", info.Protect );
1940 ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type );
1942 /* put some initial value into the memory */
1943 success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
1944 ok( success, "VirtualProtect failed %u\n", GetLastError() );
1945 ok( old_prot == (PAGE_READWRITE | PAGE_GUARD), "wrong old prot %x\n", old_prot );
1947 *value = 1;
1948 *(value + 1) = 2;
1950 success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
1951 ok( success, "VirtualProtect failed %u\n", GetLastError() );
1952 ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
1954 /* test behaviour of VirtualLock - first attempt should fail */
1955 SetLastError( 0xdeadbeef );
1956 success = VirtualLock( base, size );
1957 ok( !success, "VirtualLock unexpectedly succeeded\n" );
1958 todo_wine
1959 ok( GetLastError() == STATUS_GUARD_PAGE_VIOLATION, "wrong error %u\n", GetLastError() );
1961 success = VirtualLock( base, size );
1962 todo_wine
1963 ok( success, "VirtualLock failed %u\n", GetLastError() );
1964 if (success)
1966 ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%x\n", *value );
1967 success = VirtualUnlock( base, size );
1968 ok( success, "VirtualUnlock failed %u\n", GetLastError() );
1971 /* check info structure again, PAGE_GUARD should be removed now */
1972 ret = VirtualQuery( base, &info, sizeof(info) );
1973 ok( ret, "VirtualQuery failed %u\n", GetLastError());
1974 ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base );
1975 ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "wrong AllocationProtect %x\n", info.AllocationProtect );
1976 ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize );
1977 ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State );
1978 todo_wine
1979 ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect );
1980 ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type );
1982 success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
1983 ok( success, "VirtualProtect failed %u\n", GetLastError() );
1984 todo_wine
1985 ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
1987 /* test directly accessing the memory - we need to setup an exception handler first */
1988 frame.Handler = guard_page_handler;
1989 frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
1990 NtCurrentTeb()->Tib.ExceptionList = &frame;
1992 InterlockedExchange( &num_guard_page_calls, 0 );
1993 InterlockedExchange( &old_value, *value ); /* exception handler increments value by 0x100 */
1994 *value = 2;
1995 ok( old_value == 0x101, "memory block contains wrong value, expected 0x101, got 0x%x\n", old_value );
1996 ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls );
1998 NtCurrentTeb()->Tib.ExceptionList = frame.Prev;
2000 /* check info structure again, PAGE_GUARD should be removed now */
2001 ret = VirtualQuery( base, &info, sizeof(info) );
2002 ok( ret, "VirtualQuery failed %u\n", GetLastError());
2003 ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect );
2005 success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
2006 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2007 ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
2009 /* test accessing second integer in memory */
2010 frame.Handler = guard_page_handler;
2011 frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
2012 NtCurrentTeb()->Tib.ExceptionList = &frame;
2014 InterlockedExchange( &num_guard_page_calls, 0 );
2015 old_value = *(value + 1);
2016 ok( old_value == 0x102, "memory block contains wrong value, expected 0x102, got 0x%x\n", old_value );
2017 ok( *value == 2, "memory block contains wrong value, expected 2, got 0x%x\n", *value );
2018 ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls );
2020 NtCurrentTeb()->Tib.ExceptionList = frame.Prev;
2022 success = VirtualLock( base, size );
2023 ok( success, "VirtualLock failed %u\n", GetLastError() );
2024 if (success)
2026 ok( *value == 2, "memory block contains wrong value, expected 2, got 0x%x\n", *value );
2027 success = VirtualUnlock( base, size );
2028 ok( success, "VirtualUnlock failed %u\n", GetLastError() );
2031 VirtualFree( base, 0, MEM_RELEASE );
2033 /* combined guard page / write watch tests */
2034 if (!pGetWriteWatch || !pResetWriteWatch)
2036 win_skip( "GetWriteWatch not supported, skipping combined guard page / write watch tests\n" );
2037 return;
2040 base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT | MEM_WRITE_WATCH, PAGE_READWRITE | PAGE_GUARD );
2041 if (!base && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_NOT_SUPPORTED))
2043 win_skip( "MEM_WRITE_WATCH not supported\n" );
2044 return;
2046 ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
2047 value = (int *)base;
2049 ret = VirtualQuery( base, &info, sizeof(info) );
2050 ok( ret, "VirtualQuery failed %u\n", GetLastError() );
2051 ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base );
2052 ok( info.AllocationProtect == (PAGE_READWRITE | PAGE_GUARD), "wrong AllocationProtect %x\n", info.AllocationProtect );
2053 ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize );
2054 ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State );
2055 ok( info.Protect == (PAGE_READWRITE | PAGE_GUARD), "wrong Protect 0x%x\n", info.Protect );
2056 ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type );
2058 count = 64;
2059 ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
2060 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2061 ok( count == 0, "wrong count %lu\n", count );
2063 /* writing to a page should trigger should trigger guard page, even if write watch is set */
2064 frame.Handler = guard_page_handler;
2065 frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
2066 NtCurrentTeb()->Tib.ExceptionList = &frame;
2068 InterlockedExchange( &num_guard_page_calls, 0 );
2069 *value = 1;
2070 *(value + 1) = 2;
2071 ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls );
2073 NtCurrentTeb()->Tib.ExceptionList = frame.Prev;
2075 count = 64;
2076 ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2077 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2078 ok( count == 1, "wrong count %lu\n", count );
2079 ok( results[0] == base, "wrong result %p\n", results[0] );
2081 success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
2082 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2084 /* write watch is triggered from inside of the guard page handler */
2085 frame.Handler = guard_page_handler;
2086 frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
2087 NtCurrentTeb()->Tib.ExceptionList = &frame;
2089 InterlockedExchange( &num_guard_page_calls, 0 );
2090 old_value = *(value + 1); /* doesn't trigger write watch */
2091 ok( old_value == 0x102, "memory block contains wrong value, expected 0x102, got 0x%x\n", old_value );
2092 ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%x\n", *value );
2093 ok( num_guard_page_calls == 1, "expected one callback of guard page handler, got %d calls\n", num_guard_page_calls );
2095 NtCurrentTeb()->Tib.ExceptionList = frame.Prev;
2097 count = 64;
2098 ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2099 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2100 ok( count == 1, "wrong count %lu\n", count );
2101 ok( results[0] == base, "wrong result %p\n", results[0] );
2103 success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
2104 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2106 /* test behaviour of VirtualLock - first attempt should fail without triggering write watches */
2107 SetLastError( 0xdeadbeef );
2108 success = VirtualLock( base, size );
2109 ok( !success, "VirtualLock unexpectedly succeeded\n" );
2110 todo_wine
2111 ok( GetLastError() == STATUS_GUARD_PAGE_VIOLATION, "wrong error %u\n", GetLastError() );
2113 count = 64;
2114 ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
2115 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2116 ok( count == 0, "wrong count %lu\n", count );
2118 success = VirtualLock( base, size );
2119 todo_wine
2120 ok( success, "VirtualLock failed %u\n", GetLastError() );
2121 if (success)
2123 ok( *value == 1, "memory block contains wrong value, expected 1, got 0x%x\n", *value );
2124 success = VirtualUnlock( base, size );
2125 ok( success, "VirtualUnlock failed %u\n", GetLastError() );
2128 count = 64;
2129 results[0] = (void *)0xdeadbeef;
2130 ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2131 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2132 todo_wine
2133 ok( count == 1 || broken(count == 0) /* Windows 8 */, "wrong count %lu\n", count );
2134 todo_wine
2135 ok( results[0] == base || broken(results[0] == (void *)0xdeadbeef) /* Windows 8 */, "wrong result %p\n", results[0] );
2137 VirtualFree( base, 0, MEM_RELEASE );
2140 static LONG num_execute_fault_calls;
2142 static DWORD execute_fault_seh_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
2143 CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
2145 ULONG flags = MEM_EXECUTE_OPTION_ENABLE;
2146 DWORD err;
2148 trace( "exception: %08x flags:%x addr:%p info[0]:%ld info[1]:%p\n",
2149 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
2150 rec->ExceptionInformation[0], (void *)rec->ExceptionInformation[1] );
2152 ok( rec->NumberParameters == 2, "NumberParameters is %d instead of 2\n", rec->NumberParameters );
2153 ok( rec->ExceptionCode == STATUS_ACCESS_VIOLATION || rec->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION,
2154 "ExceptionCode is %08x instead of STATUS_ACCESS_VIOLATION or STATUS_GUARD_PAGE_VIOLATION\n", rec->ExceptionCode );
2156 NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags), NULL );
2158 if (rec->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION)
2161 err = IsProcessorFeaturePresent( PF_NX_ENABLED ) ? EXCEPTION_EXECUTE_FAULT : EXCEPTION_READ_FAULT;
2162 ok( rec->ExceptionInformation[0] == err, "ExceptionInformation[0] is %d instead of %d\n",
2163 (DWORD)rec->ExceptionInformation[0], err );
2165 InterlockedIncrement( &num_guard_page_calls );
2167 else if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION)
2169 DWORD old_prot;
2170 BOOL success;
2172 err = (flags & MEM_EXECUTE_OPTION_DISABLE) ? EXCEPTION_EXECUTE_FAULT : EXCEPTION_READ_FAULT;
2173 ok( rec->ExceptionInformation[0] == err, "ExceptionInformation[0] is %d instead of %d\n",
2174 (DWORD)rec->ExceptionInformation[0], err );
2176 success = VirtualProtect( (void *)rec->ExceptionInformation[1], 16, PAGE_EXECUTE_READWRITE, &old_prot );
2177 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2178 ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
2180 InterlockedIncrement( &num_execute_fault_calls );
2183 return ExceptionContinueExecution;
2186 static LONG CALLBACK execute_fault_vec_handler( EXCEPTION_POINTERS *ExceptionInfo )
2188 PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord;
2189 DWORD old_prot;
2190 BOOL success;
2192 trace( "exception: %08x flags:%x addr:%p info[0]:%ld info[1]:%p\n",
2193 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
2194 rec->ExceptionInformation[0], (void *)rec->ExceptionInformation[1] );
2196 ok( rec->NumberParameters == 2, "NumberParameters is %d instead of 2\n", rec->NumberParameters );
2197 ok( rec->ExceptionCode == STATUS_ACCESS_VIOLATION,
2198 "ExceptionCode is %08x instead of STATUS_ACCESS_VIOLATION\n", rec->ExceptionCode );
2200 if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION)
2201 InterlockedIncrement( &num_execute_fault_calls );
2203 if (rec->ExceptionInformation[0] == EXCEPTION_READ_FAULT)
2204 return EXCEPTION_CONTINUE_SEARCH;
2206 success = VirtualProtect( (void *)rec->ExceptionInformation[1], 16, PAGE_EXECUTE_READWRITE, &old_prot );
2207 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2208 ok( old_prot == PAGE_NOACCESS, "wrong old prot %x\n", old_prot );
2210 return EXCEPTION_CONTINUE_EXECUTION;
2213 static inline DWORD send_message_excpt( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
2215 EXCEPTION_REGISTRATION_RECORD frame;
2216 DWORD ret;
2218 frame.Handler = execute_fault_seh_handler;
2219 frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
2220 NtCurrentTeb()->Tib.ExceptionList = &frame;
2222 InterlockedExchange( &num_guard_page_calls, 0 );
2223 InterlockedExchange( &num_execute_fault_calls, 0 );
2224 ret = SendMessageA( hWnd, uMsg, wParam, lParam );
2226 NtCurrentTeb()->Tib.ExceptionList = frame.Prev;
2228 return ret;
2231 static inline DWORD call_proc_excpt( DWORD (CALLBACK *code)(void *), void *arg )
2233 EXCEPTION_REGISTRATION_RECORD frame;
2234 DWORD ret;
2236 frame.Handler = execute_fault_seh_handler;
2237 frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
2238 NtCurrentTeb()->Tib.ExceptionList = &frame;
2240 InterlockedExchange( &num_guard_page_calls, 0 );
2241 InterlockedExchange( &num_execute_fault_calls, 0 );
2242 ret = code( arg );
2244 NtCurrentTeb()->Tib.ExceptionList = frame.Prev;
2246 return ret;
2249 static LRESULT CALLBACK jmp_test_func( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
2251 if (uMsg == WM_USER)
2252 return 42;
2254 return DefWindowProcA( hWnd, uMsg, wParam, lParam );
2257 static LRESULT CALLBACK atl_test_func( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
2259 DWORD arg = (DWORD)hWnd;
2260 if (uMsg == WM_USER)
2261 ok( arg == 0x11223344, "arg is 0x%08x instead of 0x11223344\n", arg );
2262 else
2263 ok( arg != 0x11223344, "arg is unexpectedly 0x11223344\n" );
2264 return 43;
2267 static DWORD CALLBACK atl5_test_func( void )
2269 return 44;
2272 static void test_atl_thunk_emulation( ULONG dep_flags )
2274 static const char code_jmp[] = {0xE9, 0x00, 0x00, 0x00, 0x00};
2275 static const char code_atl1[] = {0xC7, 0x44, 0x24, 0x04, 0x44, 0x33, 0x22, 0x11, 0xE9, 0x00, 0x00, 0x00, 0x00};
2276 static const char code_atl2[] = {0xB9, 0x44, 0x33, 0x22, 0x11, 0xE9, 0x00, 0x00, 0x00, 0x00};
2277 static const char code_atl3[] = {0xBA, 0x44, 0x33, 0x22, 0x11, 0xB9, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE1};
2278 static const char code_atl4[] = {0xB9, 0x44, 0x33, 0x22, 0x11, 0xB8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0};
2279 static const char code_atl5[] = {0x59, 0x58, 0x51, 0xFF, 0x60, 0x04};
2280 static const char cls_name[] = "atl_thunk_class";
2281 DWORD ret, size, old_prot;
2282 ULONG old_flags = MEM_EXECUTE_OPTION_ENABLE;
2283 BOOL success, restore_flags = FALSE;
2284 void *results[64];
2285 ULONG_PTR count;
2286 ULONG pagesize;
2287 WNDCLASSEXA wc;
2288 char *base;
2289 HWND hWnd;
2291 trace( "Running DEP tests with ProcessExecuteFlags = %d\n", dep_flags );
2293 NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &old_flags, sizeof(old_flags), NULL );
2294 if (old_flags != dep_flags)
2296 ret = NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &dep_flags, sizeof(dep_flags) );
2297 if (ret == STATUS_INVALID_INFO_CLASS) /* Windows 2000 */
2299 win_skip( "Skipping DEP tests with ProcessExecuteFlags = %d\n", dep_flags );
2300 return;
2302 ok( !ret, "NtSetInformationProcess failed with status %08x\n", ret );
2303 restore_flags = TRUE;
2306 size = 0x1000;
2307 base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
2308 ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
2310 /* Check result of GetProcessDEPPolicy */
2311 if (!pGetProcessDEPPolicy)
2312 win_skip( "GetProcessDEPPolicy not supported\n" );
2313 else
2315 BOOL (WINAPI *get_dep_policy)(HANDLE, LPDWORD, PBOOL) = (void *)base;
2316 BOOL policy_permanent = 0xdeadbeef;
2317 DWORD policy_flags = 0xdeadbeef;
2319 /* GetProcessDEPPolicy crashes on Windows when a NULL pointer is passed.
2320 * Moreover this function has a bug on Windows 8, which has the effect that
2321 * policy_permanent is set to the content of the CL register instead of 0,
2322 * when the policy is not permanent. To detect that we use an assembler
2323 * wrapper to call the function. */
2325 memcpy( base, code_atl2, sizeof(code_atl2) );
2326 *(DWORD *)(base + 6) = (DWORD_PTR)pGetProcessDEPPolicy - (DWORD_PTR)(base + 10);
2328 success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot );
2329 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2331 success = get_dep_policy( GetCurrentProcess(), &policy_flags, &policy_permanent );
2332 ok( success, "GetProcessDEPPolicy failed %u\n", GetLastError() );
2334 ret = 0;
2335 if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
2336 ret |= PROCESS_DEP_ENABLE;
2337 if (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)
2338 ret |= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION;
2340 ok( policy_flags == ret, "expected policy flags %d, got %d\n", ret, policy_flags );
2341 ok( !policy_permanent || broken(policy_permanent == 0x44),
2342 "expected policy permanent FALSE, got %d\n", policy_permanent );
2345 memcpy( base, code_jmp, sizeof(code_jmp) );
2346 *(DWORD *)(base + 1) = (DWORD_PTR)jmp_test_func - (DWORD_PTR)(base + 5);
2348 /* On Windows, the ATL Thunk emulation is only enabled while running WndProc functions,
2349 * whereas in Wine such a limitation doesn't exist yet. We want to test in a scenario
2350 * where it is active, so that application which depend on that still work properly.
2351 * We have no exception handler enabled yet, so give proper EXECUTE permissions to
2352 * prevent crashes while creating the window. */
2354 success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot );
2355 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2357 memset( &wc, 0, sizeof(wc) );
2358 wc.cbSize = sizeof(wc);
2359 wc.style = CS_VREDRAW | CS_HREDRAW;
2360 wc.hInstance = GetModuleHandleA( 0 );
2361 wc.hCursor = LoadCursorA( NULL, (LPCSTR)IDC_ARROW );
2362 wc.hbrBackground = NULL;
2363 wc.lpszClassName = cls_name;
2364 wc.lpfnWndProc = (WNDPROC)base;
2365 success = RegisterClassExA(&wc) != 0;
2366 ok( success, "RegisterClassExA failed %u\n", GetLastError() );
2368 hWnd = CreateWindowExA(0, cls_name, "Test", WS_TILEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
2369 ok( hWnd != 0, "CreateWindowExA failed %u\n", GetLastError() );
2371 ret = SendMessageA(hWnd, WM_USER, 0, 0);
2372 ok( ret == 42, "SendMessage returned unexpected result %d\n", ret );
2374 /* At first try with an instruction which is not recognized as proper ATL thunk
2375 * by the Windows ATL Thunk Emulator. Removing execute permissions will lead to
2376 * STATUS_ACCESS_VIOLATION exceptions when DEP is enabled. */
2378 success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2379 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2381 ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2382 ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
2383 ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2384 if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && !IsProcessorFeaturePresent( PF_NX_ENABLED ))
2386 trace( "DEP hardware support is not available\n" );
2387 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2388 dep_flags = MEM_EXECUTE_OPTION_ENABLE;
2390 else if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
2392 trace( "DEP hardware support is available\n" );
2393 ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2395 else
2396 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2398 /* Now a bit more complicated, the page containing the code is protected with
2399 * PAGE_GUARD memory protection. */
2401 success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
2402 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2404 ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2405 ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
2406 ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2407 if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
2408 ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2409 else
2410 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2412 ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2413 ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
2414 ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2415 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2417 /* Now test with a proper ATL thunk instruction. */
2419 memcpy( base, code_atl1, sizeof(code_atl1) );
2420 *(DWORD *)(base + 9) = (DWORD_PTR)atl_test_func - (DWORD_PTR)(base + 13);
2422 success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot );
2423 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2425 ret = SendMessageA(hWnd, WM_USER, 0, 0);
2426 ok( ret == 43, "SendMessage returned unexpected result %d\n", ret );
2428 /* Try executing with PAGE_READWRITE protection. */
2430 success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2431 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2433 ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2434 ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2435 ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2436 if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2437 ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2438 else
2439 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2441 /* Now a bit more complicated, the page containing the code is protected with
2442 * PAGE_GUARD memory protection. */
2444 success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
2445 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2447 /* the same, but with PAGE_GUARD set */
2448 ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2449 ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2450 ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2451 if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2452 ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2453 else
2454 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2456 ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2457 ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2458 ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2459 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2461 /* The following test shows that on Windows, even a vectored exception handler
2462 * cannot intercept internal exceptions thrown by the ATL thunk emulation layer. */
2464 if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && !(dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2466 if (pRtlAddVectoredExceptionHandler && pRtlRemoveVectoredExceptionHandler)
2468 PVOID vectored_handler;
2470 success = VirtualProtect( base, size, PAGE_NOACCESS, &old_prot );
2471 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2473 vectored_handler = pRtlAddVectoredExceptionHandler( TRUE, &execute_fault_vec_handler );
2474 ok( vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n" );
2476 ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2478 pRtlRemoveVectoredExceptionHandler( vectored_handler );
2480 ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2481 ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2483 else
2484 win_skip( "RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler not found\n" );
2487 /* Test alternative ATL thunk instructions. */
2489 memcpy( base, code_atl2, sizeof(code_atl2) );
2490 *(DWORD *)(base + 6) = (DWORD_PTR)atl_test_func - (DWORD_PTR)(base + 10);
2492 success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2493 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2495 ret = send_message_excpt( hWnd, WM_USER + 1, 0, 0 );
2496 /* FIXME: we don't check the content of the register ECX yet */
2497 ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2498 ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2499 if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2500 ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2501 else
2502 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2504 memcpy( base, code_atl3, sizeof(code_atl3) );
2505 *(DWORD *)(base + 6) = (DWORD_PTR)atl_test_func;
2507 success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2508 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2510 ret = send_message_excpt( hWnd, WM_USER + 1, 0, 0 );
2511 /* FIXME: we don't check the content of the registers ECX/EDX yet */
2512 ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2513 ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2514 if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2515 ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2516 else
2517 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2519 memcpy( base, code_atl4, sizeof(code_atl4) );
2520 *(DWORD *)(base + 6) = (DWORD_PTR)atl_test_func;
2522 success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2523 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2525 ret = send_message_excpt( hWnd, WM_USER + 1, 0, 0 );
2526 /* FIXME: We don't check the content of the registers EAX/ECX yet */
2527 ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2528 ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2529 if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2530 ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2531 else if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
2532 ok( num_execute_fault_calls == 0 || broken(num_execute_fault_calls == 1) /* Windows XP */,
2533 "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2534 else
2535 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2537 memcpy( base, code_atl5, sizeof(code_atl5) );
2539 success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2540 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2542 ret = (DWORD_PTR)atl5_test_func;
2543 ret = call_proc_excpt( (void *)base, &ret - 1 );
2544 /* FIXME: We don't check the content of the registers EAX/ECX yet */
2545 ok( ret == 44, "call returned wrong result, expected 44, got %d\n", ret );
2546 ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2547 if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2548 ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2549 else if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
2550 ok( num_execute_fault_calls == 0 || broken(num_execute_fault_calls == 1) /* Windows XP */,
2551 "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2552 else
2553 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2555 /* Restore the JMP instruction, set to executable, and then destroy the Window */
2557 memcpy( base, code_jmp, sizeof(code_jmp) );
2558 *(DWORD *)(base + 1) = (DWORD_PTR)jmp_test_func - (DWORD_PTR)(base + 5);
2560 success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot );
2561 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2563 DestroyWindow( hWnd );
2565 success = UnregisterClassA( cls_name, GetModuleHandleA(0) );
2566 ok( success, "UnregisterClass failed %u\n", GetLastError() );
2568 VirtualFree( base, 0, MEM_RELEASE );
2570 /* Repeat the tests from above with MEM_WRITE_WATCH protected memory. */
2572 base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT | MEM_WRITE_WATCH, PAGE_READWRITE );
2573 if (!base && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_NOT_SUPPORTED))
2575 win_skip( "MEM_WRITE_WATCH not supported\n" );
2576 goto out;
2578 ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
2580 count = 64;
2581 ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2582 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2583 ok( count == 0, "wrong count %lu\n", count );
2585 memcpy( base, code_jmp, sizeof(code_jmp) );
2586 *(DWORD *)(base + 1) = (DWORD_PTR)jmp_test_func - (DWORD_PTR)(base + 5);
2588 count = 64;
2589 ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2590 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2591 ok( count == 1, "wrong count %lu\n", count );
2592 ok( results[0] == base, "wrong result %p\n", results[0] );
2594 /* Create a new window class and associated Window (see above) */
2596 success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot );
2597 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2599 memset( &wc, 0, sizeof(wc) );
2600 wc.cbSize = sizeof(wc);
2601 wc.style = CS_VREDRAW | CS_HREDRAW;
2602 wc.hInstance = GetModuleHandleA( 0 );
2603 wc.hCursor = LoadCursorA( NULL, (LPCSTR)IDC_ARROW );
2604 wc.hbrBackground = NULL;
2605 wc.lpszClassName = cls_name;
2606 wc.lpfnWndProc = (WNDPROC)base;
2607 success = RegisterClassExA(&wc) != 0;
2608 ok( success, "RegisterClassExA failed %u\n", GetLastError() );
2610 hWnd = CreateWindowExA(0, cls_name, "Test", WS_TILEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
2611 ok( hWnd != 0, "CreateWindowExA failed %u\n", GetLastError() );
2613 ret = SendMessageA(hWnd, WM_USER, 0, 0);
2614 ok( ret == 42, "SendMessage returned unexpected result %d\n", ret );
2616 count = 64;
2617 ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2618 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2619 ok( count == 0, "wrong count %lu\n", count );
2621 /* At first try with an instruction which is not recognized as proper ATL thunk
2622 * by the Windows ATL Thunk Emulator. Removing execute permissions will lead to
2623 * STATUS_ACCESS_VIOLATION exceptions when DEP is enabled. */
2625 success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2626 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2628 ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2629 ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
2630 ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2631 if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
2632 ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2633 else
2634 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2636 count = 64;
2637 ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2638 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2639 ok( count == 0, "wrong count %lu\n", count );
2641 ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2642 ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
2643 ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2644 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2646 /* Now a bit more complicated, the page containing the code is protected with
2647 * PAGE_GUARD memory protection. */
2649 success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
2650 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2652 ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2653 ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
2654 ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2655 if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
2656 ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2657 else
2658 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2660 ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2661 ok( ret == 42, "call returned wrong result, expected 42, got %d\n", ret );
2662 ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2663 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2665 count = 64;
2666 ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2667 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2668 ok( count == 0 || broken(count == 1) /* Windows 8 */, "wrong count %lu\n", count );
2670 /* Now test with a proper ATL thunk instruction. */
2672 memcpy( base, code_atl1, sizeof(code_atl1) );
2673 *(DWORD *)(base + 9) = (DWORD_PTR)atl_test_func - (DWORD_PTR)(base + 13);
2675 count = 64;
2676 ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2677 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2678 ok( count == 1, "wrong count %lu\n", count );
2679 ok( results[0] == base, "wrong result %p\n", results[0] );
2681 success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot );
2682 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2684 ret = SendMessageA(hWnd, WM_USER, 0, 0);
2685 ok( ret == 43, "SendMessage returned unexpected result %d\n", ret );
2687 /* Try executing with PAGE_READWRITE protection. */
2689 success = VirtualProtect( base, size, PAGE_READWRITE, &old_prot );
2690 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2692 ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2693 ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2694 ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2695 if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2696 ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2697 else
2698 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
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 == 0, "wrong count %lu\n", count );
2705 ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2706 ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2707 ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2708 if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2709 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2710 else
2711 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2713 /* Now a bit more complicated, the page containing the code is protected with
2714 * PAGE_GUARD memory protection. */
2716 success = VirtualProtect( base, size, PAGE_READWRITE | PAGE_GUARD, &old_prot );
2717 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2719 /* the same, but with PAGE_GUARD set */
2720 ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2721 ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2722 ok( num_guard_page_calls == 1, "expected one STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2723 if ((dep_flags & MEM_EXECUTE_OPTION_DISABLE) && (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION))
2724 ok( num_execute_fault_calls == 1, "expected one STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2725 else
2726 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2728 ret = send_message_excpt( hWnd, WM_USER, 0, 0 );
2729 ok( ret == 43, "call returned wrong result, expected 43, got %d\n", ret );
2730 ok( num_guard_page_calls == 0, "expected no STATUS_GUARD_PAGE_VIOLATION exception, got %d exceptions\n", num_guard_page_calls );
2731 ok( num_execute_fault_calls == 0, "expected no STATUS_ACCESS_VIOLATION exception, got %d exceptions\n", num_execute_fault_calls );
2733 count = 64;
2734 ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2735 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2736 ok( count == 0 || broken(count == 1) /* Windows 8 */, "wrong count %lu\n", count );
2738 /* Restore the JMP instruction, set to executable, and then destroy the Window */
2740 memcpy( base, code_jmp, sizeof(code_jmp) );
2741 *(DWORD *)(base + 1) = (DWORD_PTR)jmp_test_func - (DWORD_PTR)(base + 5);
2743 count = 64;
2744 ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
2745 ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
2746 ok( count == 1, "wrong count %lu\n", count );
2747 ok( results[0] == base, "wrong result %p\n", results[0] );
2749 success = VirtualProtect( base, size, PAGE_EXECUTE_READWRITE, &old_prot );
2750 ok( success, "VirtualProtect failed %u\n", GetLastError() );
2752 DestroyWindow( hWnd );
2754 success = UnregisterClassA( cls_name, GetModuleHandleA(0) );
2755 ok( success, "UnregisterClass failed %u\n", GetLastError() );
2757 VirtualFree( base, 0, MEM_RELEASE );
2759 out:
2760 if (restore_flags)
2762 ret = NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &old_flags, sizeof(old_flags) );
2763 ok( !ret, "NtSetInformationProcess failed with status %08x\n", ret );
2767 #endif /* __i386__ */
2769 static void test_VirtualProtect(void)
2771 static const struct test_data
2773 DWORD prot_set, prot_get;
2774 } td[] =
2776 { 0, 0 }, /* 0x00 */
2777 { PAGE_NOACCESS, PAGE_NOACCESS }, /* 0x01 */
2778 { PAGE_READONLY, PAGE_READONLY }, /* 0x02 */
2779 { PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x03 */
2780 { PAGE_READWRITE, PAGE_READWRITE }, /* 0x04 */
2781 { PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x05 */
2782 { PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x06 */
2783 { PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x07 */
2784 { PAGE_WRITECOPY, 0 }, /* 0x08 */
2785 { PAGE_WRITECOPY | PAGE_NOACCESS, 0 }, /* 0x09 */
2786 { PAGE_WRITECOPY | PAGE_READONLY, 0 }, /* 0x0a */
2787 { PAGE_WRITECOPY | PAGE_NOACCESS | PAGE_READONLY, 0 }, /* 0x0b */
2788 { PAGE_WRITECOPY | PAGE_READWRITE, 0 }, /* 0x0c */
2789 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_NOACCESS, 0 }, /* 0x0d */
2790 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY, 0 }, /* 0x0e */
2791 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, 0 }, /* 0x0f */
2793 { PAGE_EXECUTE, PAGE_EXECUTE }, /* 0x10 */
2794 { PAGE_EXECUTE_READ, PAGE_EXECUTE_READ }, /* 0x20 */
2795 { PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x30 */
2796 { PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_READWRITE }, /* 0x40 */
2797 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0x50 */
2798 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0x60 */
2799 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0x70 */
2800 { PAGE_EXECUTE_WRITECOPY, 0 }, /* 0x80 */
2801 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE, 0 }, /* 0x90 */
2802 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ, 0 }, /* 0xa0 */
2803 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 }, /* 0xb0 */
2804 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE, 0 }, /* 0xc0 */
2805 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, 0 }, /* 0xd0 */
2806 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, 0 }, /* 0xe0 */
2807 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, 0 } /* 0xf0 */
2809 char *base, *ptr;
2810 DWORD ret, old_prot, rw_prot, exec_prot, i, j;
2811 MEMORY_BASIC_INFORMATION info;
2812 SYSTEM_INFO si;
2813 void *addr;
2814 SIZE_T size;
2815 NTSTATUS status;
2817 GetSystemInfo(&si);
2818 trace("system page size %#x\n", si.dwPageSize);
2820 SetLastError(0xdeadbeef);
2821 base = VirtualAlloc(0, si.dwPageSize, MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
2822 ok(base != NULL, "VirtualAlloc failed %d\n", GetLastError());
2824 SetLastError(0xdeadbeef);
2825 ret = VirtualProtect(base, si.dwPageSize, PAGE_READONLY, NULL);
2826 ok(!ret, "VirtualProtect should fail\n");
2827 ok(GetLastError() == ERROR_NOACCESS, "expected ERROR_NOACCESS, got %d\n", GetLastError());
2828 old_prot = 0xdeadbeef;
2829 ret = VirtualProtect(base, si.dwPageSize, PAGE_NOACCESS, &old_prot);
2830 ok(ret, "VirtualProtect failed %d\n", GetLastError());
2831 ok(old_prot == PAGE_NOACCESS, "got %#x != expected PAGE_NOACCESS\n", old_prot);
2833 addr = base;
2834 size = si.dwPageSize;
2835 status = pNtProtectVirtualMemory(GetCurrentProcess(), &addr, &size, PAGE_READONLY, NULL);
2836 ok(status == STATUS_ACCESS_VIOLATION, "NtProtectVirtualMemory should fail, got %08x\n", status);
2837 addr = base;
2838 size = si.dwPageSize;
2839 old_prot = 0xdeadbeef;
2840 status = pNtProtectVirtualMemory(GetCurrentProcess(), &addr, &size, PAGE_NOACCESS, &old_prot);
2841 ok(status == STATUS_SUCCESS, "NtProtectVirtualMemory should succeed, got %08x\n", status);
2842 ok(old_prot == PAGE_NOACCESS, "got %#x != expected PAGE_NOACCESS\n", old_prot);
2844 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
2846 SetLastError(0xdeadbeef);
2847 ret = VirtualQuery(base, &info, sizeof(info));
2848 ok(ret, "VirtualQuery failed %d\n", GetLastError());
2849 ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base);
2850 ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
2851 ok(info.Protect == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, info.Protect);
2852 ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
2853 ok(info.AllocationProtect == PAGE_NOACCESS, "%d: %#x != PAGE_NOACCESS\n", i, info.AllocationProtect);
2854 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
2855 ok(info.Type == MEM_PRIVATE, "%d: %#x != MEM_PRIVATE\n", i, info.Type);
2857 old_prot = 0xdeadbeef;
2858 SetLastError(0xdeadbeef);
2859 ret = VirtualProtect(base, si.dwPageSize, td[i].prot_set, &old_prot);
2860 if (td[i].prot_get)
2862 ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
2863 ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
2865 SetLastError(0xdeadbeef);
2866 ret = VirtualQuery(base, &info, sizeof(info));
2867 ok(ret, "VirtualQuery failed %d\n", GetLastError());
2868 ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base);
2869 ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
2870 ok(info.Protect == td[i].prot_get, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_get);
2871 ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
2872 ok(info.AllocationProtect == PAGE_NOACCESS, "%d: %#x != PAGE_NOACCESS\n", i, info.AllocationProtect);
2873 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
2874 ok(info.Type == MEM_PRIVATE, "%d: %#x != MEM_PRIVATE\n", i, info.Type);
2876 else
2878 ok(!ret, "%d: VirtualProtect should fail\n", i);
2879 ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
2882 old_prot = 0xdeadbeef;
2883 SetLastError(0xdeadbeef);
2884 ret = VirtualProtect(base, si.dwPageSize, PAGE_NOACCESS, &old_prot);
2885 ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
2886 if (td[i].prot_get)
2887 ok(old_prot == td[i].prot_get, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_get);
2888 else
2889 ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
2892 exec_prot = 0;
2894 for (i = 0; i <= 4; i++)
2896 rw_prot = 0;
2898 for (j = 0; j <= 4; j++)
2900 DWORD prot = exec_prot | rw_prot;
2902 SetLastError(0xdeadbeef);
2903 ptr = VirtualAlloc(base, si.dwPageSize, MEM_COMMIT, prot);
2904 if ((rw_prot && exec_prot) || (!rw_prot && !exec_prot))
2906 ok(!ptr, "VirtualAlloc(%02x) should fail\n", prot);
2907 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2909 else
2911 if (prot & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY))
2913 ok(!ptr, "VirtualAlloc(%02x) should fail\n", prot);
2914 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2916 else
2918 ok(ptr != NULL, "VirtualAlloc(%02x) error %d\n", prot, GetLastError());
2919 ok(ptr == base, "expected %p, got %p\n", base, ptr);
2923 SetLastError(0xdeadbeef);
2924 ret = VirtualProtect(base, si.dwPageSize, prot, &old_prot);
2925 if ((rw_prot && exec_prot) || (!rw_prot && !exec_prot))
2927 ok(!ret, "VirtualProtect(%02x) should fail\n", prot);
2928 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2930 else
2932 if (prot & (PAGE_WRITECOPY | PAGE_EXECUTE_WRITECOPY))
2934 ok(!ret, "VirtualProtect(%02x) should fail\n", prot);
2935 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2937 else
2938 ok(ret, "VirtualProtect(%02x) error %d\n", prot, GetLastError());
2941 rw_prot = 1 << j;
2944 exec_prot = 1 << (i + 4);
2947 VirtualFree(base, 0, MEM_RELEASE);
2950 static BOOL is_mem_writable(DWORD prot)
2952 switch (prot & 0xff)
2954 case PAGE_READWRITE:
2955 case PAGE_WRITECOPY:
2956 case PAGE_EXECUTE_READWRITE:
2957 case PAGE_EXECUTE_WRITECOPY:
2958 return TRUE;
2960 default:
2961 return FALSE;
2965 static void test_VirtualAlloc_protection(void)
2967 static const struct test_data
2969 DWORD prot;
2970 BOOL success;
2971 } td[] =
2973 { 0, FALSE }, /* 0x00 */
2974 { PAGE_NOACCESS, TRUE }, /* 0x01 */
2975 { PAGE_READONLY, TRUE }, /* 0x02 */
2976 { PAGE_READONLY | PAGE_NOACCESS, FALSE }, /* 0x03 */
2977 { PAGE_READWRITE, TRUE }, /* 0x04 */
2978 { PAGE_READWRITE | PAGE_NOACCESS, FALSE }, /* 0x05 */
2979 { PAGE_READWRITE | PAGE_READONLY, FALSE }, /* 0x06 */
2980 { PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, FALSE }, /* 0x07 */
2981 { PAGE_WRITECOPY, FALSE }, /* 0x08 */
2982 { PAGE_WRITECOPY | PAGE_NOACCESS, FALSE }, /* 0x09 */
2983 { PAGE_WRITECOPY | PAGE_READONLY, FALSE }, /* 0x0a */
2984 { PAGE_WRITECOPY | PAGE_NOACCESS | PAGE_READONLY, FALSE }, /* 0x0b */
2985 { PAGE_WRITECOPY | PAGE_READWRITE, FALSE }, /* 0x0c */
2986 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_NOACCESS, FALSE }, /* 0x0d */
2987 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY, FALSE }, /* 0x0e */
2988 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, FALSE }, /* 0x0f */
2990 { PAGE_EXECUTE, TRUE }, /* 0x10 */
2991 { PAGE_EXECUTE_READ, TRUE }, /* 0x20 */
2992 { PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE }, /* 0x30 */
2993 { PAGE_EXECUTE_READWRITE, TRUE }, /* 0x40 */
2994 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, FALSE }, /* 0x50 */
2995 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, FALSE }, /* 0x60 */
2996 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE }, /* 0x70 */
2997 { PAGE_EXECUTE_WRITECOPY, FALSE }, /* 0x80 */
2998 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE, FALSE }, /* 0x90 */
2999 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ, FALSE }, /* 0xa0 */
3000 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE }, /* 0xb0 */
3001 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE, FALSE }, /* 0xc0 */
3002 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, FALSE }, /* 0xd0 */
3003 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, FALSE }, /* 0xe0 */
3004 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE } /* 0xf0 */
3006 char *base, *ptr;
3007 DWORD ret, i;
3008 MEMORY_BASIC_INFORMATION info;
3009 SYSTEM_INFO si;
3011 GetSystemInfo(&si);
3012 trace("system page size %#x\n", si.dwPageSize);
3014 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
3016 SetLastError(0xdeadbeef);
3017 base = VirtualAlloc(0, si.dwPageSize, MEM_COMMIT, td[i].prot);
3019 if (td[i].success)
3021 ok(base != NULL, "%d: VirtualAlloc failed %d\n", i, GetLastError());
3023 SetLastError(0xdeadbeef);
3024 ret = VirtualQuery(base, &info, sizeof(info));
3025 ok(ret, "VirtualQuery failed %d\n", GetLastError());
3026 ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base);
3027 ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
3028 ok(info.Protect == td[i].prot, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot);
3029 ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
3030 ok(info.AllocationProtect == td[i].prot, "%d: %#x != %#x\n", i, info.AllocationProtect, td[i].prot);
3031 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
3032 ok(info.Type == MEM_PRIVATE, "%d: %#x != MEM_PRIVATE\n", i, info.Type);
3034 if (is_mem_writable(info.Protect))
3036 base[0] = 0xfe;
3038 SetLastError(0xdeadbeef);
3039 ret = VirtualQuery(base, &info, sizeof(info));
3040 ok(ret, "VirtualQuery failed %d\n", GetLastError());
3041 ok(info.Protect == td[i].prot, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot);
3044 SetLastError(0xdeadbeef);
3045 ptr = VirtualAlloc(base, si.dwPageSize, MEM_COMMIT, td[i].prot);
3046 ok(ptr == base, "%d: VirtualAlloc failed %d\n", i, GetLastError());
3048 VirtualFree(base, 0, MEM_RELEASE);
3050 else
3052 ok(!base, "%d: VirtualAlloc should fail\n", i);
3053 ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
3058 static void test_CreateFileMapping_protection(void)
3060 static const struct test_data
3062 DWORD prot;
3063 BOOL success;
3064 DWORD prot_after_write;
3065 } td[] =
3067 { 0, FALSE, 0 }, /* 0x00 */
3068 { PAGE_NOACCESS, FALSE, PAGE_NOACCESS }, /* 0x01 */
3069 { PAGE_READONLY, TRUE, PAGE_READONLY }, /* 0x02 */
3070 { PAGE_READONLY | PAGE_NOACCESS, FALSE, PAGE_NOACCESS }, /* 0x03 */
3071 { PAGE_READWRITE, TRUE, PAGE_READWRITE }, /* 0x04 */
3072 { PAGE_READWRITE | PAGE_NOACCESS, FALSE, PAGE_NOACCESS }, /* 0x05 */
3073 { PAGE_READWRITE | PAGE_READONLY, FALSE, PAGE_NOACCESS }, /* 0x06 */
3074 { PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, FALSE, PAGE_NOACCESS }, /* 0x07 */
3075 { PAGE_WRITECOPY, TRUE, PAGE_READWRITE }, /* 0x08 */
3076 { PAGE_WRITECOPY | PAGE_NOACCESS, FALSE, PAGE_NOACCESS }, /* 0x09 */
3077 { PAGE_WRITECOPY | PAGE_READONLY, FALSE, PAGE_NOACCESS }, /* 0x0a */
3078 { PAGE_WRITECOPY | PAGE_NOACCESS | PAGE_READONLY, FALSE, PAGE_NOACCESS }, /* 0x0b */
3079 { PAGE_WRITECOPY | PAGE_READWRITE, FALSE, PAGE_NOACCESS }, /* 0x0c */
3080 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_NOACCESS, FALSE, PAGE_NOACCESS }, /* 0x0d */
3081 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY, FALSE, PAGE_NOACCESS }, /* 0x0e */
3082 { PAGE_WRITECOPY | PAGE_READWRITE | PAGE_READONLY | PAGE_NOACCESS, FALSE, PAGE_NOACCESS }, /* 0x0f */
3084 { PAGE_EXECUTE, FALSE, PAGE_EXECUTE }, /* 0x10 */
3085 { PAGE_EXECUTE_READ, TRUE, PAGE_EXECUTE_READ }, /* 0x20 */
3086 { PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE, PAGE_EXECUTE_READ }, /* 0x30 */
3087 { PAGE_EXECUTE_READWRITE, TRUE, PAGE_EXECUTE_READWRITE }, /* 0x40 */
3088 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, FALSE, PAGE_NOACCESS }, /* 0x50 */
3089 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, FALSE, PAGE_NOACCESS }, /* 0x60 */
3090 { PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE, PAGE_NOACCESS }, /* 0x70 */
3091 { PAGE_EXECUTE_WRITECOPY, TRUE, PAGE_EXECUTE_READWRITE }, /* 0x80 */
3092 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE, FALSE, PAGE_NOACCESS }, /* 0x90 */
3093 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ, FALSE, PAGE_NOACCESS }, /* 0xa0 */
3094 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE, PAGE_NOACCESS }, /* 0xb0 */
3095 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE, FALSE, PAGE_NOACCESS }, /* 0xc0 */
3096 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE, FALSE, PAGE_NOACCESS }, /* 0xd0 */
3097 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ, FALSE, PAGE_NOACCESS }, /* 0xe0 */
3098 { PAGE_EXECUTE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE, FALSE, PAGE_NOACCESS } /* 0xf0 */
3100 char *base, *ptr;
3101 DWORD ret, i, alloc_prot, prot, old_prot;
3102 MEMORY_BASIC_INFORMATION info;
3103 SYSTEM_INFO si;
3104 char temp_path[MAX_PATH];
3105 char file_name[MAX_PATH];
3106 HANDLE hfile, hmap;
3107 BOOL page_exec_supported = TRUE;
3109 GetSystemInfo(&si);
3110 trace("system page size %#x\n", si.dwPageSize);
3112 GetTempPathA(MAX_PATH, temp_path);
3113 GetTempFileNameA(temp_path, "map", 0, file_name);
3115 SetLastError(0xdeadbeef);
3116 hfile = CreateFileA(file_name, GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE, 0, NULL, CREATE_ALWAYS, 0, 0);
3117 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile(%s) error %d\n", file_name, GetLastError());
3118 SetFilePointer(hfile, si.dwPageSize, NULL, FILE_BEGIN);
3119 SetEndOfFile(hfile);
3121 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
3123 SetLastError(0xdeadbeef);
3124 hmap = CreateFileMappingW(hfile, NULL, td[i].prot | SEC_COMMIT, 0, si.dwPageSize, NULL);
3126 if (td[i].success)
3128 if (!hmap)
3130 trace("%d: CreateFileMapping(%04x) failed: %d\n", i, td[i].prot, GetLastError());
3131 /* NT4 and win2k don't support EXEC on file mappings */
3132 if (td[i].prot == PAGE_EXECUTE_READ || td[i].prot == PAGE_EXECUTE_READWRITE)
3134 page_exec_supported = FALSE;
3135 ok(broken(!hmap), "%d: CreateFileMapping doesn't support PAGE_EXECUTE\n", i);
3136 continue;
3138 /* Vista+ supports PAGE_EXECUTE_WRITECOPY, earlier versions don't */
3139 if (td[i].prot == PAGE_EXECUTE_WRITECOPY)
3141 page_exec_supported = FALSE;
3142 ok(broken(!hmap), "%d: CreateFileMapping doesn't support PAGE_EXECUTE_WRITECOPY\n", i);
3143 continue;
3146 ok(hmap != 0, "%d: CreateFileMapping(%04x) error %d\n", i, td[i].prot, GetLastError());
3148 base = MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0);
3149 ok(base != NULL, "%d: MapViewOfFile failed %d\n", i, GetLastError());
3151 SetLastError(0xdeadbeef);
3152 ret = VirtualQuery(base, &info, sizeof(info));
3153 ok(ret, "VirtualQuery failed %d\n", GetLastError());
3154 ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base);
3155 ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
3156 ok(info.Protect == PAGE_READONLY, "%d: got %#x != expected PAGE_READONLY\n", i, info.Protect);
3157 ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
3158 ok(info.AllocationProtect == PAGE_READONLY, "%d: %#x != PAGE_READONLY\n", i, info.AllocationProtect);
3159 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
3160 ok(info.Type == MEM_MAPPED, "%d: %#x != MEM_MAPPED\n", i, info.Type);
3162 if (is_mem_writable(info.Protect))
3164 base[0] = 0xfe;
3166 SetLastError(0xdeadbeef);
3167 ret = VirtualQuery(base, &info, sizeof(info));
3168 ok(ret, "VirtualQuery failed %d\n", GetLastError());
3169 ok(info.Protect == td[i].prot, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot);
3172 SetLastError(0xdeadbeef);
3173 ptr = VirtualAlloc(base, si.dwPageSize, MEM_COMMIT, td[i].prot);
3174 ok(!ptr, "%d: VirtualAlloc(%02x) should fail\n", i, td[i].prot);
3175 /* FIXME: remove once Wine is fixed */
3176 todo_wine_if (td[i].prot == PAGE_WRITECOPY || td[i].prot == PAGE_EXECUTE_WRITECOPY)
3177 ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError());
3179 SetLastError(0xdeadbeef);
3180 ret = VirtualProtect(base, si.dwPageSize, td[i].prot, &old_prot);
3181 if (td[i].prot == PAGE_READONLY || td[i].prot == PAGE_WRITECOPY)
3182 ok(ret, "%d: VirtualProtect(%02x) error %d\n", i, td[i].prot, GetLastError());
3183 else
3185 ok(!ret, "%d: VirtualProtect(%02x) should fail\n", i, td[i].prot);
3186 ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
3189 UnmapViewOfFile(base);
3190 CloseHandle(hmap);
3192 else
3194 ok(!hmap, "%d: CreateFileMapping should fail\n", i);
3195 ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
3199 if (page_exec_supported) alloc_prot = PAGE_EXECUTE_READWRITE;
3200 else alloc_prot = PAGE_READWRITE;
3201 SetLastError(0xdeadbeef);
3202 hmap = CreateFileMappingW(hfile, NULL, alloc_prot, 0, si.dwPageSize, NULL);
3203 ok(hmap != 0, "%d: CreateFileMapping error %d\n", i, GetLastError());
3205 SetLastError(0xdeadbeef);
3206 base = MapViewOfFile(hmap, FILE_MAP_READ | FILE_MAP_WRITE | (page_exec_supported ? FILE_MAP_EXECUTE : 0), 0, 0, 0);
3207 ok(base != NULL, "MapViewOfFile failed %d\n", GetLastError());
3209 old_prot = 0xdeadbeef;
3210 SetLastError(0xdeadbeef);
3211 ret = VirtualProtect(base, si.dwPageSize, PAGE_NOACCESS, &old_prot);
3212 ok(ret, "VirtualProtect error %d\n", GetLastError());
3213 ok(old_prot == alloc_prot, "got %#x != expected %#x\n", old_prot, alloc_prot);
3215 for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
3217 SetLastError(0xdeadbeef);
3218 ret = VirtualQuery(base, &info, sizeof(info));
3219 ok(ret, "VirtualQuery failed %d\n", GetLastError());
3220 ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base);
3221 ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
3222 ok(info.Protect == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, info.Protect);
3223 ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
3224 ok(info.AllocationProtect == alloc_prot, "%d: %#x != %#x\n", i, info.AllocationProtect, alloc_prot);
3225 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
3226 ok(info.Type == MEM_MAPPED, "%d: %#x != MEM_MAPPED\n", i, info.Type);
3228 old_prot = 0xdeadbeef;
3229 SetLastError(0xdeadbeef);
3230 ret = VirtualProtect(base, si.dwPageSize, td[i].prot, &old_prot);
3231 if (td[i].success || td[i].prot == PAGE_NOACCESS || td[i].prot == PAGE_EXECUTE)
3233 if (!ret)
3235 /* win2k and XP don't support EXEC on file mappings */
3236 if (td[i].prot == PAGE_EXECUTE)
3238 ok(broken(!ret), "%d: VirtualProtect doesn't support PAGE_EXECUTE\n", i);
3239 continue;
3241 /* NT4 and win2k don't support EXEC on file mappings */
3242 if (td[i].prot == PAGE_EXECUTE_READ || td[i].prot == PAGE_EXECUTE_READWRITE)
3244 ok(broken(!ret), "%d: VirtualProtect doesn't support PAGE_EXECUTE\n", i);
3245 continue;
3247 /* Vista+ supports PAGE_EXECUTE_WRITECOPY, earlier versions don't */
3248 if (td[i].prot == PAGE_EXECUTE_WRITECOPY)
3250 ok(broken(!ret), "%d: VirtualProtect doesn't support PAGE_EXECUTE_WRITECOPY\n", i);
3251 continue;
3255 ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
3256 ok(old_prot == PAGE_NOACCESS, "%d: got %#x != expected PAGE_NOACCESS\n", i, old_prot);
3258 prot = td[i].prot;
3259 /* looks strange but Windows doesn't do this for PAGE_WRITECOPY */
3260 if (prot == PAGE_EXECUTE_WRITECOPY) prot = PAGE_EXECUTE_READWRITE;
3262 SetLastError(0xdeadbeef);
3263 ret = VirtualQuery(base, &info, sizeof(info));
3264 ok(ret, "VirtualQuery failed %d\n", GetLastError());
3265 ok(info.BaseAddress == base, "%d: got %p != expected %p\n", i, info.BaseAddress, base);
3266 ok(info.RegionSize == si.dwPageSize, "%d: got %#lx != expected %#x\n", i, info.RegionSize, si.dwPageSize);
3267 /* FIXME: remove the condition below once Wine is fixed */
3268 todo_wine_if (td[i].prot == PAGE_EXECUTE_WRITECOPY)
3269 ok(info.Protect == prot, "%d: got %#x != expected %#x\n", i, info.Protect, prot);
3270 ok(info.AllocationBase == base, "%d: %p != %p\n", i, info.AllocationBase, base);
3271 ok(info.AllocationProtect == alloc_prot, "%d: %#x != %#x\n", i, info.AllocationProtect, alloc_prot);
3272 ok(info.State == MEM_COMMIT, "%d: %#x != MEM_COMMIT\n", i, info.State);
3273 ok(info.Type == MEM_MAPPED, "%d: %#x != MEM_MAPPED\n", i, info.Type);
3275 if (is_mem_writable(info.Protect))
3277 base[0] = 0xfe;
3279 SetLastError(0xdeadbeef);
3280 ret = VirtualQuery(base, &info, sizeof(info));
3281 ok(ret, "VirtualQuery failed %d\n", GetLastError());
3282 /* FIXME: remove the condition below once Wine is fixed */
3283 todo_wine_if (td[i].prot == PAGE_WRITECOPY || td[i].prot == PAGE_EXECUTE_WRITECOPY)
3284 ok(info.Protect == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, info.Protect, td[i].prot_after_write);
3287 else
3289 ok(!ret, "%d: VirtualProtect should fail\n", i);
3290 ok(GetLastError() == ERROR_INVALID_PARAMETER, "%d: expected ERROR_INVALID_PARAMETER, got %d\n", i, GetLastError());
3291 continue;
3294 old_prot = 0xdeadbeef;
3295 SetLastError(0xdeadbeef);
3296 ret = VirtualProtect(base, si.dwPageSize, PAGE_NOACCESS, &old_prot);
3297 ok(ret, "%d: VirtualProtect error %d\n", i, GetLastError());
3298 /* FIXME: remove the condition below once Wine is fixed */
3299 todo_wine_if (td[i].prot == PAGE_WRITECOPY || td[i].prot == PAGE_EXECUTE_WRITECOPY)
3300 ok(old_prot == td[i].prot_after_write, "%d: got %#x != expected %#x\n", i, old_prot, td[i].prot_after_write);
3303 UnmapViewOfFile(base);
3304 CloseHandle(hmap);
3306 CloseHandle(hfile);
3307 DeleteFileA(file_name);
3310 #define ACCESS_READ 0x01
3311 #define ACCESS_WRITE 0x02
3312 #define ACCESS_EXECUTE 0x04
3313 #define ACCESS_WRITECOPY 0x08
3315 static DWORD page_prot_to_access(DWORD prot)
3317 switch (prot)
3319 case PAGE_READWRITE:
3320 return ACCESS_READ | ACCESS_WRITE;
3322 case PAGE_EXECUTE:
3323 case PAGE_EXECUTE_READ:
3324 return ACCESS_READ | ACCESS_EXECUTE;
3326 case PAGE_EXECUTE_READWRITE:
3327 return ACCESS_READ | ACCESS_WRITE | ACCESS_WRITECOPY | ACCESS_EXECUTE;
3329 case PAGE_EXECUTE_WRITECOPY:
3330 return ACCESS_READ | ACCESS_WRITECOPY | ACCESS_EXECUTE;
3332 case PAGE_READONLY:
3333 return ACCESS_READ;
3335 case PAGE_WRITECOPY:
3336 return ACCESS_READ;
3338 default:
3339 return 0;
3343 static BOOL is_compatible_protection(DWORD map_prot, DWORD view_prot, DWORD prot)
3345 DWORD map_access, view_access, prot_access;
3347 map_access = page_prot_to_access(map_prot);
3348 view_access = page_prot_to_access(view_prot);
3349 prot_access = page_prot_to_access(prot);
3351 if (view_access == prot_access) return TRUE;
3352 if (!view_access) return FALSE;
3354 if ((view_access & prot_access) != prot_access) return FALSE;
3355 if ((map_access & prot_access) == prot_access) return TRUE;
3357 return FALSE;
3360 static DWORD map_prot_to_access(DWORD prot)
3362 switch (prot)
3364 case PAGE_READWRITE:
3365 case PAGE_EXECUTE_READWRITE:
3366 return SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE | SECTION_MAP_EXECUTE_EXPLICIT | SECTION_QUERY;
3367 case PAGE_READONLY:
3368 case PAGE_WRITECOPY:
3369 case PAGE_EXECUTE:
3370 case PAGE_EXECUTE_READ:
3371 case PAGE_EXECUTE_WRITECOPY:
3372 return SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_MAP_EXECUTE_EXPLICIT | SECTION_QUERY;
3373 default:
3374 return 0;
3378 static BOOL is_compatible_access(DWORD map_prot, DWORD view_prot)
3380 DWORD access = map_prot_to_access(map_prot);
3381 if (!view_prot) view_prot = SECTION_MAP_READ;
3382 return (view_prot & access) == view_prot;
3385 static void *map_view_of_file(HANDLE handle, DWORD access)
3387 NTSTATUS status;
3388 LARGE_INTEGER offset;
3389 SIZE_T count;
3390 ULONG protect;
3391 BOOL exec;
3392 void *addr;
3394 if (!pNtMapViewOfSection) return NULL;
3396 count = 0;
3397 offset.u.LowPart = 0;
3398 offset.u.HighPart = 0;
3400 exec = access & FILE_MAP_EXECUTE;
3401 access &= ~FILE_MAP_EXECUTE;
3403 if (access == FILE_MAP_COPY)
3405 if (exec)
3406 protect = PAGE_EXECUTE_WRITECOPY;
3407 else
3408 protect = PAGE_WRITECOPY;
3410 else if (access & FILE_MAP_WRITE)
3412 if (exec)
3413 protect = PAGE_EXECUTE_READWRITE;
3414 else
3415 protect = PAGE_READWRITE;
3417 else if (access & FILE_MAP_READ)
3419 if (exec)
3420 protect = PAGE_EXECUTE_READ;
3421 else
3422 protect = PAGE_READONLY;
3424 else protect = PAGE_NOACCESS;
3426 addr = NULL;
3427 status = pNtMapViewOfSection(handle, GetCurrentProcess(), &addr, 0, 0, &offset,
3428 &count, 1 /* ViewShare */, 0, protect);
3429 if (status)
3431 /* for simplicity */
3432 SetLastError(ERROR_ACCESS_DENIED);
3433 addr = NULL;
3435 return addr;
3438 static void test_mapping(void)
3440 static const DWORD page_prot[] =
3442 PAGE_NOACCESS, PAGE_READONLY, PAGE_READWRITE, PAGE_WRITECOPY,
3443 PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY
3445 static const struct
3447 DWORD access, prot;
3448 } view[] =
3450 { 0, PAGE_NOACCESS }, /* 0x00 */
3451 { FILE_MAP_COPY, PAGE_WRITECOPY }, /* 0x01 */
3452 { FILE_MAP_WRITE, PAGE_READWRITE }, /* 0x02 */
3453 { FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_READWRITE }, /* 0x03 */
3454 { FILE_MAP_READ, PAGE_READONLY }, /* 0x04 */
3455 { FILE_MAP_READ | FILE_MAP_COPY, PAGE_READONLY }, /* 0x05 */
3456 { FILE_MAP_READ | FILE_MAP_WRITE, PAGE_READWRITE }, /* 0x06 */
3457 { FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_READWRITE }, /* 0x07 */
3458 { SECTION_MAP_EXECUTE, PAGE_NOACCESS }, /* 0x08 */
3459 { SECTION_MAP_EXECUTE | FILE_MAP_COPY, PAGE_NOACCESS }, /* 0x09 */
3460 { SECTION_MAP_EXECUTE | FILE_MAP_WRITE, PAGE_READWRITE }, /* 0x0a */
3461 { SECTION_MAP_EXECUTE | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_READWRITE }, /* 0x0b */
3462 { SECTION_MAP_EXECUTE | FILE_MAP_READ, PAGE_READONLY }, /* 0x0c */
3463 { SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_COPY, PAGE_READONLY }, /* 0x0d */
3464 { SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE, PAGE_READWRITE }, /* 0x0e */
3465 { SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_READWRITE }, /* 0x0f */
3466 { FILE_MAP_EXECUTE, PAGE_NOACCESS }, /* 0x20 */
3467 { FILE_MAP_EXECUTE | FILE_MAP_COPY, PAGE_EXECUTE_WRITECOPY }, /* 0x21 */
3468 { FILE_MAP_EXECUTE | FILE_MAP_WRITE, PAGE_EXECUTE_READWRITE }, /* 0x22 */
3469 { FILE_MAP_EXECUTE | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_EXECUTE_READWRITE }, /* 0x23 */
3470 { FILE_MAP_EXECUTE | FILE_MAP_READ, PAGE_EXECUTE_READ }, /* 0x24 */
3471 { FILE_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_COPY, PAGE_EXECUTE_READ }, /* 0x25 */
3472 { FILE_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE, PAGE_EXECUTE_READWRITE }, /* 0x26 */
3473 { FILE_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_EXECUTE_READWRITE }, /* 0x27 */
3474 { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE, PAGE_NOACCESS }, /* 0x28 */
3475 { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_COPY, PAGE_NOACCESS }, /* 0x29 */
3476 { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_WRITE, PAGE_EXECUTE_READWRITE }, /* 0x2a */
3477 { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_EXECUTE_READWRITE }, /* 0x2b */
3478 { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_READ, PAGE_EXECUTE_READ }, /* 0x2c */
3479 { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_COPY, PAGE_EXECUTE_READ }, /* 0x2d */
3480 { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE, PAGE_EXECUTE_READWRITE }, /* 0x2e */
3481 { FILE_MAP_EXECUTE | SECTION_MAP_EXECUTE | FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_COPY, PAGE_EXECUTE_READWRITE } /* 0x2f */
3483 void *base, *nt_base, *ptr;
3484 DWORD i, j, k, ret, old_prot, prev_prot;
3485 SYSTEM_INFO si;
3486 char temp_path[MAX_PATH];
3487 char file_name[MAX_PATH];
3488 HANDLE hfile, hmap;
3489 MEMORY_BASIC_INFORMATION info, nt_info;
3491 GetSystemInfo(&si);
3492 trace("system page size %#x\n", si.dwPageSize);
3494 GetTempPathA(MAX_PATH, temp_path);
3495 GetTempFileNameA(temp_path, "map", 0, file_name);
3497 SetLastError(0xdeadbeef);
3498 hfile = CreateFileA(file_name, GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE, 0, NULL, CREATE_ALWAYS, 0, 0);
3499 ok(hfile != INVALID_HANDLE_VALUE, "CreateFile(%s) error %d\n", file_name, GetLastError());
3500 SetFilePointer(hfile, si.dwPageSize, NULL, FILE_BEGIN);
3501 SetEndOfFile(hfile);
3503 for (i = 0; i < sizeof(page_prot)/sizeof(page_prot[0]); i++)
3505 SetLastError(0xdeadbeef);
3506 hmap = CreateFileMappingW(hfile, NULL, page_prot[i] | SEC_COMMIT, 0, si.dwPageSize, NULL);
3508 if (page_prot[i] == PAGE_NOACCESS)
3510 HANDLE hmap2;
3512 ok(!hmap, "CreateFileMapping(PAGE_NOACCESS) should fail\n");
3513 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3515 /* A trick to create a not accessible mapping */
3516 SetLastError(0xdeadbeef);
3517 hmap = CreateFileMappingW(hfile, NULL, PAGE_READWRITE | SEC_COMMIT, 0, si.dwPageSize, NULL);
3518 ok(hmap != 0, "CreateFileMapping(PAGE_READWRITE) error %d\n", GetLastError());
3519 SetLastError(0xdeadbeef);
3520 ret = DuplicateHandle(GetCurrentProcess(), hmap, GetCurrentProcess(), &hmap2, 0, FALSE, 0);
3521 ok(ret, "DuplicateHandle error %d\n", GetLastError());
3522 CloseHandle(hmap);
3523 hmap = hmap2;
3526 if (!hmap)
3528 trace("%d: CreateFileMapping(%04x) failed: %d\n", i, page_prot[i], GetLastError());
3530 /* NT4 and win2k don't support EXEC on file mappings */
3531 if (page_prot[i] == PAGE_EXECUTE_READ || page_prot[i] == PAGE_EXECUTE_READWRITE)
3533 ok(broken(!hmap), "%d: CreateFileMapping doesn't support PAGE_EXECUTE\n", i);
3534 continue;
3536 /* Vista+ supports PAGE_EXECUTE_WRITECOPY, earlier versions don't */
3537 if (page_prot[i] == PAGE_EXECUTE_WRITECOPY)
3539 ok(broken(!hmap), "%d: CreateFileMapping doesn't support PAGE_EXECUTE_WRITECOPY\n", i);
3540 continue;
3544 ok(hmap != 0, "%d: CreateFileMapping(%04x) error %d\n", i, page_prot[i], GetLastError());
3546 for (j = 0; j < sizeof(view)/sizeof(view[0]); j++)
3548 nt_base = map_view_of_file(hmap, view[j].access);
3549 if (nt_base)
3551 SetLastError(0xdeadbeef);
3552 ret = VirtualQuery(nt_base, &nt_info, sizeof(nt_info));
3553 ok(ret, "%d: VirtualQuery failed %d\n", j, GetLastError());
3554 UnmapViewOfFile(nt_base);
3557 SetLastError(0xdeadbeef);
3558 base = MapViewOfFile(hmap, view[j].access, 0, 0, 0);
3560 /* Vista+ supports FILE_MAP_EXECUTE properly, earlier versions don't */
3561 ok(!nt_base == !base ||
3562 broken((view[j].access & FILE_MAP_EXECUTE) && !nt_base != !base),
3563 "%d: (%04x/%04x) NT %p kernel %p\n", j, page_prot[i], view[j].access, nt_base, base);
3565 if (!is_compatible_access(page_prot[i], view[j].access))
3567 ok(!base, "%d: MapViewOfFile(%04x/%04x) should fail\n", j, page_prot[i], view[j].access);
3568 ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error %d\n", GetLastError());
3569 continue;
3572 /* Vista+ properly supports FILE_MAP_EXECUTE, earlier versions don't */
3573 if (!base && (view[j].access & FILE_MAP_EXECUTE))
3575 ok(broken(!base), "%d: MapViewOfFile(%04x/%04x) failed %d\n", j, page_prot[i], view[j].access, GetLastError());
3576 continue;
3579 ok(base != NULL, "%d: MapViewOfFile(%04x/%04x) failed %d\n", j, page_prot[i], view[j].access, GetLastError());
3581 SetLastError(0xdeadbeef);
3582 ret = VirtualQuery(base, &info, sizeof(info));
3583 ok(ret, "%d: VirtualQuery failed %d\n", j, GetLastError());
3584 ok(info.BaseAddress == base, "%d: (%04x) got %p, expected %p\n", j, view[j].access, info.BaseAddress, base);
3585 ok(info.RegionSize == si.dwPageSize, "%d: (%04x) got %#lx != expected %#x\n", j, view[j].access, info.RegionSize, si.dwPageSize);
3586 ok(info.Protect == view[j].prot ||
3587 broken(view[j].prot == PAGE_EXECUTE_READ && info.Protect == PAGE_READONLY) || /* win2k */
3588 broken(view[j].prot == PAGE_EXECUTE_READWRITE && info.Protect == PAGE_READWRITE) || /* win2k */
3589 broken(view[j].prot == PAGE_EXECUTE_WRITECOPY && info.Protect == PAGE_NOACCESS), /* XP */
3590 "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, info.Protect, view[j].prot);
3591 ok(info.AllocationBase == base, "%d: (%04x) got %p, expected %p\n", j, view[j].access, info.AllocationBase, base);
3592 ok(info.AllocationProtect == info.Protect, "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, info.AllocationProtect, info.Protect);
3593 ok(info.State == MEM_COMMIT, "%d: (%04x) got %#x, expected MEM_COMMIT\n", j, view[j].access, info.State);
3594 ok(info.Type == MEM_MAPPED, "%d: (%04x) got %#x, expected MEM_MAPPED\n", j, view[j].access, info.Type);
3596 if (nt_base && base)
3598 ok(nt_info.RegionSize == info.RegionSize, "%d: (%04x) got %#lx != expected %#lx\n", j, view[j].access, nt_info.RegionSize, info.RegionSize);
3599 ok(nt_info.Protect == info.Protect /* Vista+ */ ||
3600 broken(nt_info.AllocationProtect == PAGE_EXECUTE_WRITECOPY && info.Protect == PAGE_NOACCESS), /* XP */
3601 "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, nt_info.Protect, info.Protect);
3602 ok(nt_info.AllocationProtect == info.AllocationProtect /* Vista+ */ ||
3603 broken(nt_info.AllocationProtect == PAGE_EXECUTE_WRITECOPY && info.Protect == PAGE_NOACCESS), /* XP */
3604 "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, nt_info.AllocationProtect, info.AllocationProtect);
3605 ok(nt_info.State == info.State, "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, nt_info.State, info.State);
3606 ok(nt_info.Type == info.Type, "%d: (%04x) got %#x, expected %#x\n", j, view[j].access, nt_info.Type, info.Type);
3609 prev_prot = info.Protect;
3611 for (k = 0; k < sizeof(page_prot)/sizeof(page_prot[0]); k++)
3613 /*trace("map %#x, view %#x, requested prot %#x\n", page_prot[i], view[j].prot, page_prot[k]);*/
3614 SetLastError(0xdeadbeef);
3615 old_prot = 0xdeadbeef;
3616 ret = VirtualProtect(base, si.dwPageSize, page_prot[k], &old_prot);
3617 if (is_compatible_protection(page_prot[i], view[j].prot, page_prot[k]))
3619 /* win2k and XP don't support EXEC on file mappings */
3620 if (!ret && page_prot[k] == PAGE_EXECUTE)
3622 ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE\n");
3623 continue;
3625 /* NT4 and win2k don't support EXEC on file mappings */
3626 if (!ret && (page_prot[k] == PAGE_EXECUTE_READ || page_prot[k] == PAGE_EXECUTE_READWRITE))
3628 ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE\n");
3629 continue;
3631 /* Vista+ supports PAGE_EXECUTE_WRITECOPY, earlier versions don't */
3632 if (!ret && page_prot[k] == PAGE_EXECUTE_WRITECOPY)
3634 ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE_WRITECOPY\n");
3635 continue;
3637 /* win2k and XP don't support PAGE_EXECUTE_WRITECOPY views properly */
3638 if (!ret && view[j].prot == PAGE_EXECUTE_WRITECOPY)
3640 ok(broken(!ret), "VirtualProtect doesn't support PAGE_EXECUTE_WRITECOPY view properly\n");
3641 continue;
3644 ok(ret, "VirtualProtect error %d, map %#x, view %#x, requested prot %#x\n", GetLastError(), page_prot[i], view[j].prot, page_prot[k]);
3645 ok(old_prot == prev_prot, "got %#x, expected %#x\n", old_prot, prev_prot);
3646 prev_prot = page_prot[k];
3648 else
3650 /* NT4 doesn't fail on incompatible map and view */
3651 if (ret)
3653 ok(broken(ret), "VirtualProtect should fail, map %#x, view %#x, requested prot %#x\n", page_prot[i], view[j].prot, page_prot[k]);
3654 skip("Incompatible map and view are not properly handled on this platform\n");
3655 break; /* NT4 won't pass remaining tests */
3658 ok(!ret, "VirtualProtect should fail, map %#x, view %#x, requested prot %#x\n", page_prot[i], view[j].prot, page_prot[k]);
3659 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
3663 for (k = 0; k < sizeof(page_prot)/sizeof(page_prot[0]); k++)
3665 /*trace("map %#x, view %#x, requested prot %#x\n", page_prot[i], view[j].prot, page_prot[k]);*/
3666 SetLastError(0xdeadbeef);
3667 ptr = VirtualAlloc(base, si.dwPageSize, MEM_COMMIT, page_prot[k]);
3668 ok(!ptr, "VirtualAlloc(%02x) should fail\n", page_prot[k]);
3669 /* FIXME: remove once Wine is fixed */
3670 todo_wine_if (page_prot[k] == PAGE_WRITECOPY || page_prot[k] == PAGE_EXECUTE_WRITECOPY)
3671 ok(GetLastError() == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
3674 UnmapViewOfFile(base);
3677 CloseHandle(hmap);
3680 CloseHandle(hfile);
3681 DeleteFileA(file_name);
3684 static void test_shared_memory(BOOL is_child)
3686 HANDLE mapping;
3687 LONG *p;
3689 SetLastError(0xdeadbef);
3690 mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_virtual.c");
3691 ok(mapping != 0, "CreateFileMapping error %d\n", GetLastError());
3692 if (is_child)
3693 ok(GetLastError() == ERROR_ALREADY_EXISTS, "expected ERROR_ALREADY_EXISTS, got %d\n", GetLastError());
3695 SetLastError(0xdeadbef);
3696 p = MapViewOfFile(mapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 4096);
3697 ok(p != NULL, "MapViewOfFile error %d\n", GetLastError());
3699 if (is_child)
3701 ok(*p == 0x1a2b3c4d, "expected 0x1a2b3c4d in child, got %#x\n", *p);
3703 else
3705 char **argv;
3706 char cmdline[MAX_PATH];
3707 PROCESS_INFORMATION pi;
3708 STARTUPINFOA si = { sizeof(si) };
3709 DWORD ret;
3711 *p = 0x1a2b3c4d;
3713 winetest_get_mainargs(&argv);
3714 sprintf(cmdline, "\"%s\" virtual sharedmem", argv[0]);
3715 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3716 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
3717 winetest_wait_child_process(pi.hProcess);
3718 CloseHandle(pi.hThread);
3719 CloseHandle(pi.hProcess);
3722 UnmapViewOfFile(p);
3723 CloseHandle(mapping);
3726 static void test_shared_memory_ro(BOOL is_child, DWORD child_access)
3728 HANDLE mapping;
3729 LONG *p;
3731 SetLastError(0xdeadbef);
3732 mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_virtual.c_ro");
3733 ok(mapping != 0, "CreateFileMapping error %d\n", GetLastError());
3734 if (is_child)
3735 ok(GetLastError() == ERROR_ALREADY_EXISTS, "expected ERROR_ALREADY_EXISTS, got %d\n", GetLastError());
3737 SetLastError(0xdeadbef);
3738 p = MapViewOfFile(mapping, is_child ? child_access : FILE_MAP_READ, 0, 0, 4096);
3739 ok(p != NULL, "MapViewOfFile error %d\n", GetLastError());
3741 if (is_child)
3743 *p = 0xdeadbeef;
3745 else
3747 char **argv;
3748 char cmdline[MAX_PATH];
3749 PROCESS_INFORMATION pi;
3750 STARTUPINFOA si = { sizeof(si) };
3751 DWORD ret;
3753 winetest_get_mainargs(&argv);
3754 sprintf(cmdline, "\"%s\" virtual sharedmemro %x", argv[0], child_access);
3755 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3756 ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
3757 winetest_wait_child_process(pi.hProcess);
3758 CloseHandle(pi.hThread);
3759 CloseHandle(pi.hProcess);
3761 if(child_access & FILE_MAP_WRITE)
3762 ok(*p == 0xdeadbeef, "*p = %x, expected 0xdeadbeef\n", *p);
3763 else
3764 ok(!*p, "*p = %x, expected 0\n", *p);
3767 UnmapViewOfFile(p);
3768 CloseHandle(mapping);
3771 START_TEST(virtual)
3773 int argc;
3774 char **argv;
3775 argc = winetest_get_mainargs( &argv );
3777 if (argc >= 3)
3779 if (!strcmp(argv[2], "sleep"))
3781 Sleep(5000); /* spawned process runs for at most 5 seconds */
3782 return;
3784 if (!strcmp(argv[2], "sharedmem"))
3786 test_shared_memory(TRUE);
3787 return;
3789 if (!strcmp(argv[2], "sharedmemro"))
3791 test_shared_memory_ro(TRUE, strtol(argv[3], NULL, 16));
3792 return;
3794 while (1)
3796 void *mem;
3797 BOOL ret;
3798 mem = VirtualAlloc(NULL, 1<<20, MEM_COMMIT|MEM_RESERVE,
3799 PAGE_EXECUTE_READWRITE);
3800 ok(mem != NULL, "VirtualAlloc failed %u\n", GetLastError());
3801 if (mem == NULL) break;
3802 ret = VirtualFree(mem, 0, MEM_RELEASE);
3803 ok(ret, "VirtualFree failed %u\n", GetLastError());
3804 if (!ret) break;
3806 return;
3809 hkernel32 = GetModuleHandleA("kernel32.dll");
3810 hntdll = GetModuleHandleA("ntdll.dll");
3812 pVirtualAllocEx = (void *) GetProcAddress(hkernel32, "VirtualAllocEx");
3813 pVirtualFreeEx = (void *) GetProcAddress(hkernel32, "VirtualFreeEx");
3814 pGetWriteWatch = (void *) GetProcAddress(hkernel32, "GetWriteWatch");
3815 pResetWriteWatch = (void *) GetProcAddress(hkernel32, "ResetWriteWatch");
3816 pGetProcessDEPPolicy = (void *)GetProcAddress( hkernel32, "GetProcessDEPPolicy" );
3817 pIsWow64Process = (void *)GetProcAddress( hkernel32, "IsWow64Process" );
3818 pNtAreMappedFilesTheSame = (void *)GetProcAddress( hntdll, "NtAreMappedFilesTheSame" );
3819 pNtMapViewOfSection = (void *)GetProcAddress( hntdll, "NtMapViewOfSection" );
3820 pNtUnmapViewOfSection = (void *)GetProcAddress( hntdll, "NtUnmapViewOfSection" );
3821 pRtlAddVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlAddVectoredExceptionHandler" );
3822 pRtlRemoveVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlRemoveVectoredExceptionHandler" );
3823 pNtProtectVirtualMemory = (void *)GetProcAddress( hntdll, "NtProtectVirtualMemory" );
3824 pNtAllocateVirtualMemory = (void *)GetProcAddress( hntdll, "NtAllocateVirtualMemory" );
3825 pNtFreeVirtualMemory = (void *)GetProcAddress( hntdll, "NtFreeVirtualMemory" );
3827 test_shared_memory(FALSE);
3828 test_shared_memory_ro(FALSE, FILE_MAP_READ|FILE_MAP_WRITE);
3829 test_shared_memory_ro(FALSE, FILE_MAP_COPY);
3830 test_shared_memory_ro(FALSE, FILE_MAP_COPY|FILE_MAP_WRITE);
3831 test_mapping();
3832 test_CreateFileMapping_protection();
3833 test_VirtualAlloc_protection();
3834 test_VirtualProtect();
3835 test_VirtualAllocEx();
3836 test_VirtualAlloc();
3837 test_MapViewOfFile();
3838 test_NtMapViewOfSection();
3839 test_NtAreMappedFilesTheSame();
3840 test_CreateFileMapping();
3841 test_IsBadReadPtr();
3842 test_IsBadWritePtr();
3843 test_IsBadCodePtr();
3844 test_write_watch();
3845 #if defined(__i386__) || defined(__x86_64__)
3846 test_stack_commit();
3847 #endif
3848 #ifdef __i386__
3849 test_guard_page();
3850 /* The following tests should be executed as a last step, and in exactly this
3851 * order, since ATL thunk emulation cannot be enabled anymore on Windows. */
3852 test_atl_thunk_emulation( MEM_EXECUTE_OPTION_ENABLE );
3853 test_atl_thunk_emulation( MEM_EXECUTE_OPTION_DISABLE );
3854 test_atl_thunk_emulation( MEM_EXECUTE_OPTION_DISABLE | MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION );
3855 #endif