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 } 316