ntdll: Implementation of inter-process VirtualProtectEx.
[wine] / dlls / kernel32 / tests / 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 "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "wine/test.h"
28
29 #define NUM_THREADS 4
30
31 static HANDLE create_target_process(const char *arg)
32 {
33     char **argv;
34     char cmdline[MAX_PATH];
35     PROCESS_INFORMATION pi;
36     STARTUPINFO si = { 0 };
37     si.cb = sizeof(si);
38
39     winetest_get_mainargs( &argv );
40     sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg);
41     ok(CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL,
42                      &si, &pi) != 0, "error: %u\n", GetLastError());
43     ok(CloseHandle(pi.hThread) != 0, "error %u\n", GetLastError());
44     return pi.hProcess;
45 }
46
47 static void test_VirtualAllocEx(void)
48 {
49     const unsigned int alloc_size = 1<<15;
50     char *src, *dst;
51     unsigned long bytes_written = 0, bytes_read = 0, i;
52     void *addr1, *addr2;
53     BOOL b;
54     DWORD old_prot;
55     MEMORY_BASIC_INFORMATION info;
56     HANDLE hProcess;
57
58     hProcess = create_target_process("sleep");
59     ok(hProcess != NULL, "Can't start process\n");
60
61     SetLastError(0xdeadbeef);
62     addr1 = VirtualAllocEx(hProcess, NULL, alloc_size, MEM_COMMIT,
63                            PAGE_EXECUTE_READWRITE);
64     if (!addr1 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
65     {   /* Win9x */
66         trace("VirtualAllocEx is not implemented, skipping the test\n");
67         TerminateProcess(hProcess, 0);
68         CloseHandle(hProcess);
69         return;
70     }
71
72     src = (char *) HeapAlloc( GetProcessHeap(), 0, alloc_size );
73     dst = (char *) HeapAlloc( GetProcessHeap(), 0, alloc_size );
74     for (i = 0; i < alloc_size; i++)
75         src[i] = 0xcafedead + i;
76
77     ok(addr1 != NULL, "VirtualAllocEx error %u\n", GetLastError());
78     b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
79     ok(b && (bytes_written == alloc_size), "%lu bytes written\n",
80        bytes_written);
81     b = ReadProcessMemory(hProcess, addr1, dst, alloc_size, &bytes_read);
82     ok(b && (bytes_read == alloc_size), "%lu bytes read\n", bytes_read);
83     ok(!memcmp(src, dst, alloc_size), "Data from remote process differs\n");
84     b = VirtualFreeEx(hProcess, addr1, 0, MEM_RELEASE);
85     ok(b != 0, "VirtualFreeEx, error %u\n", GetLastError());
86
87     HeapFree( GetProcessHeap(), 0, src );
88     HeapFree( GetProcessHeap(), 0, dst );
89
90     /*
91      * The following tests parallel those in test_VirtualAlloc()
92      */
93
94     SetLastError(0xdeadbeef);
95     addr1 = VirtualAllocEx(hProcess, 0, 0, MEM_RESERVE, PAGE_NOACCESS);
96     ok(addr1 == NULL, "VirtualAllocEx should fail on zero-sized allocation\n");
97     ok(GetLastError() == ERROR_INVALID_PARAMETER /* NT */ ||
98        GetLastError() == ERROR_NOT_ENOUGH_MEMORY, /* Win9x */
99         "got %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
100
101     addr1 = VirtualAllocEx(hProcess, 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
102     ok(addr1 != NULL, "VirtualAllocEx failed\n");
103
104     /* test a not committed memory */
105     memset(&info, 'q', sizeof(info));
106     ok(VirtualQueryEx(hProcess, addr1, &info, sizeof(info)) == sizeof(info), "VirtualQueryEx failed\n");
107     ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
108     ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
109     ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
110     ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
111     ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
112     /* NT reports Protect == 0 for a not committed memory block */
113     ok(info.Protect == 0 /* NT */ ||
114        info.Protect == PAGE_NOACCESS, /* Win9x */
115         "%x != PAGE_NOACCESS\n", info.Protect);
116     ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
117
118     SetLastError(0xdeadbeef);
119     ok(!VirtualProtectEx(hProcess, addr1, 0xFFFC, PAGE_READONLY, &old_prot),
120        "VirtualProtectEx should fail on a not committed memory\n");
121     ok(GetLastError() == ERROR_INVALID_ADDRESS /* NT */ ||
122        GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x */
123         "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError());
124
125     addr2 = VirtualAllocEx(hProcess, addr1, 0x1000, MEM_COMMIT, PAGE_NOACCESS);
126     ok(addr1 == addr2, "VirtualAllocEx failed\n");
127
128     /* test a committed memory */
129     ok(VirtualQueryEx(hProcess, addr1, &info, sizeof(info)) == sizeof(info),
130         "VirtualQueryEx failed\n");
131     ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
132     ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
133     ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
134     ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize);
135     ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State);
136     /* this time NT reports PAGE_NOACCESS as well */
137     ok(info.Protect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.Protect);
138     ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
139
140     /* this should fail, since not the whole range is committed yet */
141     SetLastError(0xdeadbeef);
142     ok(!VirtualProtectEx(hProcess, addr1, 0xFFFC, PAGE_READONLY, &old_prot),
143         "VirtualProtectEx should fail on a not committed memory\n");
144     ok(GetLastError() == ERROR_INVALID_ADDRESS /* NT */ ||
145        GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x */
146         "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError());
147
148     old_prot = 0;
149     ok(VirtualProtectEx(hProcess, addr1, 0x1000, PAGE_READONLY, &old_prot), "VirtualProtectEx failed\n");
150     ok(old_prot == PAGE_NOACCESS, "wrong old protection: got %04x instead of PAGE_NOACCESS\n", old_prot);
151
152     old_prot = 0;
153     ok(VirtualProtectEx(hProcess, addr1, 0x1000, PAGE_READWRITE, &old_prot), "VirtualProtectEx failed\n");
154     ok(old_prot == PAGE_READONLY, "wrong old protection: got %04x instead of PAGE_READONLY\n", old_prot);
155
156     ok(!VirtualFreeEx(hProcess, addr1, 0x10000, 0),
157        "VirtualFreeEx should fail with type 0\n");
158     ok(GetLastError() == ERROR_INVALID_PARAMETER,
159         "got %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
160
161     ok(VirtualFreeEx(hProcess, addr1, 0x10000, MEM_DECOMMIT), "VirtualFreeEx failed\n");
162
163     /* if the type is MEM_RELEASE, size must be 0 */
164     ok(!VirtualFreeEx(hProcess, addr1, 1, MEM_RELEASE),
165        "VirtualFreeEx should fail\n");
166     ok(GetLastError() == ERROR_INVALID_PARAMETER,
167         "got %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
168
169     ok(VirtualFreeEx(hProcess, addr1, 0, MEM_RELEASE), "VirtualFreeEx failed\n");
170
171     TerminateProcess(hProcess, 0);
172     CloseHandle(hProcess);
173 }
174
175 static void test_VirtualAlloc(void)
176 {
177     void *addr1, *addr2;
178     DWORD old_prot;
179     MEMORY_BASIC_INFORMATION info;
180
181     SetLastError(0xdeadbeef);
182     addr1 = VirtualAlloc(0, 0, MEM_RESERVE, PAGE_NOACCESS);
183     ok(addr1 == NULL, "VirtualAlloc should fail on zero-sized allocation\n");
184     ok(GetLastError() == ERROR_INVALID_PARAMETER /* NT */ ||
185        GetLastError() == ERROR_NOT_ENOUGH_MEMORY, /* Win9x */
186         "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError());
187
188     addr1 = VirtualAlloc(0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS);
189     ok(addr1 != NULL, "VirtualAlloc failed\n");
190
191     /* test a not committed memory */
192     ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info),
193         "VirtualQuery failed\n");
194     ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
195     ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
196     ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
197     ok(info.RegionSize == 0x10000, "%lx != 0x10000\n", info.RegionSize);
198     ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
199     /* NT reports Protect == 0 for a not committed memory block */
200     ok(info.Protect == 0 /* NT */ ||
201        info.Protect == PAGE_NOACCESS, /* Win9x */
202         "%x != PAGE_NOACCESS\n", info.Protect);
203     ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
204
205     SetLastError(0xdeadbeef);
206     ok(!VirtualProtect(addr1, 0xFFFC, PAGE_READONLY, &old_prot),
207        "VirtualProtect should fail on a not committed memory\n");
208     ok(GetLastError() == ERROR_INVALID_ADDRESS /* NT */ ||
209        GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x */
210         "got %d, expected ERROR_INVALID_ADDRESS\n", GetLastError());
211
212     addr2 = VirtualAlloc(addr1, 0x1000, MEM_COMMIT, PAGE_NOACCESS);
213     ok(addr1 == addr2, "VirtualAlloc failed\n");
214
215     /* test a committed memory */
216     ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info),
217         "VirtualQuery failed\n");
218     ok(info.BaseAddress == addr1, "%p != %p\n", info.BaseAddress, addr1);
219     ok(info.AllocationBase == addr1, "%p != %p\n", info.AllocationBase, addr1);
220     ok(info.AllocationProtect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.AllocationProtect);
221     ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize);
222     ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State);
223     /* this time NT reports PAGE_NOACCESS as well */
224     ok(info.Protect == PAGE_NOACCESS, "%x != PAGE_NOACCESS\n", info.Protect);
225     ok(info.Type == MEM_PRIVATE, "%x != MEM_PRIVATE\n", info.Type);
226
227     /* this should fail, since not the whole range is committed yet */
228     SetLastError(0xdeadbeef);
229     ok(!VirtualProtect(addr1, 0xFFFC, PAGE_READONLY, &old_prot),
230         "VirtualProtect should fail on a not committed memory\n");
231     ok(GetLastError() == ERROR_INVALID_ADDRESS /* NT */ ||
232        GetLastError() == ERROR_INVALID_PARAMETER, /* Win9x */
233         "got %d, expected ERROR_INVALID_ADDRESS\n", GetLastError());
234
235     ok(VirtualProtect(addr1, 0x1000, PAGE_READONLY, &old_prot), "VirtualProtect failed\n");
236     ok(old_prot == PAGE_NOACCESS,
237         "wrong old protection: got %04x instead of PAGE_NOACCESS\n", old_prot);
238
239     ok(VirtualProtect(addr1, 0x1000, PAGE_READWRITE, &old_prot), "VirtualProtect failed\n");
240     ok(old_prot == PAGE_READONLY,
241         "wrong old protection: got %04x instead of PAGE_READONLY\n", old_prot);
242
243     ok(!VirtualFree(addr1, 0x10000, 0), "VirtualFree should fail with type 0\n");
244     ok(GetLastError() == ERROR_INVALID_PARAMETER,
245         "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError());
246
247     ok(VirtualFree(addr1, 0x10000, MEM_DECOMMIT), "VirtualFree failed\n");
248
249     /* if the type is MEM_RELEASE, size must be 0 */
250     ok(!VirtualFree(addr1, 1, MEM_RELEASE), "VirtualFree should fail\n");
251     ok(GetLastError() == ERROR_INVALID_PARAMETER,
252         "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError());
253
254     ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n");
255 }
256
257 static void test_MapViewOfFile(void)
258 {
259     static const char testfile[] = "testfile.xxx";
260     HANDLE file, mapping;
261     void *ptr;
262
263     file = CreateFileA( testfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 );
264     ok( file != INVALID_HANDLE_VALUE, "Failed to create test file\n" );
265     SetFilePointer( file, 4096, NULL, FILE_BEGIN );
266     SetEndOfFile( file );
267
268     /* read/write mapping */
269
270     mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
271     ok( mapping != 0, "CreateFileMapping failed\n" );
272
273     ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
274     ok( ptr != NULL, "MapViewOfFile FILE_MAPE_READ failed\n" );
275     UnmapViewOfFile( ptr );
276
277     /* this fails on win9x but succeeds on NT */
278     ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 );
279     if (ptr) UnmapViewOfFile( ptr );
280     else ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %d\n", GetLastError() );
281
282     ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 );
283     ok( ptr != NULL, "MapViewOfFile 0 failed\n" );
284     UnmapViewOfFile( ptr );
285
286     ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 );
287     ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE failed\n" );
288     UnmapViewOfFile( ptr );
289     CloseHandle( mapping );
290
291     /* read-only mapping */
292
293     mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL );
294     ok( mapping != 0, "CreateFileMapping failed\n" );
295
296     ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
297     ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ failed\n" );
298     UnmapViewOfFile( ptr );
299
300     /* this fails on win9x but succeeds on NT */
301     ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 );
302     if (ptr) UnmapViewOfFile( ptr );
303     else ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %d\n", GetLastError() );
304
305     ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 );
306     ok( ptr != NULL, "MapViewOfFile 0 failed\n" );
307     UnmapViewOfFile( ptr );
308
309     ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 );
310     ok( !ptr, "MapViewOfFile FILE_MAP_WRITE succeeded\n" );
311     ok( GetLastError() == ERROR_INVALID_PARAMETER ||
312         GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
313     CloseHandle( mapping );
314
315     /* copy-on-write mapping */
316
317     mapping = CreateFileMappingA( file, NULL, PAGE_WRITECOPY, 0, 4096, NULL );
318     ok( mapping != 0, "CreateFileMapping failed\n" );
319
320     ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
321     ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ failed\n" );
322     UnmapViewOfFile( ptr );
323
324     ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 );
325     ok( ptr != NULL, "MapViewOfFile FILE_MAP_COPY failed\n" );
326     UnmapViewOfFile( ptr );
327
328     ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 );
329     ok( ptr != NULL, "MapViewOfFile 0 failed\n" );
330     UnmapViewOfFile( ptr );
331
332     ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 );
333     ok( !ptr, "MapViewOfFile FILE_MAP_WRITE succeeded\n" );
334     ok( GetLastError() == ERROR_INVALID_PARAMETER ||
335         GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
336     CloseHandle( mapping );
337
338     /* no access mapping */
339
340     mapping = CreateFileMappingA( file, NULL, PAGE_NOACCESS, 0, 4096, NULL );
341     /* fails on NT but succeeds on win9x */
342     if (!mapping) ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %d\n", GetLastError() );
343     else
344     {
345         ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 4096 );
346         ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ failed\n" );
347         UnmapViewOfFile( ptr );
348
349         ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 4096 );
350         ok( !ptr, "MapViewOfFile FILE_MAP_COPY succeeded\n" );
351         ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %d\n", GetLastError() );
352
353         ptr = MapViewOfFile( mapping, 0, 0, 0, 4096 );
354         ok( ptr != NULL, "MapViewOfFile 0 failed\n" );
355         UnmapViewOfFile( ptr );
356
357         ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 );
358         ok( !ptr, "MapViewOfFile FILE_MAP_WRITE succeeded\n" );
359         ok( GetLastError() == ERROR_INVALID_PARAMETER, "Wrong error %d\n", GetLastError() );
360
361         CloseHandle( mapping );
362     }
363
364     CloseHandle( file );
365
366     /* now try read-only file */
367
368     file = CreateFileA( testfile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0 );
369     ok( file != INVALID_HANDLE_VALUE, "Failed to create test file\n" );
370
371     mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
372     ok( !mapping, "CreateFileMapping PAGE_READWRITE succeeded\n" );
373     ok( GetLastError() == ERROR_INVALID_PARAMETER ||
374         GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
375
376     mapping = CreateFileMappingA( file, NULL, PAGE_WRITECOPY, 0, 4096, NULL );
377     ok( mapping != 0, "CreateFileMapping PAGE_WRITECOPY failed\n" );
378     CloseHandle( mapping );
379
380     mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL );
381     ok( mapping != 0, "CreateFileMapping PAGE_READONLY failed\n" );
382     CloseHandle( mapping );
383     CloseHandle( file );
384
385     /* now try no access file */
386
387     file = CreateFileA( testfile, 0, 0, NULL, OPEN_EXISTING, 0, 0 );
388     ok( file != INVALID_HANDLE_VALUE, "Failed to create test file\n" );
389
390     mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL );
391     ok( !mapping, "CreateFileMapping PAGE_READWRITE succeeded\n" );
392     ok( GetLastError() == ERROR_INVALID_PARAMETER ||
393         GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
394
395     mapping = CreateFileMappingA( file, NULL, PAGE_WRITECOPY, 0, 4096, NULL );
396     ok( !mapping, "CreateFileMapping PAGE_WRITECOPY succeeded\n" );
397     ok( GetLastError() == ERROR_INVALID_PARAMETER ||
398         GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
399
400     mapping = CreateFileMappingA( file, NULL, PAGE_READONLY, 0, 4096, NULL );
401     ok( !mapping, "CreateFileMapping PAGE_READONLY succeeded\n" );
402     ok( GetLastError() == ERROR_INVALID_PARAMETER ||
403         GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
404
405     CloseHandle( file );
406
407     CloseHandle( file );
408     DeleteFileA( testfile );
409 }
410
411 START_TEST(virtual)
412 {
413     int argc;
414     char **argv;
415     argc = winetest_get_mainargs( &argv );
416
417     if (argc >= 3)
418     {
419         if (!strcmp(argv[2], "sleep"))
420         {
421             Sleep(5000); /* spawned process runs for at most 5 seconds */
422             return;
423         }
424         while (1)
425         {
426             void *mem;
427             BOOL ret;
428             mem = VirtualAlloc(NULL, 1<<20, MEM_COMMIT|MEM_RESERVE,
429                                PAGE_EXECUTE_READWRITE);
430             ok(mem != NULL, "VirtualAlloc failed %u\n", GetLastError());
431             if (mem == NULL) break;
432             ret = VirtualFree(mem, 0, MEM_RELEASE);
433             ok(ret, "VirtualFree failed %u\n", GetLastError());
434             if (!ret) break;
435         }
436         return;
437     }
438
439     test_VirtualAllocEx();
440     test_VirtualAlloc();
441     test_MapViewOfFile();
442 }