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