|
26 | 26 | import static org.junit.Assert.assertTrue;
|
27 | 27 | import static org.junit.Assert.assertNotEquals;
|
28 | 28 | import static org.junit.Assert.assertFalse;
|
| 29 | +import static org.junit.Assert.assertEquals; |
29 | 30 |
|
30 | 31 | import java.util.LinkedList;
|
31 | 32 | import java.util.List;
|
|
45 | 46 | import com.sun.jna.platform.win32.WinNT.HANDLE;
|
46 | 47 | import com.sun.jna.platform.win32.WinNT.MEMORY_BASIC_INFORMATION;
|
47 | 48 | import com.sun.jna.platform.win32.BaseTSD.SIZE_T;
|
| 49 | +import com.sun.jna.platform.win32.Psapi.PSAPI_WORKING_SET_EX_INFORMATION; |
48 | 50 | import com.sun.jna.ptr.IntByReference;
|
49 | 51 |
|
50 | 52 | /**
|
@@ -280,38 +282,104 @@ public void testEnumProcesses() {
|
280 | 282 | }
|
281 | 283 |
|
282 | 284 | @Test
|
| 285 | + @SuppressWarnings("ResultOfObjectAllocationIgnored") |
283 | 286 | public void testQueryWorkingSetEx() {
|
284 |
| - Win32Exception we = null; |
285 | 287 | HANDLE selfHandle = Kernel32.INSTANCE.GetCurrentProcess();
|
286 |
| - MEMORY_BASIC_INFORMATION mbi = new MEMORY_BASIC_INFORMATION(); |
| 288 | + |
| 289 | + Memory[] mem = new Memory[4]; |
| 290 | + mem[0] = new Memory(4096); |
| 291 | + new Memory(8192); // Try to ensure the memory pages are not adjacent |
| 292 | + mem[1] = new Memory(4096); |
| 293 | + new Memory(8192); // Try to ensure the memory pages are not adjacent |
| 294 | + mem[3] = new Memory(4096); |
| 295 | + |
287 | 296 | try {
|
288 |
| - SIZE_T bytesRead = Kernel32.INSTANCE.VirtualQueryEx(selfHandle, Pointer.NULL, mbi, new SIZE_T(mbi.size())); |
289 |
| - assertNotEquals("Kernel should be able to read this Process' Bytes", bytesRead.intValue(), 0); |
290 |
| - Psapi.PSAPI_WORKING_SET_EX_INFORMATION pswsi = new Psapi.PSAPI_WORKING_SET_EX_INFORMATION(); |
291 |
| - pswsi.VirtualAddress = mbi.baseAddress; |
292 |
| - if (!Psapi.INSTANCE.QueryWorkingSetEx(selfHandle, pswsi.VirtualAddress, pswsi.size())) { |
293 |
| - throw new Win32Exception(Native.getLastError()); |
| 297 | + PSAPI_WORKING_SET_EX_INFORMATION[] pswsi = (PSAPI_WORKING_SET_EX_INFORMATION[]) new PSAPI_WORKING_SET_EX_INFORMATION().toArray(4); |
| 298 | + |
| 299 | + pswsi[0].VirtualAddress = mem[0]; |
| 300 | + pswsi[1].VirtualAddress = mem[1]; |
| 301 | + pswsi[2].VirtualAddress = mem[2]; |
| 302 | + pswsi[3].VirtualAddress = mem[3]; |
| 303 | + |
| 304 | + for(int i = 0; i < pswsi.length; i++) { |
| 305 | + pswsi[i].write(); |
294 | 306 | }
|
295 |
| - assertTrue("Virual Attributes should not be null", pswsi.VirtualAttributes != null); |
296 |
| - if (Psapi.INSTANCE.QueryWorkingSetEx(new HANDLE(), pswsi.VirtualAddress, pswsi.size())) { |
297 |
| - throw new Win32Exception(Native.getLastError()); |
| 307 | + |
| 308 | + assertTrue("Failed to invoke QueryWorkingSetEx (1)", Psapi.INSTANCE.QueryWorkingSetEx(selfHandle, pswsi[0].getPointer(), pswsi[0].size() * pswsi.length)); |
| 309 | + |
| 310 | + for (int i = 0; i < pswsi.length; i++) { |
| 311 | + pswsi[i].read(); |
| 312 | + assertTrue("Virtual Attributes should not be null (1)", pswsi[i].VirtualAttributes != null); |
| 313 | + assertEquals("Virtual Address should not change before and after call (1)", pswsi[i].VirtualAddress, mem[i]); |
| 314 | + if (i != 2) { |
| 315 | + assertTrue("Data was invalid (1)", pswsi[i].isValid()); |
| 316 | + assertFalse("Data was reported as bad (1)", pswsi[i].isBad()); |
| 317 | + assertEquals("Data indicates sharing (1)", pswsi[i].getShareCount(), 0); |
| 318 | + assertEquals("Data indicated that protection does not match PAGE_READWRITE (1)", |
| 319 | + pswsi[i].getWin32Protection(), WinNT.PAGE_READWRITE); |
| 320 | + assertFalse("Data was reported as shared (1)", pswsi[i].isShared()); |
| 321 | + assertFalse("Data was reported as locked (1)", pswsi[i].isLocked()); |
| 322 | + assertFalse("Data was reported as large pages (1)", pswsi[i].isLargePage()); |
| 323 | + } else { |
| 324 | + assertFalse("Data was reported valid, but expected to be invalid (1)", pswsi[i].isValid()); |
| 325 | + } |
298 | 326 | }
|
299 |
| - assertFalse("This line should never be called", true); |
300 |
| - } catch (Win32Exception e) { |
301 |
| - we = e; |
302 |
| - throw we; // re-throw to invoke finally block |
| 327 | + |
| 328 | + // Lock the page we used into memory - this should be reflected in the reported flags in the next call |
| 329 | + assertTrue(Kernel32.INSTANCE.VirtualLock(mem[1], new SIZE_T(4096))); |
| 330 | + |
| 331 | + for (int i = 0; i < pswsi.length; i++) { |
| 332 | + pswsi[i].write(); |
| 333 | + } |
| 334 | + |
| 335 | + assertTrue("Failed to invoke QueryWorkingSetEx (2)", Psapi.INSTANCE.QueryWorkingSetEx(selfHandle, pswsi[0].getPointer(), pswsi[0].size() * pswsi.length)); |
| 336 | + |
| 337 | + for (int i = 0; i < pswsi.length; i++) { |
| 338 | + pswsi[i].read(); |
| 339 | + assertTrue("Virtual Attributes should not be null (2)", pswsi[i].VirtualAttributes != null); |
| 340 | + assertEquals("Virtual Address should not change before and after call (2)", pswsi[i].VirtualAddress, mem[i]); |
| 341 | + if (i != 2) { |
| 342 | + assertTrue("Virtual Attributes should not be null (2)", pswsi[i].VirtualAttributes != null); |
| 343 | + assertEquals("Virtual Address should not change before and after call (2)", pswsi[i].VirtualAddress, mem[i]); |
| 344 | + assertTrue("Data was invalid (2)", pswsi[i].isValid()); |
| 345 | + assertFalse("Data was reported as bad (2)", pswsi[i].isBad()); |
| 346 | + assertEquals("Data indicates sharing (2)", pswsi[i].getShareCount(), 0); |
| 347 | + assertEquals("Data indicated that protection does not match PAGE_READWRITE (2)", |
| 348 | + pswsi[i].getWin32Protection(), WinNT.PAGE_READWRITE); |
| 349 | + assertFalse("Data was reported as shared (2)", pswsi[i].isShared()); |
| 350 | + // Only the second page should be locked |
| 351 | + if( i == 1 ) { |
| 352 | + assertTrue("Data was reported as unlocked (2)", pswsi[i].isLocked()); |
| 353 | + } else { |
| 354 | + assertFalse("Data was reported as locked (2)", pswsi[i].isLocked()); |
| 355 | + } |
| 356 | + assertFalse("Data was reported as large pages (2)", pswsi[i].isLargePage()); |
| 357 | + } else { |
| 358 | + assertFalse("Data was reported valid, but expected to be invalid (2)", pswsi[i].isValid()); |
| 359 | + } |
| 360 | + } |
| 361 | + |
| 362 | + // Check that a query against an invalid target succeeds, but report |
| 363 | + // invalid data |
| 364 | + PSAPI_WORKING_SET_EX_INFORMATION pswsi2 = new PSAPI_WORKING_SET_EX_INFORMATION(); |
| 365 | + pswsi2.VirtualAddress = null; |
| 366 | + pswsi2.write(); |
| 367 | + assertTrue("Failed to invoke QueryWorkingSetEx (3)", Psapi.INSTANCE.QueryWorkingSetEx(WinBase.INVALID_HANDLE_VALUE, pswsi2.getPointer(), pswsi2.size())); |
| 368 | + pswsi2.read(); |
| 369 | + |
| 370 | + assertTrue("Virtual Attributes should not be null (3)", pswsi2.VirtualAttributes != null); |
| 371 | + assertTrue("Virtual Address should not change before and after call (3)", pswsi2.VirtualAddress == null); |
| 372 | + assertFalse("Data was reported valid, but expected to be invalid (3)", pswsi2.isValid()); |
303 | 373 | } finally {
|
304 | 374 | try {
|
305 | 375 | Kernel32Util.closeHandle(selfHandle);
|
306 | 376 | } catch (Win32Exception e) {
|
307 |
| - if (we == null) { |
308 |
| - we = e; |
309 |
| - } else { |
310 |
| - we.addSuppressedReflected(e); |
311 |
| - } |
| 377 | + // Ignore |
312 | 378 | }
|
313 |
| - if (we != null) { |
314 |
| - throw we; |
| 379 | + try { |
| 380 | + Kernel32.INSTANCE.VirtualUnlock(mem[1], new SIZE_T(4096)); |
| 381 | + } catch (Win32Exception e) { |
| 382 | + // Ignore |
315 | 383 | }
|
316 | 384 | }
|
317 | 385 | }
|
|
0 commit comments