[KMTESTS:EX] Add a test that triggers big pool expansion. CORE-15051
[reactos.git] / modules / rostests / kmtests / ntos_ex / ExPools.c
1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Pools test routines KM-Test
5 * PROGRAMMER: Aleksey Bragin <aleksey@reactos.org>
6 */
7
8 #include <kmt_test.h>
9
10 #define NDEBUG
11 #include <debug.h>
12
13 #define TAG_POOLTEST 'tstP'
14
15 #define BASE_POOL_TYPE_MASK 1
16 #define QUOTA_POOL_MASK 8
17
18 static
19 LONG
20 GetRefCount(
21 _In_ PVOID Object)
22 {
23 POBJECT_HEADER Header = OBJECT_TO_OBJECT_HEADER(Object);
24 return Header->PointerCount;
25 }
26
27 static VOID PoolsTest(VOID)
28 {
29 PVOID Ptr;
30 ULONG AllocSize, i, AllocNumber;
31 PVOID *Allocs;
32
33 // Stress-test nonpaged pool
34 for (i=1; i<10000; i++)
35 {
36 // make up some increasing, a bit irregular size
37 AllocSize = i*10;
38
39 if (i % 10)
40 AllocSize++;
41
42 if (i % 25)
43 AllocSize += 13;
44
45 // start with non-paged pool
46 Ptr = ExAllocatePoolWithTag(NonPagedPool, AllocSize, TAG_POOLTEST);
47
48 // it may fail due to no-memory condition
49 if (!Ptr) break;
50
51 // try to fully fill it
52 RtlFillMemory(Ptr, AllocSize, 0xAB);
53
54 // free it
55 ExFreePoolWithTag(Ptr, TAG_POOLTEST);
56 }
57
58 // now paged one
59 for (i=1; i<10000; i++)
60 {
61 // make up some increasing, a bit irregular size
62 AllocSize = i*50;
63
64 if (i % 10)
65 AllocSize++;
66
67 if (i % 25)
68 AllocSize += 13;
69
70 // start with non-paged pool
71 Ptr = ExAllocatePoolWithTag(PagedPool, AllocSize, TAG_POOLTEST);
72
73 // it may fail due to no-memory condition
74 if (!Ptr) break;
75
76 // try to fully fill it
77 RtlFillMemory(Ptr, AllocSize, 0xAB);
78
79 // free it
80 ExFreePoolWithTag(Ptr, TAG_POOLTEST);
81 }
82
83 // test super-big allocations
84 /*AllocSize = 2UL * 1024 * 1024 * 1024;
85 Ptr = ExAllocatePoolWithTag(NonPagedPool, AllocSize, TAG_POOLTEST);
86 ok(Ptr == NULL, "Allocating 2Gb of nonpaged pool should fail\n");
87
88 Ptr = ExAllocatePoolWithTag(PagedPool, AllocSize, TAG_POOLTEST);
89 ok(Ptr == NULL, "Allocating 2Gb of paged pool should fail\n");*/
90
91 // now test allocating lots of small/medium blocks
92 AllocNumber = 100000;
93 Allocs = ExAllocatePoolWithTag(PagedPool, sizeof(*Allocs) * AllocNumber, TAG_POOLTEST);
94
95 // alloc blocks
96 for (i=0; i<AllocNumber; i++)
97 {
98 AllocSize = 42;
99 Allocs[i] = ExAllocatePoolWithTag(NonPagedPool, AllocSize, TAG_POOLTEST);
100 }
101
102 // now free them
103 for (i=0; i<AllocNumber; i++)
104 {
105 ExFreePoolWithTag(Allocs[i], TAG_POOLTEST);
106 }
107
108
109 ExFreePoolWithTag(Allocs, TAG_POOLTEST);
110 }
111
112 static VOID PoolsCorruption(VOID)
113 {
114 PULONG Ptr;
115 ULONG AllocSize;
116
117 // start with non-paged pool
118 AllocSize = 4096 + 0x10;
119 Ptr = ExAllocatePoolWithTag(NonPagedPool, AllocSize, TAG_POOLTEST);
120
121 // touch all bytes, it shouldn't cause an exception
122 RtlZeroMemory(Ptr, AllocSize);
123
124 /* TODO: These fail because accessing invalid memory doesn't necessarily
125 cause an access violation */
126 #ifdef THIS_DOESNT_WORK
127 // test buffer overrun, right after our allocation ends
128 _SEH2_TRY
129 {
130 TestPtr = (PULONG)((PUCHAR)Ptr + AllocSize);
131 //Ptr[4] = 0xd33dbeef;
132 *TestPtr = 0xd33dbeef;
133 }
134 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
135 {
136 /* Get the status */
137 Status = _SEH2_GetExceptionCode();
138 } _SEH2_END;
139
140 ok(Status == STATUS_ACCESS_VIOLATION, "Exception should occur, but got Status 0x%08lX\n", Status);
141
142 // test overrun in a distant byte range, but within 4096KB
143 _SEH2_TRY
144 {
145 Ptr[2020] = 0xdeadb33f;
146 }
147 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
148 {
149 /* Get the status */
150 Status = _SEH2_GetExceptionCode();
151 } _SEH2_END;
152
153 ok(Status == STATUS_ACCESS_VIOLATION, "Exception should occur, but got Status 0x%08lX\n", Status);
154 #endif
155
156 // free the pool
157 ExFreePoolWithTag(Ptr, TAG_POOLTEST);
158 }
159
160 static
161 VOID
162 TestPoolTags(VOID)
163 {
164 PVOID Memory;
165
166 Memory = ExAllocatePoolWithTag(PagedPool, 8, 'MyTa');
167 ok_eq_tag(KmtGetPoolTag(Memory), 'MyTa');
168 ExFreePoolWithTag(Memory, 'MyTa');
169
170 Memory = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, 'MyTa');
171 ok_eq_tag(KmtGetPoolTag(Memory), 'TooL');
172 ExFreePoolWithTag(Memory, 'MyTa');
173
174 Memory = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE - 3 * sizeof(PVOID), 'MyTa');
175 ok_eq_tag(KmtGetPoolTag(Memory), 'TooL');
176 ExFreePoolWithTag(Memory, 'MyTa');
177
178 Memory = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE - 4 * sizeof(PVOID) + 1, 'MyTa');
179 ok_eq_tag(KmtGetPoolTag(Memory), 'TooL');
180 ExFreePoolWithTag(Memory, 'MyTa');
181
182 Memory = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE - 4 * sizeof(PVOID), 'MyTa');
183 ok_eq_tag(KmtGetPoolTag(Memory), 'MyTa');
184 ExFreePoolWithTag(Memory, 'MyTa');
185 }
186
187 static
188 VOID
189 TestPoolQuota(VOID)
190 {
191 PEPROCESS Process = PsGetCurrentProcess();
192 PEPROCESS StoredProcess;
193 PVOID Memory;
194 LONG InitialRefCount;
195 LONG RefCount;
196 USHORT PoolType;
197
198 InitialRefCount = GetRefCount(Process);
199
200 /* We get some memory from this function, and it's properly aligned.
201 * Also, it takes a reference to the process, and releases it on free */
202 Memory = ExAllocatePoolWithQuotaTag(PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
203 sizeof(LIST_ENTRY),
204 'tQmK');
205 ok(Memory != NULL, "ExAllocatePoolWithQuotaTag returned NULL\n");
206 if (!skip(Memory != NULL, "No memory\n"))
207 {
208 ok((ULONG_PTR)Memory % sizeof(LIST_ENTRY) == 0,
209 "Allocation %p is badly aligned\n",
210 Memory);
211 RefCount = GetRefCount(Process);
212 ok_eq_long(RefCount, InitialRefCount + 1);
213
214 /* A pointer to the process is found right before the next pool header */
215 StoredProcess = ((PVOID *)((ULONG_PTR)Memory + 2 * sizeof(LIST_ENTRY)))[-1];
216 ok_eq_pointer(StoredProcess, Process);
217
218 /* Pool type should have QUOTA_POOL_MASK set */
219 PoolType = KmtGetPoolType(Memory);
220 ok(PoolType != 0, "PoolType is 0\n");
221 PoolType--;
222 ok(PoolType & QUOTA_POOL_MASK, "PoolType = %x\n", PoolType);
223 ok((PoolType & BASE_POOL_TYPE_MASK) == PagedPool, "PoolType = %x\n", PoolType);
224
225 ExFreePoolWithTag(Memory, 'tQmK');
226 RefCount = GetRefCount(Process);
227 ok_eq_long(RefCount, InitialRefCount);
228 }
229
230 /* Large allocations are page-aligned, don't reference the process */
231 Memory = ExAllocatePoolWithQuotaTag(PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
232 PAGE_SIZE,
233 'tQmK');
234 ok(Memory != NULL, "ExAllocatePoolWithQuotaTag returned NULL\n");
235 if (!skip(Memory != NULL, "No memory\n"))
236 {
237 ok((ULONG_PTR)Memory % PAGE_SIZE == 0,
238 "Allocation %p is badly aligned\n",
239 Memory);
240 RefCount = GetRefCount(Process);
241 ok_eq_long(RefCount, InitialRefCount);
242 ExFreePoolWithTag(Memory, 'tQmK');
243 RefCount = GetRefCount(Process);
244 ok_eq_long(RefCount, InitialRefCount);
245 }
246
247 /* Function raises by default */
248 KmtStartSeh()
249 Memory = ExAllocatePoolWithQuotaTag(PagedPool,
250 0x7FFFFFFF,
251 'tQmK');
252 if (Memory)
253 ExFreePoolWithTag(Memory, 'tQmK');
254 KmtEndSeh(STATUS_INSUFFICIENT_RESOURCES);
255
256 /* Function returns NULL with POOL_QUOTA_FAIL_INSTEAD_OF_RAISE */
257 KmtStartSeh()
258 Memory = ExAllocatePoolWithQuotaTag(PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
259 0x7FFFFFFF,
260 'tQmK');
261 ok(Memory == NULL, "Successfully got 2GB block: %p\n", Memory);
262 if (Memory)
263 ExFreePoolWithTag(Memory, 'tQmK');
264 KmtEndSeh(STATUS_SUCCESS);
265 }
266
267 static
268 VOID
269 TestBigPoolExpansion(VOID)
270 {
271 POOL_TYPE PoolType;
272 PVOID *BigAllocations;
273 const ULONG MaxAllocations = 1024 * 128;
274 ULONG NumAllocations;
275
276 for (PoolType = NonPagedPool; PoolType <= PagedPool; PoolType++)
277 {
278 BigAllocations = ExAllocatePoolWithTag(PoolType,
279 MaxAllocations * sizeof(*BigAllocations),
280 'ABmK');
281
282 /* Allocate a lot of pages (== big pool allocations) */
283 for (NumAllocations = 0; NumAllocations < MaxAllocations; NumAllocations++)
284 {
285 BigAllocations[NumAllocations] = ExAllocatePoolWithTag(PoolType,
286 PAGE_SIZE,
287 'aPmK');
288 if (BigAllocations[NumAllocations] == NULL)
289 {
290 NumAllocations--;
291 break;
292 }
293 }
294
295 trace("Got %lu allocations for PoolType %d\n", NumAllocations, PoolType);
296
297 /* Free them */
298 for (; NumAllocations < MaxAllocations; NumAllocations--)
299 {
300 ASSERT(BigAllocations[NumAllocations] != NULL);
301 ExFreePoolWithTag(BigAllocations[NumAllocations],
302 'aPmK');
303 }
304 ExFreePoolWithTag(BigAllocations, 'ABmK');
305 }
306 }
307
308 START_TEST(ExPools)
309 {
310 PoolsTest();
311 PoolsCorruption();
312 TestPoolTags();
313 TestPoolQuota();
314 TestBigPoolExpansion();
315 }