1 /*
2  * PROJECT:     ReactOS API Tests
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Test for NtAllocateVirtualMemory
5  * COPYRIGHT:   Copyright 2011 Thomas Faber <thomas.faber@reactos.org>
6  *              Copyright 2013 Timo Kreuzer <timo.kreuzer@reactos.org>
7  *              Copyright 2015 J�r�me Gardou <jerome.gardou@reactos.org>
8  *              Copyright 2018 Serge Gautherie <reactos-git_serge_171003@gautherie.fr>
9  */
10 
11 #include "precomp.h"
12 
13 static PVOID Allocations[4096] = { NULL };
14 static ULONG CurrentAllocation = 0;
15 
16 static
17 VOID
18 ValidateAllocations(VOID)
19 {
20     ULONG i;
21 
22     ASSERT(CurrentAllocation < sizeof(Allocations) / sizeof(Allocations[0]));
23     for (i = 0; i < CurrentAllocation; ++i)
24     {
25         PUCHAR UserBuffer = Allocations[i];
26         SIZE_T AllocationSize;
27         SIZE_T DataSize;
28 
29         if (UserBuffer == NULL)
30             continue;
31 
32         AllocationSize = ((PSIZE_T)UserBuffer)[-2];
33         DataSize = ((PSIZE_T)UserBuffer)[-1];
34         ASSERT(AllocationSize != 0);
35         ASSERT(AllocationSize % PAGE_SIZE == 0);
36         ASSERT(DataSize != 0);
37         ASSERT(((SIZE_T)UserBuffer + DataSize) % PAGE_SIZE == 0);
38     }
39 }
40 
41 static
42 PVOID
43 Allocate(
44     SIZE_T DataSize)
45 {
46     NTSTATUS Status;
47     PVOID AllocationStart = NULL;
48     SIZE_T AllocationSize = PAGE_ROUND_UP(DataSize + PAGE_SIZE + 2 * sizeof(SIZE_T));
49     PVOID FirstPageStart;
50     SIZE_T NumberOfPages = AllocationSize / PAGE_SIZE;
51     SIZE_T Size;
52     PUCHAR UserBuffer;
53 
54     Status = NtAllocateVirtualMemory(NtCurrentProcess(), &AllocationStart, 0, &AllocationSize, MEM_RESERVE, PAGE_NOACCESS);
55 
56     if (!NT_SUCCESS(Status))
57         return NULL;
58 
59     FirstPageStart = (PUCHAR)AllocationStart + AllocationSize - PAGE_SIZE * NumberOfPages;
60     Size = (NumberOfPages - 1) * PAGE_SIZE;
61     Status = NtAllocateVirtualMemory(NtCurrentProcess(), &FirstPageStart, 0, &Size, MEM_COMMIT, PAGE_READWRITE);
62     if (!NT_SUCCESS(Status))
63     {
64         AllocationSize = 0;
65         Status = NtFreeVirtualMemory(NtCurrentProcess(), &AllocationStart, &AllocationSize, MEM_RELEASE);
66         ASSERT(Status == STATUS_SUCCESS);
67         return NULL;
68     }
69     ASSERT(Size % sizeof(ULONG) == 0);
70     ASSERT(RtlCompareMemoryUlong(FirstPageStart, Size, 0) == Size);
71 
72     UserBuffer = AllocationStart;
73     UserBuffer += AllocationSize - PAGE_SIZE - DataSize;
74     RtlFillMemory(FirstPageStart, UserBuffer - (PUCHAR)FirstPageStart, 0xae);
75     RtlZeroMemory(UserBuffer, DataSize);
76     ((PSIZE_T)UserBuffer)[-2] = AllocationSize;
77     ((PSIZE_T)UserBuffer)[-1] = DataSize;
78 
79     Allocations[CurrentAllocation++] = UserBuffer;
80     ValidateAllocations();
81     return UserBuffer;
82 }
83 
84 static
85 VOID
86 Free(
87     PVOID UserBuffer)
88 {
89     NTSTATUS Status;
90     PVOID AllocationStart;
91     SIZE_T Zero = 0;
92     SIZE_T AllocationSize;
93     SIZE_T DataSize;
94     ULONG i;
95 
96     AllocationSize = ((PSIZE_T)UserBuffer)[-2];
97     DataSize = ((PSIZE_T)UserBuffer)[-1];
98     ASSERT(DataSize != 0);
99 
100     AllocationStart = (PUCHAR)UserBuffer + DataSize + PAGE_SIZE - AllocationSize;
101     ASSERT((SIZE_T)AllocationStart % PAGE_SIZE == 0);
102 
103     RtlFillMemory(UserBuffer, DataSize, 0xbe);
104     ((PSIZE_T)UserBuffer)[-1] = 0;
105     ((PSIZE_T)UserBuffer)[-2] = 0xFAFBFCFD;
106 
107     for (i = 0; i < CurrentAllocation; ++i)
108         if (Allocations[i] == UserBuffer)
109         {
110             Allocations[i] = NULL;
111             break;
112         }
113     ValidateAllocations();
114 
115     Status = NtFreeVirtualMemory(NtCurrentProcess(), &AllocationStart, &Zero, MEM_RELEASE);
116     ASSERT(Status == STATUS_SUCCESS);
117 }
118 
119 static
120 PVOID
121 ReAllocate(
122     PVOID OldUserBuffer,
123     SIZE_T NewDataSize)
124 {
125     PVOID NewUserBuffer;
126     SIZE_T OldDataSize;
127 
128     OldDataSize = ((PSIZE_T)OldUserBuffer)[-1];
129     ASSERT(OldDataSize != 0);
130 
131     NewUserBuffer = Allocate(NewDataSize);
132     ASSERT(((PSIZE_T)OldUserBuffer)[-1] == OldDataSize);
133     RtlCopyMemory(NewUserBuffer, OldUserBuffer, min(OldDataSize, NewDataSize));
134     ASSERT(((PSIZE_T)OldUserBuffer)[-1] == OldDataSize);
135     Free(OldUserBuffer);
136     return NewUserBuffer;
137 }
138 
139 static
140 VOID
141 AccessMemory1(
142     PVOID UserBuffer,
143     SIZE_T DataSize)
144 {
145     PBYTE Buffer = UserBuffer;
146     SIZE_T i;
147 
148     for (i = 0; i < DataSize; ++i)
149         Buffer[i] = LOBYTE(i);
150 }
151 
152 static
153 BOOLEAN
154 CheckMemory1(
155     PVOID UserBuffer,
156     SIZE_T DataSize)
157 {
158     PBYTE Buffer = UserBuffer;
159     SIZE_T i;
160 
161     for (i = 0; i < DataSize; ++i)
162         if (Buffer[i] != LOBYTE(i))
163         {
164             trace("Mismatch in region %p at index %lu. Value=%02x\n", UserBuffer, (ULONG)i, Buffer[i]);
165             ASSERT(FALSE);
166             return FALSE;
167         }
168     return TRUE;
169 }
170 
171 static
172 VOID
173 AccessMemory2(
174     PVOID UserBuffer,
175     SIZE_T DataSize)
176 {
177     PBYTE Buffer = UserBuffer;
178     SIZE_T i;
179 
180     for (i = 0; i < DataSize; ++i)
181         Buffer[i] = UCHAR_MAX - LOBYTE(i);
182 }
183 
184 static
185 BOOLEAN
186 CheckMemory2(
187     PVOID UserBuffer,
188     SIZE_T DataSize)
189 {
190     PBYTE Buffer = UserBuffer;
191     SIZE_T i;
192 
193     for (i = 0; i < DataSize; ++i)
194         if (Buffer[i] != UCHAR_MAX - LOBYTE(i))
195         {
196             trace("Mismatch in region %p at index %lu. Value=%02x\n", UserBuffer, (ULONG)i, Buffer[i]);
197             ASSERT(FALSE);
198             return FALSE;
199         }
200     return TRUE;
201 }
202 
203 VOID
204 CheckSize(ULONG_PTR Base, SIZE_T InSize, SIZE_T ExpectedSize)
205 {
206     NTSTATUS Status;
207     PVOID BaseAddress;
208     SIZE_T Size;
209 
210     /* Reserve memory */
211     BaseAddress = (PVOID)Base;
212     Size = InSize;
213     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
214                                      &BaseAddress,
215                                      0,
216                                      &Size,
217                                      MEM_RESERVE,
218                                      PAGE_NOACCESS);
219     ok(NT_SUCCESS(Status), "NtAllocateVirtualMemory failed!\n");
220     ok(BaseAddress == (PVOID)(Base & ~((ULONG_PTR)0xFFFF)), "Got back wrong base address: %p\n", BaseAddress);
221     ok(Size == ExpectedSize, "Alloc of 0x%Ix: got back wrong size: 0x%Ix, expected 0x%Ix\n", InSize, Size, ExpectedSize);
222     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
223     ok(NT_SUCCESS(Status), "NtFreeVirtualMemory failed!\n");
224 }
225 
226 VOID
227 CheckAlignment()
228 {
229     NTSTATUS Status;
230     PVOID BaseAddress;
231     SIZE_T Size;
232 
233     CheckSize(0x50000000, 0x0001, 0x1000);
234     CheckSize(0x50008000, 0x0001, 0x9000);
235     CheckSize(0x50000010, 0x1000, 0x2000);
236     CheckSize(0x50010000, 0x2000, 0x2000);
237     CheckSize(0x5000FFFF, 0x3000, 0x13000);
238     CheckSize(0x50001010, 0x7000, 0x9000);
239     CheckSize(0x50001010, 0xC000, 0xe000);
240 
241     /* Reserve memory not aligned to allocation granularity */
242     BaseAddress = UlongToPtr(0x50001010);
243     Size = 0x1000;
244     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
245                                      &BaseAddress,
246                                      0,
247                                      &Size,
248                                      MEM_RESERVE,
249                                      PAGE_NOACCESS);
250     ok_ntstatus(Status, STATUS_SUCCESS);
251     ok(BaseAddress == UlongToPtr(0x50000000), "Got back wrong base address: %p", BaseAddress);
252     ok(Size == 0x3000, "Got back wrong size: 0x%Ix", Size);
253 
254     /* Try to reserve again in the same 64k region */
255     BaseAddress = UlongToPtr(0x50008000);
256     Size = 0x1000;
257     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
258                                      &BaseAddress,
259                                      0,
260                                      &Size,
261                                      MEM_RESERVE,
262                                      PAGE_NOACCESS);
263     ok_ntstatus(Status, STATUS_CONFLICTING_ADDRESSES);
264 
265     /* Commit memory */
266     BaseAddress = UlongToPtr(0x50002000);
267     Size = 0x1000;
268     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
269                                      &BaseAddress,
270                                      0,
271                                      &Size,
272                                      MEM_COMMIT,
273                                      PAGE_NOACCESS);
274     ok_ntstatus(Status, STATUS_SUCCESS);
275     ok(BaseAddress == UlongToPtr(0x50002000), "Got back wrong base address: %p", BaseAddress);
276     ok(Size == 0x1000, "Got back wrong size: 0x%Ix", Size);
277 
278     /* Commit the same address again with a different protection */
279     BaseAddress = UlongToPtr(0x50002000);
280     Size = 0x1000;
281     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
282                                      &BaseAddress,
283                                      0,
284                                      &Size,
285                                      MEM_COMMIT,
286                                      PAGE_READWRITE);
287     ok_ntstatus(Status, STATUS_SUCCESS);
288     ok(BaseAddress == UlongToPtr(0x50002000), "Got back wrong base address: %p", BaseAddress);
289     ok(Size == 0x1000, "Got back wrong size: 0x%Ix", Size);
290 
291     /* Commit memory at a too high address */
292     BaseAddress = UlongToPtr(0x50003000);
293     Size = 0x1000;
294     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
295                                      &BaseAddress,
296                                      0,
297                                      &Size,
298                                      MEM_COMMIT,
299                                      PAGE_NOACCESS);
300     ok_ntstatus(Status, STATUS_CONFLICTING_ADDRESSES);
301 
302     /* Decommit the memory, even those pages that were not committed */
303     BaseAddress = UlongToPtr(0x50000000);
304     Size = 0x3000;
305     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_DECOMMIT);
306     ok_ntstatus(Status, STATUS_SUCCESS);
307 
308     /* Try to release memory in a different 64k region */
309     BaseAddress = UlongToPtr(0x50010000);
310     Size = 0x1000;
311     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
312     ok_ntstatus(Status, STATUS_MEMORY_NOT_ALLOCATED);
313 
314     /* Release the memory in the same 64k region at a different address */
315     BaseAddress = UlongToPtr(0x50008000);
316     Size = 0x1000;
317     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
318     ok_ntstatus(Status, STATUS_MEMORY_NOT_ALLOCATED);
319 
320     /* Release the memory at the correct address but with wrong size */
321     BaseAddress = UlongToPtr(0x50000000);
322     Size = 0x4000;
323     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
324     ok_ntstatus(Status, STATUS_UNABLE_TO_FREE_VM);
325 
326     /* Release the memory */
327     BaseAddress = UlongToPtr(0x50000000);
328     Size = 0x3000;
329     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
330     ok_ntstatus(Status, STATUS_SUCCESS);
331 
332     /* Reserve and commit at once */
333     BaseAddress = UlongToPtr(0x50004080);
334     Size = 0x1000;
335     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
336                                      &BaseAddress,
337                                      0,
338                                      &Size,
339                                      MEM_RESERVE | MEM_COMMIT,
340                                      PAGE_READWRITE);
341     ok_ntstatus(Status, STATUS_SUCCESS);
342     ok(BaseAddress == UlongToPtr(0x50000000), "Got back wrong base address: %p", BaseAddress);
343     ok(Size == 0x6000, "Got back wrong size: 0x%Ix", Size);
344 
345     _SEH2_TRY
346     {
347         *(int*)BaseAddress = 1;
348         *(int*)UlongToPtr(0x50004080) = 1;
349     }
350     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
351     {
352         ok(0, "Got exception\n");
353     }
354     _SEH2_END;
355 
356     /* Release the memory */
357     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
358     ok_ntstatus(Status, STATUS_SUCCESS);
359 
360 }
361 
362 static
363 VOID
364 CheckAdjacentVADs()
365 {
366     NTSTATUS Status;
367     PVOID BaseAddress;
368     SIZE_T Size;
369     MEMORY_BASIC_INFORMATION MemoryBasicInfo;
370 
371     /* Reserve a full 64k region */
372     BaseAddress = UlongToPtr(0x50000000);
373     Size = 0x10000;
374     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
375                                      &BaseAddress,
376                                      0,
377                                      &Size,
378                                      MEM_RESERVE,
379                                      PAGE_NOACCESS);
380     ok_ntstatus(Status, STATUS_SUCCESS);
381     if (!NT_SUCCESS(Status))
382         return;
383 
384     /* Reserve another 64k region, but with 64k between */
385     BaseAddress = UlongToPtr(0x50020000);
386     Size = 0x10000;
387     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
388                                      &BaseAddress,
389                                      0,
390                                      &Size,
391                                      MEM_RESERVE,
392                                      PAGE_NOACCESS);
393     ok_ntstatus(Status, STATUS_SUCCESS);
394     if (!NT_SUCCESS(Status))
395         return;
396 
397     /* Try to free the whole at once */
398     BaseAddress = UlongToPtr(0x50000000);
399     Size = 0x30000;
400     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
401     ok_ntstatus(Status, STATUS_UNABLE_TO_FREE_VM);
402 
403     /* Reserve the part in the middle */
404     BaseAddress = UlongToPtr(0x50010000);
405     Size = 0x10000;
406     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
407                                      &BaseAddress,
408                                      0,
409                                      &Size,
410                                      MEM_RESERVE,
411                                      PAGE_NOACCESS);
412     ok_ntstatus(Status, STATUS_SUCCESS);
413 
414     /* Try to commit memory covering 2 allocations */
415     BaseAddress = UlongToPtr(0x50004000);
416     Size = 0x10000;
417     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
418                                      &BaseAddress,
419                                      0,
420                                      &Size,
421                                      MEM_COMMIT,
422                                      PAGE_NOACCESS);
423     ok_ntstatus(Status, STATUS_CONFLICTING_ADDRESSES);
424 
425     /* Commit a page */
426     BaseAddress = UlongToPtr(0x50000000);
427     Size = 0x1000;
428     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
429                                      &BaseAddress,
430                                      0,
431                                      &Size,
432                                      MEM_COMMIT,
433                                      PAGE_READWRITE);
434     ok_ntstatus(Status, STATUS_SUCCESS);
435 
436     /* Commit another page */
437     BaseAddress = UlongToPtr(0x50002000);
438     Size = 0x1000;
439     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
440                                      &BaseAddress,
441                                      0,
442                                      &Size,
443                                      MEM_COMMIT,
444                                      PAGE_NOACCESS);
445     ok_ntstatus(Status, STATUS_SUCCESS);
446 
447     _SEH2_TRY
448     {
449         *(int*)UlongToPtr(0x50000000) = 1;
450     }
451     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
452     {
453         ok(0, "Got exception\n");
454     }
455     _SEH2_END;
456 
457     _SEH2_TRY
458     {
459         (void)*(volatile int*)UlongToPtr(0x50002000);
460     }
461     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
462     {
463         Status = _SEH2_GetExceptionCode();
464     }
465     _SEH2_END;
466     ok_ntstatus(Status, STATUS_ACCESS_VIOLATION);
467 
468     /* Allocate 3 pages, on top of the previous 2 */
469     BaseAddress = UlongToPtr(0x50000000);
470     Size = 0x3000;
471     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
472                                      &BaseAddress,
473                                      0,
474                                      &Size,
475                                      MEM_COMMIT,
476                                      PAGE_READONLY);
477     ok_ntstatus(Status, STATUS_SUCCESS);
478 
479     _SEH2_TRY
480     {
481         *(int*)UlongToPtr(0x50000000) = 1;
482     }
483     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
484     {
485         Status = _SEH2_GetExceptionCode();
486     }
487     _SEH2_END;
488     ok_ntstatus(Status, STATUS_ACCESS_VIOLATION);
489 
490     /* Commit a page at the end of the first region */
491     BaseAddress = UlongToPtr(0x5000F000);
492     Size = 0x1000;
493     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
494                                      &BaseAddress,
495                                      0,
496                                      &Size,
497                                      MEM_COMMIT,
498                                      PAGE_READWRITE);
499     ok_ntstatus(Status, STATUS_SUCCESS);
500     ok_ptr(BaseAddress, UlongToPtr(0x5000F000));
501 
502     /* See where is the base of this newly committed area
503      * (choose a base address in the middle of it) */
504     Status = NtQueryVirtualMemory(NtCurrentProcess(),
505                                   UlongToPtr(0x5000F700),
506                                   MemoryBasicInformation,
507                                   &MemoryBasicInfo,
508                                   sizeof(MemoryBasicInfo),
509                                   NULL);
510     ok_ntstatus(Status, STATUS_SUCCESS);
511     /* The base address is the beginning of the committed area */
512     ok_ptr(MemoryBasicInfo.BaseAddress, UlongToPtr(0x5000F000));
513     /* The allocation base address is the beginning of the whole region */
514     ok_ptr(MemoryBasicInfo.AllocationBase, UlongToPtr(0x50000000));
515     /* This is the protection of the memory when it was reserved. */
516     ok_long(MemoryBasicInfo.AllocationProtect, PAGE_NOACCESS);
517     /* This is the size of the committed region. (ie, smallest chunk size) */
518     ok_long(MemoryBasicInfo.RegionSize, 0x1000);
519     /* This is the state of the queried address */
520     ok_long(MemoryBasicInfo.State, MEM_COMMIT);
521     /* This is the protection of the queried address */
522     ok_long(MemoryBasicInfo.Protect, PAGE_READWRITE);
523     /* NtAllocateVirtualMemory makes it MEM_PRIVATE */
524     ok_long(MemoryBasicInfo.Type, MEM_PRIVATE);
525 
526     /* Try to free the whole region at once */
527     BaseAddress = UlongToPtr(0x50000000);
528     Size = 0x30000;
529     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
530     ok_ntstatus(Status, STATUS_UNABLE_TO_FREE_VM);
531 
532     BaseAddress = UlongToPtr(0x50000000);
533     Size = 0x10000;
534     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
535     ok_ntstatus(Status, STATUS_SUCCESS);
536 
537     BaseAddress = UlongToPtr(0x50010000);
538     Size = 0x10000;
539     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
540     ok_ntstatus(Status, STATUS_SUCCESS);
541 
542     BaseAddress = UlongToPtr(0x50020000);
543     Size = 0x10000;
544     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
545     ok_ntstatus(Status, STATUS_SUCCESS);
546 
547     /* Reserve 3 full 64k region */
548     BaseAddress = UlongToPtr(0x50000000);
549     Size = 0x30000;
550     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
551                                      &BaseAddress,
552                                      0,
553                                      &Size,
554                                      MEM_RESERVE,
555                                      PAGE_NOACCESS);
556     ok_ntstatus(Status, STATUS_SUCCESS);
557     if (!NT_SUCCESS(Status))
558         return;
559 
560     /* Release the 64k region in the middle */
561     BaseAddress = UlongToPtr(0x50010000);
562     Size = 0x10000;
563     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
564     ok_ntstatus(Status, STATUS_SUCCESS);
565 
566 }
567 
568 static
569 VOID
570 CheckSomeDefaultAddresses(VOID)
571 {
572     NTSTATUS Status;
573     PVOID BaseAddress;
574     SIZE_T Size;
575 
576     // NULL.
577 
578     /* Reserve memory dynamically, not at 0x00000000 */
579     BaseAddress = NULL;
580     Size = 0x1000;
581     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
582                                      &BaseAddress,
583                                      0,
584                                      &Size,
585                                      MEM_RESERVE,
586                                      PAGE_READWRITE);
587     ok_ntstatus(Status, STATUS_SUCCESS);
588     ok(BaseAddress != 0x00000000, "Unexpected BaseAddress = 0x00000000\n");
589     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
590     ok_ntstatus(Status, STATUS_SUCCESS);
591 
592     // 0x00000000, 64k: Free.
593 
594     /* Reserve and commit memory at 0x00000000, after round down */
595     BaseAddress = UlongToPtr(0x00000000 + 0x0FFF);
596     Size = 0x1000;
597     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
598                                      &BaseAddress,
599                                      0,
600                                      &Size,
601                                      MEM_RESERVE | MEM_COMMIT,
602                                      PAGE_READWRITE);
603     ok_ntstatus(Status, STATUS_SUCCESS);
604     ok_ptr(BaseAddress, 0x00000000);
605 
606     // Double-check that it is not forbidden "in order to catch null pointer accesses".
607     StartSeh()
608         *(int*)UlongToPtr(0x00000000) = 1;
609     EndSeh(STATUS_SUCCESS)
610 
611     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
612     ok_ntstatus(Status, STATUS_SUCCESS);
613 
614     /* Reserve memory above 0x00000000 */
615     BaseAddress = UlongToPtr(0x00000000 + 0x1000);
616     Size = 0x1000;
617     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
618                                      &BaseAddress,
619                                      0,
620                                      &Size,
621                                      MEM_RESERVE,
622                                      PAGE_READWRITE);
623     ok_ntstatus(Status, STATUS_SUCCESS);
624     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
625     ok_ntstatus(Status, STATUS_SUCCESS);
626 
627     /* The following checks assume very default addresses,
628      * no address space layout randomization (ASLR). */
629 #ifdef _WIN64
630     ok(FALSE, "ToDo, 64-bit: Check/Adapt 32-bit results\n");
631 #endif
632 
633     // 0x00010000,  4k: Private Data.
634     // 0x00011000, 60k: Unusable.
635 
636     /* Reserve memory below 0x00010000 */
637     BaseAddress = UlongToPtr(0x00010000 - 0x1000);
638     Size = 0x1000;
639     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
640                                      &BaseAddress,
641                                      0,
642                                      &Size,
643                                      MEM_RESERVE,
644                                      PAGE_READWRITE);
645     ok_ntstatus(Status, STATUS_SUCCESS);
646     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
647     ok_ntstatus(Status, STATUS_SUCCESS);
648 
649     /* Reserve memory at 0x00010000:
650      * Windows NT legacy default executable image base */
651     BaseAddress = UlongToPtr(0x00010000);
652     Size = 0x1000;
653     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
654                                      &BaseAddress,
655                                      0,
656                                      &Size,
657                                      MEM_RESERVE,
658                                      PAGE_READWRITE);
659     ok_ntstatus(Status, STATUS_CONFLICTING_ADDRESSES);
660     if (NT_SUCCESS(Status))
661     { // Unexpected, cleanup.
662         Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
663         ok_ntstatus(Status, STATUS_SUCCESS);
664     }
665 
666     // 0x00400000: Image base.
667 
668     /* Reserve memory below 0x00400000 */
669     BaseAddress = UlongToPtr(0x00400000 - 0x1000);
670     Size = 0x1000;
671     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
672                                      &BaseAddress,
673                                      0,
674                                      &Size,
675                                      MEM_RESERVE,
676                                      PAGE_READWRITE);
677     if (NT_SUCCESS(Status))
678     {
679         trace("Below 0x00400000 is available, as on ReactOS and Windows S03\n");
680         // 0x003F0000, 64k: Free.
681         ok_ntstatus(Status, STATUS_SUCCESS);
682         Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
683         ok_ntstatus(Status, STATUS_SUCCESS);
684     }
685     else
686     {
687         trace("Below 0x00400000 is not available, as on Windows XP\n");
688         // 0x003F0000,  4k: Shareable.
689         // 0x003F1000, 60k: Unusable.
690         ok_ntstatus(Status, STATUS_CONFLICTING_ADDRESSES);
691     }
692 
693     /* Reserve memory at 0x00400000:
694      * Windows NT legacy default DLL image base,
695      * (ReactOS and) Windows 95 new default executable image base */
696     BaseAddress = UlongToPtr(0x00400000);
697     Size = 0x1000;
698     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
699                                      &BaseAddress,
700                                      0,
701                                      &Size,
702                                      MEM_RESERVE,
703                                      PAGE_READWRITE);
704     ok_ntstatus(Status, STATUS_CONFLICTING_ADDRESSES);
705     if (NT_SUCCESS(Status))
706     { // Unexpected, cleanup.
707         Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
708         ok_ntstatus(Status, STATUS_SUCCESS);
709     }
710 
711     // 0x10000000: Free.
712 
713     /* Reserve memory below 0x10000000 */
714     BaseAddress = UlongToPtr(0x10000000 - 0x1000);
715     Size = 0x1000;
716     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
717                                      &BaseAddress,
718                                      0,
719                                      &Size,
720                                      MEM_RESERVE,
721                                      PAGE_READWRITE);
722     ok_ntstatus(Status, STATUS_SUCCESS);
723     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
724     ok_ntstatus(Status, STATUS_SUCCESS);
725 
726     /* Reserve memory at 0x10000000:
727      * Windows new default non-OS DLL image base */
728     BaseAddress = UlongToPtr(0x10000000);
729     Size = 0x1000;
730     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
731                                      &BaseAddress,
732                                      0,
733                                      &Size,
734                                      MEM_RESERVE,
735                                      PAGE_READWRITE);
736     ok_ntstatus(Status, STATUS_SUCCESS);
737     Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
738     ok_ntstatus(Status, STATUS_SUCCESS);
739 
740 #ifdef _WIN64
741     skip("ToDo, 64-bit: Add 0x140000000/Exe and 0x180000000/DLL checks\n");
742 #endif
743 }
744 
745 #define RUNS 32
746 
747 START_TEST(NtAllocateVirtualMemory)
748 {
749     PVOID Mem1, Mem2;
750     SIZE_T Size1, Size2;
751     ULONG i;
752 
753     CheckAlignment();
754     CheckAdjacentVADs();
755     CheckSomeDefaultAddresses();
756 
757     Size1 = 32;
758     Mem1 = Allocate(Size1);
759     AccessMemory1(Mem1, Size1);
760     Size2 = 128;
761     Mem2 = Allocate(Size2);
762     AccessMemory2(Mem2, Size2);
763     for (i = 0; i < RUNS; ++i)
764     {
765         PVOID New;
766         ok(CheckMemory1(Mem1, Size1) == TRUE, "CheckMemory1 failure\n");
767         New = ReAllocate(Mem1, Size1 * 3 / 2);
768         if (New == NULL)
769         {
770             skip("Realloc failure\n");
771             break;
772         }
773         Mem1 = New;
774         ok(CheckMemory1(Mem1, Size1) == TRUE, "CheckMemory1 failure\n");
775         Size1 = Size1 * 3 / 2;
776         AccessMemory1(Mem1, Size1);
777 
778         ok(CheckMemory2(Mem2, Size2) == TRUE, "CheckMemory2 failure\n");
779         New = ReAllocate(Mem2, Size2 + 128);
780         if (New == NULL)
781         {
782             skip("Realloc failure\n");
783             break;
784         }
785         Mem2 = New;
786         ok(CheckMemory2(Mem2, Size2) == TRUE, "CheckMemory2 failure\n");
787         Size2 += 128;
788         AccessMemory2(Mem2, Size2);
789     }
790     ok(CheckMemory2(Mem2, Size2) == TRUE, "CheckMemory2 failure\n");
791     Free(Mem2);
792     ok(CheckMemory1(Mem1, Size1) == TRUE, "CheckMemory1 failure\n");
793     Free(Mem1);
794 }
795