[NTDLL_APITEST]
[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 <thfabba@gmx.de>
6 */
7
8 #define WIN32_NO_STATUS
9 #include <stdio.h>
10 #include <wine/test.h>
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(DataSize != 0);
36 ASSERT(((SIZE_T)UserBuffer + DataSize) % PAGE_SIZE == 0);
37 }
38 }
39
40 static
41 PVOID
42 Allocate(
43 SIZE_T DataSize)
44 {
45 NTSTATUS Status;
46 PVOID AllocationStart = NULL;
47 SIZE_T AllocationSize = PAGE_ROUND_UP(DataSize + PAGE_SIZE + 2 * sizeof(SIZE_T));
48 PVOID FirstPageStart;
49 SIZE_T NumberOfPages = AllocationSize / PAGE_SIZE;
50 SIZE_T Size;
51 PUCHAR UserBuffer;
52
53 Status = NtAllocateVirtualMemory(NtCurrentProcess(), &AllocationStart, 0, &AllocationSize, MEM_RESERVE, PAGE_NOACCESS);
54
55 if (!NT_SUCCESS(Status))
56 return NULL;
57
58 FirstPageStart = (PUCHAR)AllocationStart + AllocationSize - PAGE_SIZE * NumberOfPages;
59 Size = (NumberOfPages - 1) * PAGE_SIZE;
60 Status = NtAllocateVirtualMemory(NtCurrentProcess(), &FirstPageStart, 0, &Size, MEM_COMMIT, PAGE_READWRITE);
61 if (!NT_SUCCESS(Status))
62 {
63 AllocationSize = 0;
64 Status = NtFreeVirtualMemory(NtCurrentProcess(), &AllocationStart, &AllocationSize, MEM_RELEASE);
65 ASSERT(Status == STATUS_SUCCESS);
66 return NULL;
67 }
68 ASSERT(Size % sizeof(ULONG) == 0);
69 ASSERT(RtlCompareMemoryUlong(FirstPageStart, Size, 0) == Size);
70
71 UserBuffer = AllocationStart;
72 UserBuffer += AllocationSize - PAGE_SIZE - DataSize;
73 RtlFillMemory(FirstPageStart, UserBuffer - (PUCHAR)FirstPageStart, 0xae);
74 RtlZeroMemory(UserBuffer, DataSize);
75 ((PSIZE_T)UserBuffer)[-2] = AllocationSize;
76 ((PSIZE_T)UserBuffer)[-1] = DataSize;
77
78 Allocations[CurrentAllocation++] = UserBuffer;
79 ValidateAllocations();
80 return UserBuffer;
81 }
82
83 static
84 VOID
85 Free(
86 PVOID UserBuffer)
87 {
88 NTSTATUS Status;
89 PVOID AllocationStart;
90 SIZE_T Zero = 0;
91 SIZE_T AllocationSize;
92 SIZE_T DataSize;
93 ULONG i;
94
95 AllocationSize = ((PSIZE_T)UserBuffer)[-2];
96 DataSize = ((PSIZE_T)UserBuffer)[-1];
97 ASSERT(DataSize != 0);
98
99 AllocationStart = (PUCHAR)UserBuffer + DataSize + PAGE_SIZE - AllocationSize;
100 ASSERT((SIZE_T)AllocationStart % PAGE_SIZE == 0);
101
102 RtlFillMemory(UserBuffer, DataSize, 0xbe);
103 ((PSIZE_T)UserBuffer)[-1] = 0;
104 ((PSIZE_T)UserBuffer)[-2] = 0xFAFBFCFD;
105
106 for (i = 0; i < CurrentAllocation; ++i)
107 if (Allocations[i] == UserBuffer)
108 {
109 Allocations[i] = NULL;
110 break;
111 }
112 ValidateAllocations();
113
114 Status = NtFreeVirtualMemory(NtCurrentProcess(), &AllocationStart, &Zero, MEM_RELEASE);
115 ASSERT(Status == STATUS_SUCCESS);
116 }
117
118 static
119 PVOID
120 ReAllocate(
121 PVOID OldUserBuffer,
122 SIZE_T NewDataSize)
123 {
124 PVOID NewUserBuffer;
125 SIZE_T OldDataSize;
126
127 OldDataSize = ((PSIZE_T)OldUserBuffer)[-1];
128 ASSERT(OldDataSize != 0);
129
130 NewUserBuffer = Allocate(NewDataSize);
131 ASSERT(((PSIZE_T)OldUserBuffer)[-1] == OldDataSize);
132 RtlCopyMemory(NewUserBuffer, OldUserBuffer, min(OldDataSize, NewDataSize));
133 ASSERT(((PSIZE_T)OldUserBuffer)[-1] == OldDataSize);
134 Free(OldUserBuffer);
135 return NewUserBuffer;
136 }
137
138 static
139 VOID
140 AccessMemory1(
141 PVOID UserBuffer,
142 SIZE_T DataSize)
143 {
144 PBYTE Buffer = UserBuffer;
145 SIZE_T i;
146
147 for (i = 0; i < DataSize; ++i)
148 Buffer[i] = LOBYTE(i);
149 }
150
151 static
152 BOOLEAN
153 CheckMemory1(
154 PVOID UserBuffer,
155 SIZE_T DataSize)
156 {
157 PBYTE Buffer = UserBuffer;
158 SIZE_T i;
159
160 for (i = 0; i < DataSize; ++i)
161 if (Buffer[i] != LOBYTE(i))
162 {
163 trace("Mismatch in region %p at index %lu. Value=%02x\n", UserBuffer, (ULONG)i, Buffer[i]);
164 ASSERT(FALSE);
165 return FALSE;
166 }
167 return TRUE;
168 }
169
170 static
171 VOID
172 AccessMemory2(
173 PVOID UserBuffer,
174 SIZE_T DataSize)
175 {
176 PBYTE Buffer = UserBuffer;
177 SIZE_T i;
178
179 for (i = 0; i < DataSize; ++i)
180 Buffer[i] = UCHAR_MAX - LOBYTE(i);
181 }
182
183 static
184 BOOLEAN
185 CheckMemory2(
186 PVOID UserBuffer,
187 SIZE_T DataSize)
188 {
189 PBYTE Buffer = UserBuffer;
190 SIZE_T i;
191
192 for (i = 0; i < DataSize; ++i)
193 if (Buffer[i] != UCHAR_MAX - LOBYTE(i))
194 {
195 trace("Mismatch in region %p at index %lu. Value=%02x\n", UserBuffer, (ULONG)i, Buffer[i]);
196 ASSERT(FALSE);
197 return FALSE;
198 }
199 return TRUE;
200 }
201
202 #define RUNS 32
203
204 START_TEST(NtAllocateVirtualMemory)
205 {
206 PVOID Mem1, Mem2;
207 SIZE_T Size1, Size2;
208 ULONG i;
209
210 Size1 = 32;
211 Mem1 = Allocate(Size1);
212 AccessMemory1(Mem1, Size1);
213 Size2 = 128;
214 Mem2 = Allocate(Size2);
215 AccessMemory2(Mem2, Size2);
216 for (i = 0; i < RUNS; ++i)
217 {
218 PVOID New;
219 ok(CheckMemory1(Mem1, Size1) == TRUE, "CheckMemory1 failure\n");
220 New = ReAllocate(Mem1, Size1 * 3 / 2);
221 if (New == NULL)
222 {
223 skip("Realloc failure\n");
224 break;
225 }
226 Mem1 = New;
227 ok(CheckMemory1(Mem1, Size1) == TRUE, "CheckMemory1 failure\n");
228 Size1 = Size1 * 3 / 2;
229 AccessMemory1(Mem1, Size1);
230
231 ok(CheckMemory2(Mem2, Size2) == TRUE, "CheckMemory2 failure\n");
232 New = ReAllocate(Mem2, Size2 + 128);
233 if (New == NULL)
234 {
235 skip("Realloc failure\n");
236 break;
237 }
238 Mem2 = New;
239 ok(CheckMemory2(Mem2, Size2) == TRUE, "CheckMemory2 failure\n");
240 Size2 += 128;
241 AccessMemory2(Mem2, Size2);
242 }
243 ok(CheckMemory2(Mem2, Size2) == TRUE, "CheckMemory2 failure\n");
244 Free(Mem2);
245 ok(CheckMemory1(Mem1, Size1) == TRUE, "CheckMemory1 failure\n");
246 Free(Mem1);
247 }