1 /* 2 * PROJECT: ReactOS API tests 3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory 4 * PURPOSE: Tests for the NtQueryInformationProcess API 5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org> 6 * George Bișoc <george.bisoc@reactos.org> 7 */ 8 9 #include "precomp.h" 10 #include <internal/ps_i.h> 11 12 static LARGE_INTEGER TestStartTime; 13 14 static 15 void 16 Test_ProcessTimes(void) 17 { 18 #define SPIN_TIME 1000000 19 NTSTATUS Status; 20 KERNEL_USER_TIMES Times1; 21 KERNEL_USER_TIMES Times2; 22 ULONG Length; 23 LARGE_INTEGER Time1, Time2; 24 25 /* Everything is NULL */ 26 Status = NtQueryInformationProcess(NULL, 27 ProcessTimes, 28 NULL, 29 0, 30 NULL); 31 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 32 33 /* Right size, invalid process */ 34 Status = NtQueryInformationProcess(NULL, 35 ProcessTimes, 36 NULL, 37 sizeof(KERNEL_USER_TIMES), 38 NULL); 39 ok_hex(Status, STATUS_INVALID_HANDLE); 40 41 /* Valid process, no buffer */ 42 Status = NtQueryInformationProcess(NtCurrentProcess(), 43 ProcessTimes, 44 NULL, 45 0, 46 NULL); 47 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 48 49 /* Unaligned buffer, wrong size */ 50 Status = NtQueryInformationProcess(NtCurrentProcess(), 51 ProcessTimes, 52 (PVOID)2, 53 0, 54 NULL); 55 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 56 57 /* Unaligned buffer, correct size */ 58 Status = NtQueryInformationProcess(NtCurrentProcess(), 59 ProcessTimes, 60 (PVOID)2, 61 sizeof(KERNEL_USER_TIMES), 62 NULL); 63 ok_hex(Status, STATUS_DATATYPE_MISALIGNMENT); 64 65 /* Buffer too small */ 66 Status = NtQueryInformationProcess(NtCurrentProcess(), 67 ProcessTimes, 68 NULL, 69 sizeof(KERNEL_USER_TIMES) - 1, 70 NULL); 71 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 72 73 /* Right buffer size but NULL pointer */ 74 Status = NtQueryInformationProcess(NtCurrentProcess(), 75 ProcessTimes, 76 NULL, 77 sizeof(KERNEL_USER_TIMES), 78 NULL); 79 ok_hex(Status, STATUS_ACCESS_VIOLATION); 80 81 /* Buffer too large */ 82 Status = NtQueryInformationProcess(NtCurrentProcess(), 83 ProcessTimes, 84 NULL, 85 sizeof(KERNEL_USER_TIMES) + 1, 86 NULL); 87 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 88 89 /* Buffer too small, ask for length */ 90 Length = 0x55555555; 91 Status = NtQueryInformationProcess(NtCurrentProcess(), 92 ProcessTimes, 93 NULL, 94 sizeof(KERNEL_USER_TIMES) - 1, 95 &Length); 96 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 97 ok_dec(Length, 0x55555555); 98 99 Status = NtQuerySystemTime(&Time1); 100 ok_hex(Status, STATUS_SUCCESS); 101 102 /* Do some busy waiting to increase UserTime */ 103 do 104 { 105 Status = NtQuerySystemTime(&Time2); 106 if (!NT_SUCCESS(Status)) 107 { 108 ok(0, "NtQuerySystemTime failed with %lx\n", Status); 109 break; 110 } 111 } while (Time2.QuadPart - Time1.QuadPart < SPIN_TIME); 112 113 /* Valid parameters, no return length */ 114 Status = NtQuerySystemTime(&Time1); 115 ok_hex(Status, STATUS_SUCCESS); 116 117 RtlFillMemory(&Times1, sizeof(Times1), 0x55); 118 Status = NtQueryInformationProcess(NtCurrentProcess(), 119 ProcessTimes, 120 &Times1, 121 sizeof(KERNEL_USER_TIMES), 122 NULL); 123 ok_hex(Status, STATUS_SUCCESS); 124 ok(Times1.CreateTime.QuadPart < TestStartTime.QuadPart, 125 "CreateTime is %I64u, expected < %I64u\n", Times1.CreateTime.QuadPart, TestStartTime.QuadPart); 126 ok(Times1.CreateTime.QuadPart > TestStartTime.QuadPart - 100000000LL, 127 "CreateTime is %I64u, expected > %I64u\n", Times1.CreateTime.QuadPart, TestStartTime.QuadPart - 100000000LL); 128 ok(Times1.ExitTime.QuadPart == 0, 129 "ExitTime is %I64u, expected 0\n", Times1.ExitTime.QuadPart); 130 ok(Times1.KernelTime.QuadPart != 0, "KernelTime is 0\n"); 131 ros_skip_flaky 132 ok(Times1.UserTime.QuadPart != 0, "UserTime is 0\n"); 133 134 /* Do some busy waiting to increase UserTime */ 135 do 136 { 137 Status = NtQuerySystemTime(&Time2); 138 if (!NT_SUCCESS(Status)) 139 { 140 ok(0, "NtQuerySystemTime failed with %lx\n", Status); 141 break; 142 } 143 } while (Time2.QuadPart - Time1.QuadPart < SPIN_TIME); 144 145 /* Again, this time with a return length */ 146 Length = 0x55555555; 147 RtlFillMemory(&Times2, sizeof(Times2), 0x55); 148 Status = NtQueryInformationProcess(NtCurrentProcess(), 149 ProcessTimes, 150 &Times2, 151 sizeof(KERNEL_USER_TIMES), 152 &Length); 153 ok_hex(Status, STATUS_SUCCESS); 154 ok_dec(Length, sizeof(KERNEL_USER_TIMES)); 155 ok(Times1.CreateTime.QuadPart == Times2.CreateTime.QuadPart, 156 "CreateTimes not equal: %I64u != %I64u\n", Times1.CreateTime.QuadPart, Times2.CreateTime.QuadPart); 157 ok(Times2.ExitTime.QuadPart == 0, 158 "ExitTime is %I64u, expected 0\n", Times2.ExitTime.QuadPart); 159 ok(Times2.KernelTime.QuadPart != 0, "KernelTime is 0\n"); 160 ok(Times2.UserTime.QuadPart != 0, "UserTime is 0\n"); 161 162 /* Compare the two sets of KernelTime/UserTime values */ 163 Status = NtQuerySystemTime(&Time2); 164 ok_hex(Status, STATUS_SUCCESS); 165 /* Time values must have increased */ 166 ok(Times2.KernelTime.QuadPart > Times1.KernelTime.QuadPart, 167 "KernelTime values inconsistent. Expected %I64u > %I64u\n", Times2.KernelTime.QuadPart, Times1.KernelTime.QuadPart); 168 ros_skip_flaky 169 ok(Times2.UserTime.QuadPart > Times1.UserTime.QuadPart, 170 "UserTime values inconsistent. Expected %I64u > %I64u\n", Times2.UserTime.QuadPart, Times1.UserTime.QuadPart); 171 /* They can't have increased by more than wall clock time difference (we only have one thread) */ 172 ros_skip_flaky 173 ok(Times2.KernelTime.QuadPart - Times1.KernelTime.QuadPart < Time2.QuadPart - Time1.QuadPart, 174 "KernelTime values inconsistent. Expected %I64u - %I64u < %I64u\n", 175 Times2.KernelTime.QuadPart, Times1.KernelTime.QuadPart, Time2.QuadPart - Time1.QuadPart); 176 ok(Times2.UserTime.QuadPart - Times1.UserTime.QuadPart < Time2.QuadPart - Time1.QuadPart, 177 "UserTime values inconsistent. Expected %I64u - %I64u < %I64u\n", 178 Times2.UserTime.QuadPart, Times1.UserTime.QuadPart, Time2.QuadPart - Time1.QuadPart); 179 180 trace("KernelTime1 = %I64u\n", Times1.KernelTime.QuadPart); 181 trace("KernelTime2 = %I64u\n", Times2.KernelTime.QuadPart); 182 trace("UserTime1 = %I64u\n", Times1.UserTime.QuadPart); 183 trace("UserTime2 = %I64u\n", Times2.UserTime.QuadPart); 184 185 /* TODO: Test ExitTime on a terminated process */ 186 #undef SPIN_TIME 187 } 188 189 static 190 void 191 Test_ProcessBasicInformation(void) 192 { 193 NTSTATUS Status; 194 ULONG Length; 195 PROCESS_BASIC_INFORMATION BasicInfo; 196 197 /* Everything is NULL */ 198 Status = NtQueryInformationProcess(NULL, 199 ProcessBasicInformation, 200 NULL, 201 0, 202 NULL); 203 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 204 205 /* Right size, invalid process handle */ 206 Status = NtQueryInformationProcess(NULL, 207 ProcessBasicInformation, 208 NULL, 209 sizeof(BasicInfo), 210 NULL); 211 ok_hex(Status, STATUS_INVALID_HANDLE); 212 213 /* Valid process handle, no buffer */ 214 Status = NtQueryInformationProcess(NtCurrentProcess(), 215 ProcessBasicInformation, 216 NULL, 217 0, 218 NULL); 219 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 220 221 /* Unaligned buffer, wrong size */ 222 Status = NtQueryInformationProcess(NtCurrentProcess(), 223 ProcessBasicInformation, 224 (PVOID)2, 225 0, 226 NULL); 227 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 228 229 /* Unaligned buffer, correct size */ 230 Status = NtQueryInformationProcess(NtCurrentProcess(), 231 ProcessBasicInformation, 232 (PVOID)2, 233 sizeof(BasicInfo), 234 NULL); 235 ok_hex(Status, STATUS_DATATYPE_MISALIGNMENT); 236 237 /* Buffer too small */ 238 Status = NtQueryInformationProcess(NtCurrentProcess(), 239 ProcessBasicInformation, 240 NULL, 241 sizeof(BasicInfo) - 1, 242 NULL); 243 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 244 245 /* Right buffer size but NULL pointer */ 246 Status = NtQueryInformationProcess(NtCurrentProcess(), 247 ProcessBasicInformation, 248 NULL, 249 sizeof(BasicInfo), 250 NULL); 251 ok_hex(Status, STATUS_ACCESS_VIOLATION); 252 253 /* Buffer too large */ 254 Status = NtQueryInformationProcess(NtCurrentProcess(), 255 ProcessBasicInformation, 256 NULL, 257 sizeof(BasicInfo) + 1, 258 NULL); 259 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 260 261 /* Buffer too small, ask for length */ 262 Length = 0x55555555; 263 Status = NtQueryInformationProcess(NtCurrentProcess(), 264 ProcessBasicInformation, 265 NULL, 266 sizeof(BasicInfo) - 1, 267 &Length); 268 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 269 ok_dec(Length, 0x55555555); 270 271 /* Valid parameters, no return length */ 272 RtlFillMemory(&BasicInfo, sizeof(BasicInfo), 0x55); 273 Status = NtQueryInformationProcess(NtCurrentProcess(), 274 ProcessBasicInformation, 275 &BasicInfo, 276 sizeof(BasicInfo), 277 NULL); 278 ok_hex(Status, STATUS_SUCCESS); 279 280 /* Trace the returned data (1) */ 281 trace("[1] BasicInfo.ExitStatus = %lx\n", BasicInfo.ExitStatus); 282 trace("[1] BasicInfo.PebBaseAddress = %p\n", BasicInfo.PebBaseAddress); 283 trace("[1] BasicInfo.AffinityMask = %Ix\n", BasicInfo.AffinityMask); 284 trace("[1] BasicInfo.BasePriority = %ld\n", BasicInfo.BasePriority); 285 trace("[1] BasicInfo.UniqueProcessId = %Iu\n", BasicInfo.UniqueProcessId); 286 trace("[1] BasicInfo.InheritedFromUniqueProcessId = %Iu\n", BasicInfo.InheritedFromUniqueProcessId); 287 288 /* Again, this time with a return length */ 289 Length = 0x55555555; 290 RtlFillMemory(&BasicInfo, sizeof(BasicInfo), 0x55); 291 Status = NtQueryInformationProcess(NtCurrentProcess(), 292 ProcessBasicInformation, 293 &BasicInfo, 294 sizeof(BasicInfo), 295 &Length); 296 ok_hex(Status, STATUS_SUCCESS); 297 ok_dec(Length, sizeof(BasicInfo)); 298 299 /* Trace the returned data (2) */ 300 trace("[2] BasicInfo.ExitStatus = %lx\n", BasicInfo.ExitStatus); 301 trace("[2] BasicInfo.PebBaseAddress = %p\n", BasicInfo.PebBaseAddress); 302 trace("[2] BasicInfo.AffinityMask = %Ix\n", BasicInfo.AffinityMask); 303 trace("[2] BasicInfo.BasePriority = %ld\n", BasicInfo.BasePriority); 304 trace("[2] BasicInfo.UniqueProcessId = %Iu\n", BasicInfo.UniqueProcessId); 305 trace("[2] BasicInfo.InheritedFromUniqueProcessId = %Iu\n", BasicInfo.InheritedFromUniqueProcessId); 306 } 307 308 static 309 void 310 Test_ProcessPriorityClassAlignment(void) 311 { 312 NTSTATUS Status; 313 PPROCESS_PRIORITY_CLASS ProcPriority; 314 315 /* Allocate some memory for the priority class structure */ 316 ProcPriority = malloc(sizeof(PROCESS_PRIORITY_CLASS)); 317 if (ProcPriority == NULL) 318 { 319 skip("Failed to allocate memory for PROCESS_PRIORITY_CLASS!\n"); 320 return; 321 } 322 323 /* 324 * Initialize the PriorityClass member to ensure the test won't randomly succeed (if such data is uninitialized). 325 * Filling 85 to the data member makes sure that if the test fails continously then NtQueryInformationProcess() 326 * didn't initialize the structure with data. 327 */ 328 RtlFillMemory(&ProcPriority->PriorityClass, sizeof(ProcPriority->PriorityClass), 0x55); 329 330 /* Unaligned buffer -- wrong size */ 331 Status = NtQueryInformationProcess(NtCurrentProcess(), 332 ProcessPriorityClass, 333 (PVOID)1, 334 0, 335 NULL); 336 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 337 338 /* Unaligned buffer -- correct size */ 339 Status = NtQueryInformationProcess(NtCurrentProcess(), 340 ProcessPriorityClass, 341 (PVOID)1, 342 sizeof(PROCESS_PRIORITY_CLASS), 343 NULL); 344 ok_hex(Status, STATUS_DATATYPE_MISALIGNMENT); 345 346 /* Unaligned buffer -- wrong size (but this time do with an alignment of 2) */ 347 Status = NtQueryInformationProcess(NtCurrentProcess(), 348 ProcessPriorityClass, 349 (PVOID)2, 350 0, 351 NULL); 352 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 353 354 /* Unaligned buffer -- correct size (but this time do with an alignment of 2) */ 355 Status = NtQueryInformationProcess(NtCurrentProcess(), 356 ProcessPriorityClass, 357 (PVOID)2, 358 sizeof(PROCESS_PRIORITY_CLASS), 359 NULL); 360 ok_hex(Status, STATUS_DATATYPE_MISALIGNMENT); 361 362 /* Do not care for the length but expect to return the priority class */ 363 Status = NtQueryInformationProcess(NtCurrentProcess(), 364 ProcessPriorityClass, 365 ProcPriority, 366 sizeof(PROCESS_PRIORITY_CLASS), 367 NULL); 368 ok_hex(Status, STATUS_SUCCESS); 369 370 /* Make sure the returned priority class is a valid number (non negative) but also it should be within the PROCESS_PRIORITY_CLASS range */ 371 ok(ProcPriority->PriorityClass > PROCESS_PRIORITY_CLASS_INVALID && ProcPriority->PriorityClass <= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL, 372 "Expected a valid number from priority class range but got %d\n", ProcPriority->PriorityClass); 373 free(ProcPriority); 374 } 375 376 static 377 void 378 Test_ProcessWx86Information(void) 379 { 380 NTSTATUS Status; 381 ULONG VdmPower = 1, ReturnLength; 382 383 /* Everything is NULL */ 384 Status = NtQueryInformationProcess(NULL, 385 ProcessWx86Information, 386 NULL, 387 0, 388 NULL); 389 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 390 391 /* Given an invalid process handle */ 392 Status = NtQueryInformationProcess(NULL, 393 ProcessWx86Information, 394 &VdmPower, 395 sizeof(VdmPower), 396 NULL); 397 ok_hex(Status, STATUS_INVALID_HANDLE); 398 399 /* Don't query anything */ 400 Status = NtQueryInformationProcess(NtCurrentProcess(), 401 ProcessWx86Information, 402 NULL, 403 sizeof(VdmPower), 404 NULL); 405 ok_hex(Status, STATUS_ACCESS_VIOLATION); 406 407 /* The buffer is misaligned and information length is wrong */ 408 Status = NtQueryInformationProcess(NtCurrentProcess(), 409 ProcessWx86Information, 410 (PVOID)1, 411 0, 412 NULL); 413 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 414 415 /* The buffer is misaligned */ 416 Status = NtQueryInformationProcess(NtCurrentProcess(), 417 ProcessWx86Information, 418 (PVOID)1, 419 sizeof(VdmPower), 420 NULL); 421 ok_hex(Status, STATUS_DATATYPE_MISALIGNMENT); 422 423 /* The buffer is misaligned -- try with an alignment size of 2 */ 424 Status = NtQueryInformationProcess(NtCurrentProcess(), 425 ProcessWx86Information, 426 (PVOID)2, 427 sizeof(VdmPower), 428 NULL); 429 ok_hex(Status, STATUS_DATATYPE_MISALIGNMENT); 430 431 /* Query the VDM power */ 432 Status = NtQueryInformationProcess(NtCurrentProcess(), 433 ProcessWx86Information, 434 &VdmPower, 435 sizeof(VdmPower), 436 NULL); 437 ok_hex(Status, STATUS_SUCCESS); 438 ok(VdmPower == 0 || VdmPower == 1, "The VDM power value must be within the boundary between 0 and 1, not anything else! Got %lu\n", VdmPower); 439 440 /* Same but with ReturnLength */ 441 Status = NtQueryInformationProcess(NtCurrentProcess(), 442 ProcessWx86Information, 443 &VdmPower, 444 sizeof(VdmPower), 445 &ReturnLength); 446 ok_hex(Status, STATUS_SUCCESS); 447 ok(ReturnLength != 0, "ReturnLength shouldn't be 0!\n"); 448 ok(VdmPower == 0 || VdmPower == 1, "The VDM power value must be within the boundary between 0 and 1, not anything else! Got %lu\n", VdmPower); 449 450 /* Trace the VDM power value and returned length */ 451 trace("ReturnLength = %lu\n", ReturnLength); 452 trace("VdmPower = %lu\n", VdmPower); 453 } 454 455 static 456 void 457 Test_ProcQueryAlignmentProbe(void) 458 { 459 ULONG InfoClass; 460 461 /* Iterate over the process info classes and begin the tests */ 462 for (InfoClass = 0; InfoClass < _countof(PsProcessInfoClass); InfoClass++) 463 { 464 /* The buffer is misaligned */ 465 QuerySetProcessValidator(QUERY, 466 InfoClass, 467 (PVOID)(ULONG_PTR)1, 468 PsProcessInfoClass[InfoClass].RequiredSizeQUERY, 469 STATUS_DATATYPE_MISALIGNMENT); 470 471 /* We query an invalid buffer address */ 472 QuerySetProcessValidator(QUERY, 473 InfoClass, 474 (PVOID)(ULONG_PTR)PsProcessInfoClass[InfoClass].AlignmentQUERY, 475 PsProcessInfoClass[InfoClass].RequiredSizeQUERY, 476 STATUS_ACCESS_VIOLATION); 477 478 /* The information length is wrong */ 479 QuerySetProcessValidator(QUERY, 480 InfoClass, 481 (PVOID)(ULONG_PTR)PsProcessInfoClass[InfoClass].AlignmentQUERY, 482 PsProcessInfoClass[InfoClass].RequiredSizeQUERY - 1, 483 STATUS_INFO_LENGTH_MISMATCH); 484 } 485 } 486 487 START_TEST(NtQueryInformationProcess) 488 { 489 NTSTATUS Status; 490 491 /* Make sure that some time has passed since process creation, even if the resolution of our NtQuerySystemTime is low. */ 492 Sleep(1); 493 494 Status = NtQuerySystemTime(&TestStartTime); 495 ok_hex(Status, STATUS_SUCCESS); 496 497 Test_ProcessTimes(); 498 Test_ProcessBasicInformation(); 499 Test_ProcessPriorityClassAlignment(); 500 Test_ProcessWx86Information(); 501 Test_ProcQueryAlignmentProbe(); 502 } 503