[KMTESTS:EX]
[reactos.git] / 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 static
14 LONG
15 GetRefCount(
16 _In_ PVOID Object)
17 {
18 POBJECT_HEADER Header = OBJECT_TO_OBJECT_HEADER(Object);
19 return Header->PointerCount;
20 }
21
22 #define TAG_POOLTEST 'tstP'
23
24 static VOID PoolsTest(VOID)
25 {
26 PVOID Ptr;
27 ULONG AllocSize, i, AllocNumber;
28 PVOID *Allocs;
29
30 // Stress-test nonpaged pool
31 for (i=1; i<10000; i++)
32 {
33 // make up some increasing, a bit irregular size
34 AllocSize = i*10;
35
36 if (i % 10)
37 AllocSize++;
38
39 if (i % 25)
40 AllocSize += 13;
41
42 // start with non-paged pool
43 Ptr = ExAllocatePoolWithTag(NonPagedPool, AllocSize, TAG_POOLTEST);
44
45 // it may fail due to no-memory condition
46 if (!Ptr) break;
47
48 // try to fully fill it
49 RtlFillMemory(Ptr, AllocSize, 0xAB);
50
51 // free it
52 ExFreePoolWithTag(Ptr, TAG_POOLTEST);
53 }
54
55 // now paged one
56 for (i=1; i<10000; i++)
57 {
58 // make up some increasing, a bit irregular size
59 AllocSize = i*50;
60
61 if (i % 10)
62 AllocSize++;
63
64 if (i % 25)
65 AllocSize += 13;
66
67 // start with non-paged pool
68 Ptr = ExAllocatePoolWithTag(PagedPool, AllocSize, TAG_POOLTEST);
69
70 // it may fail due to no-memory condition
71 if (!Ptr) break;
72
73 // try to fully fill it
74 RtlFillMemory(Ptr, AllocSize, 0xAB);
75
76 // free it
77 ExFreePoolWithTag(Ptr, TAG_POOLTEST);
78 }
79
80 // test super-big allocations
81 /*AllocSize = 2UL * 1024 * 1024 * 1024;
82 Ptr = ExAllocatePoolWithTag(NonPagedPool, AllocSize, TAG_POOLTEST);
83 ok(Ptr == NULL, "Allocating 2Gb of nonpaged pool should fail\n");
84
85 Ptr = ExAllocatePoolWithTag(PagedPool, AllocSize, TAG_POOLTEST);
86 ok(Ptr == NULL, "Allocating 2Gb of paged pool should fail\n");*/
87
88 // now test allocating lots of small/medium blocks
89 AllocNumber = 100000;
90 Allocs = ExAllocatePoolWithTag(PagedPool, sizeof(Allocs) * AllocNumber, TAG_POOLTEST);
91
92 // alloc blocks
93 for (i=0; i<AllocNumber; i++)
94 {
95 AllocSize = 42;
96 Allocs[i] = ExAllocatePoolWithTag(NonPagedPool, AllocSize, TAG_POOLTEST);
97 }
98
99 // now free them
100 for (i=0; i<AllocNumber; i++)
101 {
102 ExFreePoolWithTag(Allocs[i], TAG_POOLTEST);
103 }
104
105
106 ExFreePoolWithTag(Allocs, TAG_POOLTEST);
107 }
108
109 static VOID PoolsCorruption(VOID)
110 {
111 PULONG Ptr;
112 ULONG AllocSize;
113
114 // start with non-paged pool
115 AllocSize = 4096 + 0x10;
116 Ptr = ExAllocatePoolWithTag(NonPagedPool, AllocSize, TAG_POOLTEST);
117
118 // touch all bytes, it shouldn't cause an exception
119 RtlZeroMemory(Ptr, AllocSize);
120
121 /* TODO: These fail because accessing invalid memory doesn't necessarily
122 cause an access violation */
123 #ifdef THIS_DOESNT_WORK
124 // test buffer overrun, right after our allocation ends
125 _SEH2_TRY
126 {
127 TestPtr = (PULONG)((PUCHAR)Ptr + AllocSize);
128 //Ptr[4] = 0xd33dbeef;
129 *TestPtr = 0xd33dbeef;
130 }
131 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
132 {
133 /* Get the status */
134 Status = _SEH2_GetExceptionCode();
135 } _SEH2_END;
136
137 ok(Status == STATUS_ACCESS_VIOLATION, "Exception should occur, but got Status 0x%08lX\n", Status);
138
139 // test overrun in a distant byte range, but within 4096KB
140 _SEH2_TRY
141 {
142 Ptr[2020] = 0xdeadb33f;
143 }
144 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
145 {
146 /* Get the status */
147 Status = _SEH2_GetExceptionCode();
148 } _SEH2_END;
149
150 ok(Status == STATUS_ACCESS_VIOLATION, "Exception should occur, but got Status 0x%08lX\n", Status);
151 #endif
152
153 // free the pool
154 ExFreePoolWithTag(Ptr, TAG_POOLTEST);
155 }
156
157 static
158 VOID
159 TestPoolTags(VOID)
160 {
161 PVOID Memory;
162
163 Memory = ExAllocatePoolWithTag(PagedPool, 8, 'MyTa');
164 ok_eq_tag(KmtGetPoolTag(Memory), 'MyTa');
165 ExFreePoolWithTag(Memory, 'MyTa');
166
167 Memory = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, 'MyTa');
168 ok_eq_tag(KmtGetPoolTag(Memory), 'TooL');
169 ExFreePoolWithTag(Memory, 'MyTa');
170
171 Memory = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE - 3 * sizeof(PVOID), 'MyTa');
172 ok_eq_tag(KmtGetPoolTag(Memory), 'TooL');
173 ExFreePoolWithTag(Memory, 'MyTa');
174
175 Memory = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE - 4 * sizeof(PVOID) + 1, 'MyTa');
176 ok_eq_tag(KmtGetPoolTag(Memory), 'TooL');
177 ExFreePoolWithTag(Memory, 'MyTa');
178
179 Memory = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE - 4 * sizeof(PVOID), 'MyTa');
180 ok_eq_tag(KmtGetPoolTag(Memory), 'MyTa');
181 ExFreePoolWithTag(Memory, 'MyTa');
182 }
183
184 static
185 VOID
186 TestPoolQuota(VOID)
187 {
188 PEPROCESS Process = PsGetCurrentProcess();
189 PEPROCESS StoredProcess;
190 PVOID Memory;
191 LONG InitialRefCount;
192 LONG RefCount;
193 NTSTATUS ExceptionStatus;
194
195 InitialRefCount = GetRefCount(Process);
196
197 /* We get some memory from this function, and it's properly aligned.
198 * Also, it takes a reference to the process, and releases it on free */
199 Memory = ExAllocatePoolWithQuotaTag(PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
200 sizeof(LIST_ENTRY),
201 'tQmK');
202 ok(Memory != NULL, "ExAllocatePoolWithQuotaTag returned NULL\n");
203 if (!skip(Memory != NULL, "No memory\n"))
204 {
205 ok((ULONG_PTR)Memory % sizeof(LIST_ENTRY) == 0,
206 "Allocation %p is badly aligned\n",
207 Memory);
208 RefCount = GetRefCount(Process);
209 ok_eq_long(RefCount, InitialRefCount + 1);
210
211 /* A pointer to the process is found right before the next pool header */
212 StoredProcess = ((PVOID *)((ULONG_PTR)Memory + 2 * sizeof(LIST_ENTRY)))[-1];
213 ok_eq_pointer(StoredProcess, Process);
214
215 ExFreePoolWithTag(Memory, 'tQmK');
216 RefCount = GetRefCount(Process);
217 ok_eq_long(RefCount, InitialRefCount);
218 }
219
220 /* Large allocations are page-aligned, don't reference the process */
221 Memory = ExAllocatePoolWithQuotaTag(PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
222 PAGE_SIZE,
223 'tQmK');
224 ok(Memory != NULL, "ExAllocatePoolWithQuotaTag returned NULL\n");
225 if (!skip(Memory != NULL, "No memory\n"))
226 {
227 ok((ULONG_PTR)Memory % PAGE_SIZE == 0,
228 "Allocation %p is badly aligned\n",
229 Memory);
230 RefCount = GetRefCount(Process);
231 ok_eq_long(RefCount, InitialRefCount);
232 ExFreePoolWithTag(Memory, 'tQmK');
233 RefCount = GetRefCount(Process);
234 ok_eq_long(RefCount, InitialRefCount);
235 }
236
237 /* Function raises by default */
238 KmtStartSeh()
239 Memory = ExAllocatePoolWithQuotaTag(PagedPool,
240 0x7FFFFFFF,
241 'tQmK');
242 if (Memory)
243 ExFreePoolWithTag(Memory, 'tQmK');
244 KmtEndSeh(STATUS_INSUFFICIENT_RESOURCES);
245
246 /* Function returns NULL with POOL_QUOTA_FAIL_INSTEAD_OF_RAISE */
247 KmtStartSeh()
248 Memory = ExAllocatePoolWithQuotaTag(PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
249 0x7FFFFFFF,
250 'tQmK');
251 ok(Memory == NULL, "Successfully got 2GB block: %p\n", Memory);
252 if (Memory)
253 ExFreePoolWithTag(Memory, 'tQmK');
254 KmtEndSeh(STATUS_SUCCESS);
255 }
256
257 START_TEST(ExPools)
258 {
259 PoolsTest();
260 PoolsCorruption();
261 TestPoolTags();
262 TestPoolQuota();
263 }