2 * PROJECT: ReactOS API Tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Stress Test for virtual memory allocation
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
10 static PVOID Allocations
[4096] = { NULL
};
11 static ULONG CurrentAllocation
= 0;
15 ValidateAllocations(VOID
)
19 ASSERT(CurrentAllocation
< sizeof(Allocations
) / sizeof(Allocations
[0]));
20 for (i
= 0; i
< CurrentAllocation
; ++i
)
22 PUCHAR UserBuffer
= Allocations
[i
];
23 SIZE_T AllocationSize
;
26 if (UserBuffer
== NULL
)
29 AllocationSize
= ((PSIZE_T
)UserBuffer
)[-2];
30 DataSize
= ((PSIZE_T
)UserBuffer
)[-1];
31 ASSERT(AllocationSize
!= 0);
32 ASSERT(AllocationSize
% PAGE_SIZE
== 0);
33 ASSERT(DataSize
!= 0);
34 ASSERT(((SIZE_T
)UserBuffer
+ DataSize
) % PAGE_SIZE
== 0);
44 PVOID AllocationStart
= NULL
;
45 SIZE_T AllocationSize
= PAGE_ROUND_UP(DataSize
+ PAGE_SIZE
+ 2 * sizeof(SIZE_T
));
47 SIZE_T NumberOfPages
= AllocationSize
/ PAGE_SIZE
;
51 Status
= NtAllocateVirtualMemory(NtCurrentProcess(), &AllocationStart
, 0, &AllocationSize
, MEM_RESERVE
, PAGE_NOACCESS
);
53 if (!NT_SUCCESS(Status
))
56 FirstPageStart
= (PUCHAR
)AllocationStart
+ AllocationSize
- PAGE_SIZE
* NumberOfPages
;
57 Size
= (NumberOfPages
- 1) * PAGE_SIZE
;
58 Status
= NtAllocateVirtualMemory(NtCurrentProcess(), &FirstPageStart
, 0, &Size
, MEM_COMMIT
, PAGE_READWRITE
);
59 if (!NT_SUCCESS(Status
))
62 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &AllocationStart
, &AllocationSize
, MEM_RELEASE
);
63 ASSERT(Status
== STATUS_SUCCESS
);
66 ASSERT(Size
% sizeof(ULONG
) == 0);
67 ASSERT(RtlCompareMemoryUlong(FirstPageStart
, Size
, 0) == Size
);
69 UserBuffer
= AllocationStart
;
70 UserBuffer
+= AllocationSize
- PAGE_SIZE
- DataSize
;
71 RtlFillMemory(FirstPageStart
, UserBuffer
- (PUCHAR
)FirstPageStart
, 0xae);
72 RtlZeroMemory(UserBuffer
, DataSize
);
73 ((PSIZE_T
)UserBuffer
)[-2] = AllocationSize
;
74 ((PSIZE_T
)UserBuffer
)[-1] = DataSize
;
76 Allocations
[CurrentAllocation
++] = UserBuffer
;
77 ValidateAllocations();
87 PVOID AllocationStart
;
89 SIZE_T AllocationSize
;
93 AllocationSize
= ((PSIZE_T
)UserBuffer
)[-2];
94 DataSize
= ((PSIZE_T
)UserBuffer
)[-1];
95 ASSERT(DataSize
!= 0);
97 AllocationStart
= (PUCHAR
)UserBuffer
+ DataSize
+ PAGE_SIZE
- AllocationSize
;
98 ASSERT((SIZE_T
)AllocationStart
% PAGE_SIZE
== 0);
100 RtlFillMemory(UserBuffer
, DataSize
, 0xbe);
101 ((PSIZE_T
)UserBuffer
)[-1] = 0;
102 ((PSIZE_T
)UserBuffer
)[-2] = 0xFAFBFCFD;
104 for (i
= 0; i
< CurrentAllocation
; ++i
)
105 if (Allocations
[i
] == UserBuffer
)
107 Allocations
[i
] = NULL
;
110 ValidateAllocations();
112 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &AllocationStart
, &Zero
, MEM_RELEASE
);
113 ASSERT(Status
== STATUS_SUCCESS
);
125 OldDataSize
= ((PSIZE_T
)OldUserBuffer
)[-1];
126 ASSERT(OldDataSize
!= 0);
128 NewUserBuffer
= Allocate(NewDataSize
);
129 ASSERT(((PSIZE_T
)OldUserBuffer
)[-1] == OldDataSize
);
130 RtlCopyMemory(NewUserBuffer
, OldUserBuffer
, min(OldDataSize
, NewDataSize
));
131 ASSERT(((PSIZE_T
)OldUserBuffer
)[-1] == OldDataSize
);
133 return NewUserBuffer
;
142 PBYTE Buffer
= UserBuffer
;
145 for (i
= 0; i
< DataSize
; ++i
)
146 Buffer
[i
] = LOBYTE(i
);
155 PBYTE Buffer
= UserBuffer
;
158 for (i
= 0; i
< DataSize
; ++i
)
159 if (Buffer
[i
] != LOBYTE(i
))
161 trace("Mismatch in region %p at index %lu. Value=%02x\n", UserBuffer
, (ULONG
)i
, Buffer
[i
]);
174 PBYTE Buffer
= UserBuffer
;
177 for (i
= 0; i
< DataSize
; ++i
)
178 Buffer
[i
] = UCHAR_MAX
- LOBYTE(i
);
187 PBYTE Buffer
= UserBuffer
;
190 for (i
= 0; i
< DataSize
; ++i
)
191 if (Buffer
[i
] != UCHAR_MAX
- LOBYTE(i
))
193 trace("Mismatch in region %p at index %lu. Value=%02x\n", UserBuffer
, (ULONG
)i
, Buffer
[i
]);
201 CheckSize(ULONG_PTR Base
, SIZE_T InSize
, SIZE_T ExpectedSize
)
208 BaseAddress
= (PVOID
)Base
;
210 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
216 ok(NT_SUCCESS(Status
), "NtAllocateVirtualMemory failed!\n");
217 ok(BaseAddress
== (PVOID
)(Base
& ~((ULONG_PTR
)0xFFFF)), "Got back wrong base address: %p\n", BaseAddress
);
218 ok(Size
== ExpectedSize
, "Alloc of 0x%Ix: got back wrong size: 0x%Ix, expected 0x%Ix\n", InSize
, Size
, ExpectedSize
);
219 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
220 ok(NT_SUCCESS(Status
), "NtFreeVirtualMemory failed!\n");
230 CheckSize(0x50000000, 0x0001, 0x1000);
231 CheckSize(0x50008000, 0x0001, 0x9000);
232 CheckSize(0x50000010, 0x1000, 0x2000);
233 CheckSize(0x50010000, 0x2000, 0x2000);
234 CheckSize(0x5000FFFF, 0x3000, 0x13000);
235 CheckSize(0x50001010, 0x7000, 0x9000);
236 CheckSize(0x50001010, 0xC000, 0xe000);
238 /* Reserve memory not aligned to allocation granularity */
239 BaseAddress
= UlongToPtr(0x50001010);
241 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
247 ok_ntstatus(Status
, STATUS_SUCCESS
);
248 ok(BaseAddress
== UlongToPtr(0x50000000), "Got back wrong base address: %p", BaseAddress
);
249 ok(Size
== 0x3000, "Got back wrong size: 0x%Ix", Size
);
251 /* Try to reserve again in the same 64k region */
252 BaseAddress
= UlongToPtr(0x50008000);
254 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
260 ok_ntstatus(Status
, STATUS_CONFLICTING_ADDRESSES
);
263 BaseAddress
= UlongToPtr(0x50002000);
265 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
271 ok_ntstatus(Status
, STATUS_SUCCESS
);
272 ok(BaseAddress
== UlongToPtr(0x50002000), "Got back wrong base address: %p", BaseAddress
);
273 ok(Size
== 0x1000, "Got back wrong size: 0x%Ix", Size
);
275 /* Commit the same address again with a different protection */
276 BaseAddress
= UlongToPtr(0x50002000);
278 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
284 ok_ntstatus(Status
, STATUS_SUCCESS
);
285 ok(BaseAddress
== UlongToPtr(0x50002000), "Got back wrong base address: %p", BaseAddress
);
286 ok(Size
== 0x1000, "Got back wrong size: 0x%Ix", Size
);
288 /* Commit memory at a too high address */
289 BaseAddress
= UlongToPtr(0x50003000);
291 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
297 ok_ntstatus(Status
, STATUS_CONFLICTING_ADDRESSES
);
299 /* Decommit the memory, even those pages that were not committed */
300 BaseAddress
= UlongToPtr(0x50000000);
302 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_DECOMMIT
);
303 ok_ntstatus(Status
, STATUS_SUCCESS
);
305 /* Try to release memory in a different 64k region */
306 BaseAddress
= UlongToPtr(0x50010000);
308 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
309 ok_ntstatus(Status
, STATUS_MEMORY_NOT_ALLOCATED
);
311 /* Release the memory in the same 64k region at a different address */
312 BaseAddress
= UlongToPtr(0x50008000);
314 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
315 ok_ntstatus(Status
, STATUS_MEMORY_NOT_ALLOCATED
);
317 /* Release the memory at the correct address but with wrong size */
318 BaseAddress
= UlongToPtr(0x50000000);
320 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
321 ok_ntstatus(Status
, STATUS_UNABLE_TO_FREE_VM
);
323 /* Release the memory */
324 BaseAddress
= UlongToPtr(0x50000000);
326 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
327 ok_ntstatus(Status
, STATUS_SUCCESS
);
329 /* Reserve and commit at once */
330 BaseAddress
= UlongToPtr(0x50004080);
332 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
336 MEM_RESERVE
| MEM_COMMIT
,
338 ok_ntstatus(Status
, STATUS_SUCCESS
);
339 ok(BaseAddress
== UlongToPtr(0x50000000), "Got back wrong base address: %p", BaseAddress
);
340 ok(Size
== 0x6000, "Got back wrong size: 0x%Ix", Size
);
344 *(int*)BaseAddress
= 1;
345 *(int*)UlongToPtr(0x50004080) = 1;
347 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
349 ok(0, "Got exception\n");
353 /* Release the memory */
354 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
355 ok_ntstatus(Status
, STATUS_SUCCESS
);
366 MEMORY_BASIC_INFORMATION MemoryBasicInfo
;
368 /* Reserve a full 64k region */
369 BaseAddress
= UlongToPtr(0x50000000);
371 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
377 ok_ntstatus(Status
, STATUS_SUCCESS
);
378 if (!NT_SUCCESS(Status
))
381 /* Reserve another 64k region, but with 64k between */
382 BaseAddress
= UlongToPtr(0x50020000);
384 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
390 ok_ntstatus(Status
, STATUS_SUCCESS
);
391 if (!NT_SUCCESS(Status
))
394 /* Try to free the whole at once */
395 BaseAddress
= UlongToPtr(0x50000000);
397 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
398 ok_ntstatus(Status
, STATUS_UNABLE_TO_FREE_VM
);
400 /* Reserve the part in the middle */
401 BaseAddress
= UlongToPtr(0x50010000);
403 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
409 ok_ntstatus(Status
, STATUS_SUCCESS
);
411 /* Try to commit memory covering 2 allocations */
412 BaseAddress
= UlongToPtr(0x50004000);
414 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
420 ok_ntstatus(Status
, STATUS_CONFLICTING_ADDRESSES
);
423 BaseAddress
= UlongToPtr(0x50000000);
425 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
431 ok_ntstatus(Status
, STATUS_SUCCESS
);
433 /* Commit another page */
434 BaseAddress
= UlongToPtr(0x50002000);
436 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
442 ok_ntstatus(Status
, STATUS_SUCCESS
);
446 *(int*)UlongToPtr(0x50000000) = 1;
448 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
450 ok(0, "Got exception\n");
456 (void)*(volatile int*)UlongToPtr(0x50002000);
458 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
460 Status
= _SEH2_GetExceptionCode();
463 ok_ntstatus(Status
, STATUS_ACCESS_VIOLATION
);
465 /* Allocate 3 pages, on top of the previous 2 */
466 BaseAddress
= UlongToPtr(0x50000000);
468 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
474 ok_ntstatus(Status
, STATUS_SUCCESS
);
478 *(int*)UlongToPtr(0x50000000) = 1;
480 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
482 Status
= _SEH2_GetExceptionCode();
485 ok_ntstatus(Status
, STATUS_ACCESS_VIOLATION
);
487 /* Commit a page at the end of the first region */
488 BaseAddress
= UlongToPtr(0x5000F000);
490 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
496 ok_ntstatus(Status
, STATUS_SUCCESS
);
497 ok_ptr(BaseAddress
, UlongToPtr(0x5000F000));
499 /* See where is the base of this newly committed area
500 * (choose a base address in the middle of it) */
501 Status
= NtQueryVirtualMemory(NtCurrentProcess(),
502 UlongToPtr(0x5000F700),
503 MemoryBasicInformation
,
505 sizeof(MemoryBasicInfo
),
507 ok_ntstatus(Status
, STATUS_SUCCESS
);
508 /* The base address is the beginning of the committed area */
509 ok_ptr(MemoryBasicInfo
.BaseAddress
, UlongToPtr(0x5000F000));
510 /* The allocation base address is the beginning of the whole region */
511 ok_ptr(MemoryBasicInfo
.AllocationBase
, UlongToPtr(0x50000000));
512 /* This is the protection of the memory when it was reserved. */
513 ok_long(MemoryBasicInfo
.AllocationProtect
, PAGE_NOACCESS
);
514 /* This is the size of the committed region. (ie, smallest chunk size) */
515 ok_long(MemoryBasicInfo
.RegionSize
, 0x1000);
516 /* This is the state of the queried address */
517 ok_long(MemoryBasicInfo
.State
, MEM_COMMIT
);
518 /* This is the protection of the queried address */
519 ok_long(MemoryBasicInfo
.Protect
, PAGE_READWRITE
);
520 /* NtAllocateVirtualMemory makes it MEM_PRIVATE */
521 ok_long(MemoryBasicInfo
.Type
, MEM_PRIVATE
);
523 /* Try to free the whole region at once */
524 BaseAddress
= UlongToPtr(0x50000000);
526 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
527 ok_ntstatus(Status
, STATUS_UNABLE_TO_FREE_VM
);
529 BaseAddress
= UlongToPtr(0x50000000);
531 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
532 ok_ntstatus(Status
, STATUS_SUCCESS
);
534 BaseAddress
= UlongToPtr(0x50010000);
536 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
537 ok_ntstatus(Status
, STATUS_SUCCESS
);
539 BaseAddress
= UlongToPtr(0x50020000);
541 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
542 ok_ntstatus(Status
, STATUS_SUCCESS
);
544 /* Reserve 3 full 64k region */
545 BaseAddress
= UlongToPtr(0x50000000);
547 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
553 ok_ntstatus(Status
, STATUS_SUCCESS
);
554 if (!NT_SUCCESS(Status
))
557 /* Release the 64k region in the middle */
558 BaseAddress
= UlongToPtr(0x50010000);
560 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
561 ok_ntstatus(Status
, STATUS_SUCCESS
);
567 START_TEST(NtAllocateVirtualMemory
)
577 /* Reserve memory below 0x10000 */
578 Mem1
= UlongToPtr(0xf000);
580 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
586 ok_ntstatus(Status
, STATUS_INVALID_PARAMETER_2
);
588 /* Reserve memory at 0x10000 */
589 Mem1
= UlongToPtr(0x10000);
591 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
597 ok_ntstatus(Status
, STATUS_CONFLICTING_ADDRESSES
);
600 Mem1
= Allocate(Size1
);
601 AccessMemory1(Mem1
, Size1
);
603 Mem2
= Allocate(Size2
);
604 AccessMemory2(Mem2
, Size2
);
605 for (i
= 0; i
< RUNS
; ++i
)
608 ok(CheckMemory1(Mem1
, Size1
) == TRUE
, "CheckMemory1 failure\n");
609 New
= ReAllocate(Mem1
, Size1
* 3 / 2);
612 skip("Realloc failure\n");
616 ok(CheckMemory1(Mem1
, Size1
) == TRUE
, "CheckMemory1 failure\n");
617 Size1
= Size1
* 3 / 2;
618 AccessMemory1(Mem1
, Size1
);
620 ok(CheckMemory2(Mem2
, Size2
) == TRUE
, "CheckMemory2 failure\n");
621 New
= ReAllocate(Mem2
, Size2
+ 128);
624 skip("Realloc failure\n");
628 ok(CheckMemory2(Mem2
, Size2
) == TRUE
, "CheckMemory2 failure\n");
630 AccessMemory2(Mem2
, Size2
);
632 ok(CheckMemory2(Mem2
, Size2
) == TRUE
, "CheckMemory2 failure\n");
634 ok(CheckMemory1(Mem1
, Size1
) == TRUE
, "CheckMemory1 failure\n");