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 #define WIN32_NO_STATUS
11 #include <ndk/rtlfuncs.h>
12 #include <ndk/mmfuncs.h>
14 static PVOID Allocations
[4096] = { NULL
};
15 static ULONG CurrentAllocation
= 0;
19 ValidateAllocations(VOID
)
23 ASSERT(CurrentAllocation
< sizeof(Allocations
) / sizeof(Allocations
[0]));
24 for (i
= 0; i
< CurrentAllocation
; ++i
)
26 PUCHAR UserBuffer
= Allocations
[i
];
27 SIZE_T AllocationSize
;
30 if (UserBuffer
== NULL
)
33 AllocationSize
= ((PSIZE_T
)UserBuffer
)[-2];
34 DataSize
= ((PSIZE_T
)UserBuffer
)[-1];
35 ASSERT(AllocationSize
!= 0);
36 ASSERT(AllocationSize
% PAGE_SIZE
== 0);
37 ASSERT(DataSize
!= 0);
38 ASSERT(((SIZE_T
)UserBuffer
+ DataSize
) % PAGE_SIZE
== 0);
48 PVOID AllocationStart
= NULL
;
49 SIZE_T AllocationSize
= PAGE_ROUND_UP(DataSize
+ PAGE_SIZE
+ 2 * sizeof(SIZE_T
));
51 SIZE_T NumberOfPages
= AllocationSize
/ PAGE_SIZE
;
55 Status
= NtAllocateVirtualMemory(NtCurrentProcess(), &AllocationStart
, 0, &AllocationSize
, MEM_RESERVE
, PAGE_NOACCESS
);
57 if (!NT_SUCCESS(Status
))
60 FirstPageStart
= (PUCHAR
)AllocationStart
+ AllocationSize
- PAGE_SIZE
* NumberOfPages
;
61 Size
= (NumberOfPages
- 1) * PAGE_SIZE
;
62 Status
= NtAllocateVirtualMemory(NtCurrentProcess(), &FirstPageStart
, 0, &Size
, MEM_COMMIT
, PAGE_READWRITE
);
63 if (!NT_SUCCESS(Status
))
66 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &AllocationStart
, &AllocationSize
, MEM_RELEASE
);
67 ASSERT(Status
== STATUS_SUCCESS
);
70 ASSERT(Size
% sizeof(ULONG
) == 0);
71 ASSERT(RtlCompareMemoryUlong(FirstPageStart
, Size
, 0) == Size
);
73 UserBuffer
= AllocationStart
;
74 UserBuffer
+= AllocationSize
- PAGE_SIZE
- DataSize
;
75 RtlFillMemory(FirstPageStart
, UserBuffer
- (PUCHAR
)FirstPageStart
, 0xae);
76 RtlZeroMemory(UserBuffer
, DataSize
);
77 ((PSIZE_T
)UserBuffer
)[-2] = AllocationSize
;
78 ((PSIZE_T
)UserBuffer
)[-1] = DataSize
;
80 Allocations
[CurrentAllocation
++] = UserBuffer
;
81 ValidateAllocations();
91 PVOID AllocationStart
;
93 SIZE_T AllocationSize
;
97 AllocationSize
= ((PSIZE_T
)UserBuffer
)[-2];
98 DataSize
= ((PSIZE_T
)UserBuffer
)[-1];
99 ASSERT(DataSize
!= 0);
101 AllocationStart
= (PUCHAR
)UserBuffer
+ DataSize
+ PAGE_SIZE
- AllocationSize
;
102 ASSERT((SIZE_T
)AllocationStart
% PAGE_SIZE
== 0);
104 RtlFillMemory(UserBuffer
, DataSize
, 0xbe);
105 ((PSIZE_T
)UserBuffer
)[-1] = 0;
106 ((PSIZE_T
)UserBuffer
)[-2] = 0xFAFBFCFD;
108 for (i
= 0; i
< CurrentAllocation
; ++i
)
109 if (Allocations
[i
] == UserBuffer
)
111 Allocations
[i
] = NULL
;
114 ValidateAllocations();
116 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &AllocationStart
, &Zero
, MEM_RELEASE
);
117 ASSERT(Status
== STATUS_SUCCESS
);
129 OldDataSize
= ((PSIZE_T
)OldUserBuffer
)[-1];
130 ASSERT(OldDataSize
!= 0);
132 NewUserBuffer
= Allocate(NewDataSize
);
133 ASSERT(((PSIZE_T
)OldUserBuffer
)[-1] == OldDataSize
);
134 RtlCopyMemory(NewUserBuffer
, OldUserBuffer
, min(OldDataSize
, NewDataSize
));
135 ASSERT(((PSIZE_T
)OldUserBuffer
)[-1] == OldDataSize
);
137 return NewUserBuffer
;
146 PBYTE Buffer
= UserBuffer
;
149 for (i
= 0; i
< DataSize
; ++i
)
150 Buffer
[i
] = LOBYTE(i
);
159 PBYTE Buffer
= UserBuffer
;
162 for (i
= 0; i
< DataSize
; ++i
)
163 if (Buffer
[i
] != LOBYTE(i
))
165 trace("Mismatch in region %p at index %lu. Value=%02x\n", UserBuffer
, (ULONG
)i
, Buffer
[i
]);
178 PBYTE Buffer
= UserBuffer
;
181 for (i
= 0; i
< DataSize
; ++i
)
182 Buffer
[i
] = UCHAR_MAX
- LOBYTE(i
);
191 PBYTE Buffer
= UserBuffer
;
194 for (i
= 0; i
< DataSize
; ++i
)
195 if (Buffer
[i
] != UCHAR_MAX
- LOBYTE(i
))
197 trace("Mismatch in region %p at index %lu. Value=%02x\n", UserBuffer
, (ULONG
)i
, Buffer
[i
]);
205 CheckSize(ULONG_PTR Base
, SIZE_T InSize
, SIZE_T ExpectedSize
)
212 BaseAddress
= (PVOID
)Base
;
214 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
220 ok(NT_SUCCESS(Status
), "NtAllocateVirtualMemory failed!\n");
221 ok(BaseAddress
== (PVOID
)(Base
& ~((ULONG_PTR
)0xFFFF)), "Got back wrong base address: %p\n", BaseAddress
);
222 ok(Size
== ExpectedSize
, "Alloc of 0x%Ix: got back wrong size: 0x%Ix, expected 0x%Ix\n", InSize
, Size
, ExpectedSize
);
223 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
224 ok(NT_SUCCESS(Status
), "NtFreeVirtualMemory failed!\n");
234 CheckSize(0x50000000, 0x0001, 0x1000);
235 CheckSize(0x50008000, 0x0001, 0x9000);
236 CheckSize(0x50000010, 0x1000, 0x2000);
237 CheckSize(0x50010000, 0x2000, 0x2000);
238 CheckSize(0x5000FFFF, 0x3000, 0x13000);
239 CheckSize(0x50001010, 0x7000, 0x9000);
240 CheckSize(0x50001010, 0xC000, 0xe000);
242 /* Reserve memory not aligned to allocation granularity */
243 BaseAddress
= UlongToPtr(0x50001010);
245 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
251 ok_ntstatus(Status
, STATUS_SUCCESS
);
252 ok(BaseAddress
== UlongToPtr(0x50000000), "Got back wrong base address: %p", BaseAddress
);
253 ok(Size
== 0x3000, "Got back wrong size: 0x%Ix", Size
);
255 /* Try to reserve again in the same 64k region */
256 BaseAddress
= UlongToPtr(0x50008000);
258 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
264 ok_ntstatus(Status
, STATUS_CONFLICTING_ADDRESSES
);
267 BaseAddress
= UlongToPtr(0x50002000);
269 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
275 ok_ntstatus(Status
, STATUS_SUCCESS
);
276 ok(BaseAddress
== UlongToPtr(0x50002000), "Got back wrong base address: %p", BaseAddress
);
277 ok(Size
== 0x1000, "Got back wrong size: 0x%Ix", Size
);
279 /* Commit the same address again with a different protection */
280 BaseAddress
= UlongToPtr(0x50002000);
282 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
288 ok_ntstatus(Status
, STATUS_SUCCESS
);
289 ok(BaseAddress
== UlongToPtr(0x50002000), "Got back wrong base address: %p", BaseAddress
);
290 ok(Size
== 0x1000, "Got back wrong size: 0x%Ix", Size
);
292 /* Commit memory at a too high address */
293 BaseAddress
= UlongToPtr(0x50003000);
295 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
301 ok_ntstatus(Status
, STATUS_CONFLICTING_ADDRESSES
);
303 /* Decommit the memory, even those pages that were not committed */
304 BaseAddress
= UlongToPtr(0x50000000);
306 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_DECOMMIT
);
307 ok_ntstatus(Status
, STATUS_SUCCESS
);
309 /* Try to release memory in a different 64k region */
310 BaseAddress
= UlongToPtr(0x50010000);
312 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
313 ok_ntstatus(Status
, STATUS_MEMORY_NOT_ALLOCATED
);
315 /* Release the memory in the same 64k region at a different address */
316 BaseAddress
= UlongToPtr(0x50008000);
318 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
319 ok_ntstatus(Status
, STATUS_MEMORY_NOT_ALLOCATED
);
321 /* Release the memory at the correct address but with wrong size */
322 BaseAddress
= UlongToPtr(0x50000000);
324 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
325 ok_ntstatus(Status
, STATUS_UNABLE_TO_FREE_VM
);
327 /* Release the memory */
328 BaseAddress
= UlongToPtr(0x50000000);
330 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
331 ok_ntstatus(Status
, STATUS_SUCCESS
);
333 /* Reserve and commit at once */
334 BaseAddress
= UlongToPtr(0x50004080);
336 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
340 MEM_RESERVE
| MEM_COMMIT
,
342 ok_ntstatus(Status
, STATUS_SUCCESS
);
343 ok(BaseAddress
== UlongToPtr(0x50000000), "Got back wrong base address: %p", BaseAddress
);
344 ok(Size
== 0x6000, "Got back wrong size: 0x%Ix", Size
);
348 *(int*)BaseAddress
= 1;
349 *(int*)UlongToPtr(0x50004080) = 1;
351 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
353 ok(0, "Got exception\n");
357 /* Release the memory */
358 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
359 ok_ntstatus(Status
, STATUS_SUCCESS
);
370 MEMORY_BASIC_INFORMATION MemoryBasicInfo
;
372 /* Reserve a full 64k region */
373 BaseAddress
= UlongToPtr(0x50000000);
375 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
381 ok_ntstatus(Status
, STATUS_SUCCESS
);
382 if (!NT_SUCCESS(Status
))
385 /* Reserve another 64k region, but with 64k between */
386 BaseAddress
= UlongToPtr(0x50020000);
388 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
394 ok_ntstatus(Status
, STATUS_SUCCESS
);
395 if (!NT_SUCCESS(Status
))
398 /* Try to free the whole at once */
399 BaseAddress
= UlongToPtr(0x50000000);
401 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
402 ok_ntstatus(Status
, STATUS_UNABLE_TO_FREE_VM
);
404 /* Reserve the part in the middle */
405 BaseAddress
= UlongToPtr(0x50010000);
407 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
413 ok_ntstatus(Status
, STATUS_SUCCESS
);
415 /* Try to commit memory covering 2 allocations */
416 BaseAddress
= UlongToPtr(0x50004000);
418 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
424 ok_ntstatus(Status
, STATUS_CONFLICTING_ADDRESSES
);
427 BaseAddress
= UlongToPtr(0x50000000);
429 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
435 ok_ntstatus(Status
, STATUS_SUCCESS
);
437 /* Commit another page */
438 BaseAddress
= UlongToPtr(0x50002000);
440 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
446 ok_ntstatus(Status
, STATUS_SUCCESS
);
450 *(int*)UlongToPtr(0x50000000) = 1;
452 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
454 ok(0, "Got exception\n");
460 (void)*(volatile int*)UlongToPtr(0x50002000);
462 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
464 Status
= _SEH2_GetExceptionCode();
467 ok_ntstatus(Status
, STATUS_ACCESS_VIOLATION
);
469 /* Allocate 3 pages, on top of the previous 2 */
470 BaseAddress
= UlongToPtr(0x50000000);
472 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
478 ok_ntstatus(Status
, STATUS_SUCCESS
);
482 *(int*)UlongToPtr(0x50000000) = 1;
484 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
486 Status
= _SEH2_GetExceptionCode();
489 ok_ntstatus(Status
, STATUS_ACCESS_VIOLATION
);
491 /* Commit a page at the end of the first region */
492 BaseAddress
= UlongToPtr(0x5000F000);
494 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
500 ok_ntstatus(Status
, STATUS_SUCCESS
);
501 ok_ptr(BaseAddress
, UlongToPtr(0x5000F000));
503 /* See where is the base of this newly committed area
504 * (choose a base address in the middle of it) */
505 Status
= NtQueryVirtualMemory(NtCurrentProcess(),
506 UlongToPtr(0x5000F700),
507 MemoryBasicInformation
,
509 sizeof(MemoryBasicInfo
),
511 ok_ntstatus(Status
, STATUS_SUCCESS
);
512 /* The base address is the beginning of the committed area */
513 ok_ptr(MemoryBasicInfo
.BaseAddress
, UlongToPtr(0x5000F000));
514 /* The allocation base address is the beginning of the whole region */
515 ok_ptr(MemoryBasicInfo
.AllocationBase
, UlongToPtr(0x50000000));
516 /* This is the protection of the memory when it was reserved. */
517 ok_long(MemoryBasicInfo
.AllocationProtect
, PAGE_NOACCESS
);
518 /* This is the size of the committed region. (ie, smallest chunk size) */
519 ok_long(MemoryBasicInfo
.RegionSize
, 0x1000);
520 /* This is the state of the queried address */
521 ok_long(MemoryBasicInfo
.State
, MEM_COMMIT
);
522 /* This is the protection of the queried address */
523 ok_long(MemoryBasicInfo
.Protect
, PAGE_READWRITE
);
524 /* NtAllocateVirtualMemory makes it MEM_PRIVATE */
525 ok_long(MemoryBasicInfo
.Type
, MEM_PRIVATE
);
527 /* Try to free the whole region at once */
528 BaseAddress
= UlongToPtr(0x50000000);
530 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
531 ok_ntstatus(Status
, STATUS_UNABLE_TO_FREE_VM
);
533 BaseAddress
= UlongToPtr(0x50000000);
535 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
536 ok_ntstatus(Status
, STATUS_SUCCESS
);
538 BaseAddress
= UlongToPtr(0x50010000);
540 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
541 ok_ntstatus(Status
, STATUS_SUCCESS
);
543 BaseAddress
= UlongToPtr(0x50020000);
545 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
546 ok_ntstatus(Status
, STATUS_SUCCESS
);
548 /* Reserve 3 full 64k region */
549 BaseAddress
= UlongToPtr(0x50000000);
551 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
557 ok_ntstatus(Status
, STATUS_SUCCESS
);
558 if (!NT_SUCCESS(Status
))
561 /* Release the 64k region in the middle */
562 BaseAddress
= UlongToPtr(0x50010000);
564 Status
= NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress
, &Size
, MEM_RELEASE
);
565 ok_ntstatus(Status
, STATUS_SUCCESS
);
571 START_TEST(NtAllocateVirtualMemory
)
581 /* Reserve memory below 0x10000 */
582 Mem1
= UlongToPtr(0xf000);
584 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
590 ok_ntstatus(Status
, STATUS_INVALID_PARAMETER_2
);
592 /* Reserve memory at 0x10000 */
593 Mem1
= UlongToPtr(0x10000);
595 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
601 ok_ntstatus(Status
, STATUS_CONFLICTING_ADDRESSES
);
604 Mem1
= Allocate(Size1
);
605 AccessMemory1(Mem1
, Size1
);
607 Mem2
= Allocate(Size2
);
608 AccessMemory2(Mem2
, Size2
);
609 for (i
= 0; i
< RUNS
; ++i
)
612 ok(CheckMemory1(Mem1
, Size1
) == TRUE
, "CheckMemory1 failure\n");
613 New
= ReAllocate(Mem1
, Size1
* 3 / 2);
616 skip("Realloc failure\n");
620 ok(CheckMemory1(Mem1
, Size1
) == TRUE
, "CheckMemory1 failure\n");
621 Size1
= Size1
* 3 / 2;
622 AccessMemory1(Mem1
, Size1
);
624 ok(CheckMemory2(Mem2
, Size2
) == TRUE
, "CheckMemory2 failure\n");
625 New
= ReAllocate(Mem2
, Size2
+ 128);
628 skip("Realloc failure\n");
632 ok(CheckMemory2(Mem2
, Size2
) == TRUE
, "CheckMemory2 failure\n");
634 AccessMemory2(Mem2
, Size2
);
636 ok(CheckMemory2(Mem2
, Size2
) == TRUE
, "CheckMemory2 failure\n");
638 ok(CheckMemory1(Mem1
, Size1
) == TRUE
, "CheckMemory1 failure\n");