[USBSTOR]
[reactos.git] / rostests / apitests / ntdll / NtAllocateVirtualMemory.c
1 /*
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>
6 */
7
8 #include <apitest.h>
9
10 #define WIN32_NO_STATUS
11 #include <ndk/rtlfuncs.h>
12 #include <ndk/mmfuncs.h>
13
14 static PVOID Allocations[4096] = { NULL };
15 static ULONG CurrentAllocation = 0;
16
17 static
18 VOID
19 ValidateAllocations(VOID)
20 {
21 ULONG i;
22
23 ASSERT(CurrentAllocation < sizeof(Allocations) / sizeof(Allocations[0]));
24 for (i = 0; i < CurrentAllocation; ++i)
25 {
26 PUCHAR UserBuffer = Allocations[i];
27 SIZE_T AllocationSize;
28 SIZE_T DataSize;
29
30 if (UserBuffer == NULL)
31 continue;
32
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);
39 }
40 }
41
42 static
43 PVOID
44 Allocate(
45 SIZE_T DataSize)
46 {
47 NTSTATUS Status;
48 PVOID AllocationStart = NULL;
49 SIZE_T AllocationSize = PAGE_ROUND_UP(DataSize + PAGE_SIZE + 2 * sizeof(SIZE_T));
50 PVOID FirstPageStart;
51 SIZE_T NumberOfPages = AllocationSize / PAGE_SIZE;
52 SIZE_T Size;
53 PUCHAR UserBuffer;
54
55 Status = NtAllocateVirtualMemory(NtCurrentProcess(), &AllocationStart, 0, &AllocationSize, MEM_RESERVE, PAGE_NOACCESS);
56
57 if (!NT_SUCCESS(Status))
58 return NULL;
59
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))
64 {
65 AllocationSize = 0;
66 Status = NtFreeVirtualMemory(NtCurrentProcess(), &AllocationStart, &AllocationSize, MEM_RELEASE);
67 ASSERT(Status == STATUS_SUCCESS);
68 return NULL;
69 }
70 ASSERT(Size % sizeof(ULONG) == 0);
71 ASSERT(RtlCompareMemoryUlong(FirstPageStart, Size, 0) == Size);
72
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;
79
80 Allocations[CurrentAllocation++] = UserBuffer;
81 ValidateAllocations();
82 return UserBuffer;
83 }
84
85 static
86 VOID
87 Free(
88 PVOID UserBuffer)
89 {
90 NTSTATUS Status;
91 PVOID AllocationStart;
92 SIZE_T Zero = 0;
93 SIZE_T AllocationSize;
94 SIZE_T DataSize;
95 ULONG i;
96
97 AllocationSize = ((PSIZE_T)UserBuffer)[-2];
98 DataSize = ((PSIZE_T)UserBuffer)[-1];
99 ASSERT(DataSize != 0);
100
101 AllocationStart = (PUCHAR)UserBuffer + DataSize + PAGE_SIZE - AllocationSize;
102 ASSERT((SIZE_T)AllocationStart % PAGE_SIZE == 0);
103
104 RtlFillMemory(UserBuffer, DataSize, 0xbe);
105 ((PSIZE_T)UserBuffer)[-1] = 0;
106 ((PSIZE_T)UserBuffer)[-2] = 0xFAFBFCFD;
107
108 for (i = 0; i < CurrentAllocation; ++i)
109 if (Allocations[i] == UserBuffer)
110 {
111 Allocations[i] = NULL;
112 break;
113 }
114 ValidateAllocations();
115
116 Status = NtFreeVirtualMemory(NtCurrentProcess(), &AllocationStart, &Zero, MEM_RELEASE);
117 ASSERT(Status == STATUS_SUCCESS);
118 }
119
120 static
121 PVOID
122 ReAllocate(
123 PVOID OldUserBuffer,
124 SIZE_T NewDataSize)
125 {
126 PVOID NewUserBuffer;
127 SIZE_T OldDataSize;
128
129 OldDataSize = ((PSIZE_T)OldUserBuffer)[-1];
130 ASSERT(OldDataSize != 0);
131
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);
136 Free(OldUserBuffer);
137 return NewUserBuffer;
138 }
139
140 static
141 VOID
142 AccessMemory1(
143 PVOID UserBuffer,
144 SIZE_T DataSize)
145 {
146 PBYTE Buffer = UserBuffer;
147 SIZE_T i;
148
149 for (i = 0; i < DataSize; ++i)
150 Buffer[i] = LOBYTE(i);
151 }
152
153 static
154 BOOLEAN
155 CheckMemory1(
156 PVOID UserBuffer,
157 SIZE_T DataSize)
158 {
159 PBYTE Buffer = UserBuffer;
160 SIZE_T i;
161
162 for (i = 0; i < DataSize; ++i)
163 if (Buffer[i] != LOBYTE(i))
164 {
165 trace("Mismatch in region %p at index %lu. Value=%02x\n", UserBuffer, (ULONG)i, Buffer[i]);
166 ASSERT(FALSE);
167 return FALSE;
168 }
169 return TRUE;
170 }
171
172 static
173 VOID
174 AccessMemory2(
175 PVOID UserBuffer,
176 SIZE_T DataSize)
177 {
178 PBYTE Buffer = UserBuffer;
179 SIZE_T i;
180
181 for (i = 0; i < DataSize; ++i)
182 Buffer[i] = UCHAR_MAX - LOBYTE(i);
183 }
184
185 static
186 BOOLEAN
187 CheckMemory2(
188 PVOID UserBuffer,
189 SIZE_T DataSize)
190 {
191 PBYTE Buffer = UserBuffer;
192 SIZE_T i;
193
194 for (i = 0; i < DataSize; ++i)
195 if (Buffer[i] != UCHAR_MAX - LOBYTE(i))
196 {
197 trace("Mismatch in region %p at index %lu. Value=%02x\n", UserBuffer, (ULONG)i, Buffer[i]);
198 ASSERT(FALSE);
199 return FALSE;
200 }
201 return TRUE;
202 }
203
204 VOID
205 CheckSize(ULONG_PTR Base, SIZE_T InSize, SIZE_T ExpectedSize)
206 {
207 NTSTATUS Status;
208 PVOID BaseAddress;
209 SIZE_T Size;
210
211 /* Reserve memory */
212 BaseAddress = (PVOID)Base;
213 Size = InSize;
214 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
215 &BaseAddress,
216 0,
217 &Size,
218 MEM_RESERVE,
219 PAGE_NOACCESS);
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");
225 }
226
227 VOID
228 CheckAlignment()
229 {
230 NTSTATUS Status;
231 PVOID BaseAddress;
232 SIZE_T Size;
233
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);
241
242 /* Reserve memory not aligned to allocation granularity */
243 BaseAddress = UlongToPtr(0x50001010);
244 Size = 0x1000;
245 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
246 &BaseAddress,
247 0,
248 &Size,
249 MEM_RESERVE,
250 PAGE_NOACCESS);
251 ok(NT_SUCCESS(Status), "NtAllocateVirtualMemory failed!\n");
252 ok(BaseAddress == UlongToPtr(0x50000000), "Got back wrong base address: %p", BaseAddress);
253 ok(Size == 0x3000, "Got back wrong size: 0x%Ix", Size);
254
255 /* Try to reserve again in the same 64k region */
256 BaseAddress = UlongToPtr(0x50008000);
257 Size = 0x1000;
258 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
259 &BaseAddress,
260 0,
261 &Size,
262 MEM_RESERVE,
263 PAGE_NOACCESS);
264 ok(!NT_SUCCESS(Status), "NtAllocateVirtualMemory should fail!\n");
265
266 /* Commit memory */
267 BaseAddress = UlongToPtr(0x50002000);
268 Size = 0x1000;
269 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
270 &BaseAddress,
271 0,
272 &Size,
273 MEM_COMMIT,
274 PAGE_NOACCESS);
275 ok(NT_SUCCESS(Status), "NtAllocateVirtualMemory failed!\n");
276 ok(BaseAddress == UlongToPtr(0x50002000), "Got back wrong base address: %p", BaseAddress);
277 ok(Size == 0x1000, "Got back wrong size: 0x%Ix", Size);
278
279 /* Commit memory */
280 BaseAddress = UlongToPtr(0x50003000);
281 Size = 0x1000;
282 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
283 &BaseAddress,
284 0,
285 &Size,
286 MEM_COMMIT,
287 PAGE_NOACCESS);
288 ok(!NT_SUCCESS(Status), "NtAllocateVirtualMemory should fail!\n");
289
290 /* Try to release memory in a different 64k region */
291 BaseAddress = UlongToPtr(0x50010000);
292 Size = 0x1000;
293 Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
294 ok(!NT_SUCCESS(Status), "NtFreeVirtualMemory should fail!\n");
295
296 /* Release the memory in the same 64k region at a different address */
297 BaseAddress = UlongToPtr(0x50008000);
298 Size = 0x1000;
299 Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
300 ok(!NT_SUCCESS(Status), "NtFreeVirtualMemory failed!\n");
301
302 /* Release the memory at the correct address but with wrong size */
303 BaseAddress = UlongToPtr(0x50000000);
304 Size = 0x4000;
305 Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
306 ok(!NT_SUCCESS(Status), "NtFreeVirtualMemory should fail!\n");
307
308 /* Release the memory */
309 BaseAddress = UlongToPtr(0x50000000);
310 Size = 0x3000;
311 Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
312 ok(NT_SUCCESS(Status), "NtFreeVirtualMemory failed!\n");
313
314 /* Reserve and commit at once */
315 BaseAddress = UlongToPtr(0x50004080);
316 Size = 0x1000;
317 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
318 &BaseAddress,
319 0,
320 &Size,
321 MEM_RESERVE | MEM_COMMIT,
322 PAGE_READWRITE);
323 ok(NT_SUCCESS(Status), "NtAllocateVirtualMemory failed!\n");
324 ok(BaseAddress == UlongToPtr(0x50000000), "Got back wrong base address: %p", BaseAddress);
325 ok(Size == 0x6000, "Got back wrong size: 0x%Ix", Size);
326
327 _SEH2_TRY
328 {
329 *(int*)BaseAddress = 1;
330 *(int*)UlongToPtr(0x50004080) = 1;
331 }
332 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
333 {
334 ok(0, "Got exception\n");
335 }
336 _SEH2_END;
337
338 /* Release the memory */
339 Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
340 ok(NT_SUCCESS(Status), "NtFreeVirtualMemory failed!\n");
341
342 }
343
344 static
345 VOID
346 CheckAdjacentVADs()
347 {
348 NTSTATUS Status;
349 PVOID BaseAddress;
350 SIZE_T Size;
351
352 /* Reserve a full 64k region */
353 BaseAddress = UlongToPtr(0x50000000);
354 Size = 0x10000;
355 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
356 &BaseAddress,
357 0,
358 &Size,
359 MEM_RESERVE,
360 PAGE_NOACCESS);
361 ok(NT_SUCCESS(Status), "NtAllocateVirtualMemory failed!\n");
362 if (!NT_SUCCESS(Status))
363 return;
364
365 /* Reserve another 64k region, but with 64k between */
366 BaseAddress = UlongToPtr(0x50020000);
367 Size = 0x10000;
368 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
369 &BaseAddress,
370 0,
371 &Size,
372 MEM_RESERVE,
373 PAGE_NOACCESS);
374 ok(NT_SUCCESS(Status), "NtAllocateVirtualMemory failed!\n");
375 if (!NT_SUCCESS(Status))
376 return;
377
378 /* Try to free the whole at once */
379 BaseAddress = UlongToPtr(0x50000000);
380 Size = 0x30000;
381 Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
382 ok(!NT_SUCCESS(Status), "NtFreeVirtualMemory should fail!\n");
383
384 /* Reserve the part in the middle */
385 BaseAddress = UlongToPtr(0x50010000);
386 Size = 0x10000;
387 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
388 &BaseAddress,
389 0,
390 &Size,
391 MEM_RESERVE,
392 PAGE_NOACCESS);
393 ok(NT_SUCCESS(Status), "NtAllocateVirtualMemory failed!\n");
394
395 /* Try to commit memory covering 2 allocations */
396 BaseAddress = UlongToPtr(0x50004000);
397 Size = 0x10000;
398 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
399 &BaseAddress,
400 0,
401 &Size,
402 MEM_COMMIT,
403 PAGE_NOACCESS);
404 ok(!NT_SUCCESS(Status), "NtAllocateVirtualMemory should fail!\n");
405
406 /* Commit a page */
407 BaseAddress = UlongToPtr(0x50000000);
408 Size = 0x1000;
409 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
410 &BaseAddress,
411 0,
412 &Size,
413 MEM_COMMIT,
414 PAGE_READWRITE);
415 ok(NT_SUCCESS(Status), "NtAllocateVirtualMemory failed!\n");
416
417 /* Commit another page */
418 BaseAddress = UlongToPtr(0x50002000);
419 Size = 0x1000;
420 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
421 &BaseAddress,
422 0,
423 &Size,
424 MEM_COMMIT,
425 PAGE_NOACCESS);
426 ok(NT_SUCCESS(Status), "NtAllocateVirtualMemory failed!\n");
427
428 _SEH2_TRY
429 {
430 *(int*)UlongToPtr(0x50000000) = 1;
431 }
432 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
433 {
434 ok(0, "Got exception\n");
435 }
436 _SEH2_END;
437
438 _SEH2_TRY
439 {
440 (void)*(volatile int*)UlongToPtr(0x50002000);
441 }
442 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
443 {
444 Status = _SEH2_GetExceptionCode();
445 }
446 _SEH2_END;
447 ok(Status = STATUS_ACCESS_VIOLATION, "Should get an exception!\n");
448
449 /* Allocate 3 pages, on top of the previous 2 */
450 BaseAddress = UlongToPtr(0x50000000);
451 Size = 0x3000;
452 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
453 &BaseAddress,
454 0,
455 &Size,
456 MEM_COMMIT,
457 PAGE_READONLY);
458 ok(NT_SUCCESS(Status), "NtAllocateVirtualMemory failed!\n");
459
460 _SEH2_TRY
461 {
462 *(int*)UlongToPtr(0x50000000) = 1;
463 }
464 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
465 {
466 Status = _SEH2_GetExceptionCode();
467 }
468 _SEH2_END;
469 ok(Status = STATUS_ACCESS_VIOLATION, "Should get an exception!\n");
470
471 /* Try to free the whole region at once */
472 BaseAddress = UlongToPtr(0x50000000);
473 Size = 0x30000;
474 Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
475 ok(!NT_SUCCESS(Status), "NtFreeVirtualMemory should fail!\n");
476
477 BaseAddress = UlongToPtr(0x50000000);
478 Size = 0x10000;
479 Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
480 ok(NT_SUCCESS(Status), "NtFreeVirtualMemory failed!\n");
481
482 BaseAddress = UlongToPtr(0x50010000);
483 Size = 0x10000;
484 Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
485 ok(NT_SUCCESS(Status), "NtFreeVirtualMemory failed!\n");
486
487 BaseAddress = UlongToPtr(0x50020000);
488 Size = 0x10000;
489 Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
490 ok(NT_SUCCESS(Status), "NtFreeVirtualMemory failed!\n");
491
492 /* Reserve 3 full 64k region */
493 BaseAddress = UlongToPtr(0x50000000);
494 Size = 0x30000;
495 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
496 &BaseAddress,
497 0,
498 &Size,
499 MEM_RESERVE,
500 PAGE_NOACCESS);
501 ok(NT_SUCCESS(Status), "NtAllocateVirtualMemory failed!\n");
502 if (!NT_SUCCESS(Status))
503 return;
504
505 /* Release the 64k region in the middle */
506 BaseAddress = UlongToPtr(0x50010000);
507 Size = 0x10000;
508 Status = NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, MEM_RELEASE);
509 ok(NT_SUCCESS(Status), "NtFreeVirtualMemory failed!\n");
510
511 }
512
513 #define RUNS 32
514
515 START_TEST(NtAllocateVirtualMemory)
516 {
517 PVOID Mem1, Mem2;
518 SIZE_T Size1, Size2;
519 ULONG i;
520
521 CheckAlignment();
522 CheckAdjacentVADs();
523
524 Size1 = 32;
525 Mem1 = Allocate(Size1);
526 AccessMemory1(Mem1, Size1);
527 Size2 = 128;
528 Mem2 = Allocate(Size2);
529 AccessMemory2(Mem2, Size2);
530 for (i = 0; i < RUNS; ++i)
531 {
532 PVOID New;
533 ok(CheckMemory1(Mem1, Size1) == TRUE, "CheckMemory1 failure\n");
534 New = ReAllocate(Mem1, Size1 * 3 / 2);
535 if (New == NULL)
536 {
537 skip("Realloc failure\n");
538 break;
539 }
540 Mem1 = New;
541 ok(CheckMemory1(Mem1, Size1) == TRUE, "CheckMemory1 failure\n");
542 Size1 = Size1 * 3 / 2;
543 AccessMemory1(Mem1, Size1);
544
545 ok(CheckMemory2(Mem2, Size2) == TRUE, "CheckMemory2 failure\n");
546 New = ReAllocate(Mem2, Size2 + 128);
547 if (New == NULL)
548 {
549 skip("Realloc failure\n");
550 break;
551 }
552 Mem2 = New;
553 ok(CheckMemory2(Mem2, Size2) == TRUE, "CheckMemory2 failure\n");
554 Size2 += 128;
555 AccessMemory2(Mem2, Size2);
556 }
557 ok(CheckMemory2(Mem2, Size2) == TRUE, "CheckMemory2 failure\n");
558 Free(Mem2);
559 ok(CheckMemory1(Mem1, Size1) == TRUE, "CheckMemory1 failure\n");
560 Free(Mem1);
561 }