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