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_ProcessPriorityClassAlignment(void) 192 { 193 NTSTATUS Status; 194 PPROCESS_PRIORITY_CLASS ProcPriority; 195 196 /* Allocate some memory for the priority class structure */ 197 ProcPriority = malloc(sizeof(PROCESS_PRIORITY_CLASS)); 198 if (ProcPriority == NULL) 199 { 200 skip("Failed to allocate memory for PROCESS_PRIORITY_CLASS!\n"); 201 return; 202 } 203 204 /* 205 * Initialize the PriorityClass member to ensure the test won't randomly succeed (if such data is uninitialized). 206 * Filling 85 to the data member makes sure that if the test fails continously then NtQueryInformationProcess() 207 * didn't initialize the structure with data. 208 */ 209 RtlFillMemory(&ProcPriority->PriorityClass, sizeof(ProcPriority->PriorityClass), 0x55); 210 211 /* Unaligned buffer -- wrong size */ 212 Status = NtQueryInformationProcess(NtCurrentProcess(), 213 ProcessPriorityClass, 214 (PVOID)1, 215 0, 216 NULL); 217 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 218 219 /* Unaligned buffer -- correct size */ 220 Status = NtQueryInformationProcess(NtCurrentProcess(), 221 ProcessPriorityClass, 222 (PVOID)1, 223 sizeof(PROCESS_PRIORITY_CLASS), 224 NULL); 225 ok_hex(Status, STATUS_DATATYPE_MISALIGNMENT); 226 227 /* Unaligned buffer -- wrong size (but this time do with an alignment of 2) */ 228 Status = NtQueryInformationProcess(NtCurrentProcess(), 229 ProcessPriorityClass, 230 (PVOID)2, 231 0, 232 NULL); 233 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 234 235 /* Unaligned buffer -- correct size (but this time do with an alignment of 2) */ 236 Status = NtQueryInformationProcess(NtCurrentProcess(), 237 ProcessPriorityClass, 238 (PVOID)2, 239 sizeof(PROCESS_PRIORITY_CLASS), 240 NULL); 241 ok_hex(Status, STATUS_DATATYPE_MISALIGNMENT); 242 243 /* Do not care for the length but expect to return the priority class */ 244 Status = NtQueryInformationProcess(NtCurrentProcess(), 245 ProcessPriorityClass, 246 ProcPriority, 247 sizeof(PROCESS_PRIORITY_CLASS), 248 NULL); 249 ok_hex(Status, STATUS_SUCCESS); 250 251 /* Make sure the returned priority class is a valid number (non negative) but also it should be within the PROCESS_PRIORITY_CLASS range */ 252 ok(ProcPriority->PriorityClass > PROCESS_PRIORITY_CLASS_INVALID && ProcPriority->PriorityClass <= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL, 253 "Expected a valid number from priority class range but got %d\n", ProcPriority->PriorityClass); 254 free(ProcPriority); 255 } 256 257 static 258 void 259 Test_ProcessWx86Information(void) 260 { 261 NTSTATUS Status; 262 ULONG VdmPower = 1, ReturnLength; 263 264 /* Everything is NULL */ 265 Status = NtQueryInformationProcess(NULL, 266 ProcessWx86Information, 267 NULL, 268 0, 269 NULL); 270 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 271 272 /* Given an invalid process handle */ 273 Status = NtQueryInformationProcess(NULL, 274 ProcessWx86Information, 275 &VdmPower, 276 sizeof(VdmPower), 277 NULL); 278 ok_hex(Status, STATUS_INVALID_HANDLE); 279 280 /* Don't query anything */ 281 Status = NtQueryInformationProcess(NtCurrentProcess(), 282 ProcessWx86Information, 283 NULL, 284 sizeof(VdmPower), 285 NULL); 286 ok_hex(Status, STATUS_ACCESS_VIOLATION); 287 288 /* The buffer is misaligned and information length is wrong */ 289 Status = NtQueryInformationProcess(NtCurrentProcess(), 290 ProcessWx86Information, 291 (PVOID)1, 292 0, 293 NULL); 294 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 295 296 /* The buffer is misaligned */ 297 Status = NtQueryInformationProcess(NtCurrentProcess(), 298 ProcessWx86Information, 299 (PVOID)1, 300 sizeof(VdmPower), 301 NULL); 302 ok_hex(Status, STATUS_DATATYPE_MISALIGNMENT); 303 304 /* The buffer is misaligned -- try with an alignment size of 2 */ 305 Status = NtQueryInformationProcess(NtCurrentProcess(), 306 ProcessWx86Information, 307 (PVOID)2, 308 sizeof(VdmPower), 309 NULL); 310 ok_hex(Status, STATUS_DATATYPE_MISALIGNMENT); 311 312 /* Query the VDM power */ 313 Status = NtQueryInformationProcess(NtCurrentProcess(), 314 ProcessWx86Information, 315 &VdmPower, 316 sizeof(VdmPower), 317 NULL); 318 ok_hex(Status, STATUS_SUCCESS); 319 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); 320 321 /* Same but with ReturnLength */ 322 Status = NtQueryInformationProcess(NtCurrentProcess(), 323 ProcessWx86Information, 324 &VdmPower, 325 sizeof(VdmPower), 326 &ReturnLength); 327 ok_hex(Status, STATUS_SUCCESS); 328 ok(ReturnLength != 0, "ReturnLength shouldn't be 0!\n"); 329 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); 330 331 /* Trace the VDM power value and returned length */ 332 trace("ReturnLength = %lu\n", ReturnLength); 333 trace("VdmPower = %lu\n", VdmPower); 334 } 335 336 static 337 void 338 Test_ProcQueryAlignmentProbe(void) 339 { 340 ULONG InfoClass; 341 342 /* Iterate over the process info classes and begin the tests */ 343 for (InfoClass = 0; InfoClass < _countof(PsProcessInfoClass); InfoClass++) 344 { 345 /* The buffer is misaligned */ 346 QuerySetProcessValidator(QUERY, 347 InfoClass, 348 (PVOID)(ULONG_PTR)1, 349 PsProcessInfoClass[InfoClass].RequiredSizeQUERY, 350 STATUS_DATATYPE_MISALIGNMENT); 351 352 /* We query an invalid buffer address */ 353 QuerySetProcessValidator(QUERY, 354 InfoClass, 355 (PVOID)(ULONG_PTR)PsProcessInfoClass[InfoClass].AlignmentQUERY, 356 PsProcessInfoClass[InfoClass].RequiredSizeQUERY, 357 STATUS_ACCESS_VIOLATION); 358 359 /* The information length is wrong */ 360 QuerySetProcessValidator(QUERY, 361 InfoClass, 362 (PVOID)(ULONG_PTR)PsProcessInfoClass[InfoClass].AlignmentQUERY, 363 PsProcessInfoClass[InfoClass].RequiredSizeQUERY - 1, 364 STATUS_INFO_LENGTH_MISMATCH); 365 } 366 } 367 368 START_TEST(NtQueryInformationProcess) 369 { 370 NTSTATUS Status; 371 372 /* Make sure that some time has passed since process creation, even if the resolution of our NtQuerySystemTime is low. */ 373 Sleep(1); 374 375 Status = NtQuerySystemTime(&TestStartTime); 376 ok_hex(Status, STATUS_SUCCESS); 377 378 Test_ProcessTimes(); 379 Test_ProcessPriorityClassAlignment(); 380 Test_ProcessWx86Information(); 381 Test_ProcQueryAlignmentProbe(); 382 } 383