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