From b7b48c9fcf5035c1f709d62a83714c7a8e4cb901 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Tue, 1 Jun 2021 15:32:54 -0700 Subject: [PATCH] Define size_t.ByReference and fix macOS sysctl size_t* parameters (#1351) --- CHANGES.md | 1 + .../src/com/sun/jna/platform/mac/SystemB.java | 56 ++++++++++----- .../com/sun/jna/platform/unix/LibCAPI.java | 37 +++++++++- .../ByReferencePlatformToStringTest.java | 4 ++ .../com/sun/jna/platform/mac/SystemBTest.java | 68 ++++++++++--------- 5 files changed, 117 insertions(+), 49 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b9eb878a2a..f258b9a91e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -15,6 +15,7 @@ Features Bug Fixes --------- * [#1343](https://github.com/java-native-access/jna/issues/1343): `c.s.j.p.mac.CoreFoundation.CFStringRef#stringValue` buffer needs space for a null byte - [@dbwiddis](https://github.com/dbwiddis). +* [#1351](https://github.com/java-native-access/jna/issues/1351): Define `c.s.j.p.unix.size_t.ByReference` and fix macOS sysctl `size_t *` parameters - [@dbwiddis](https://github.com/dbwiddis). Release 5.8.0 ============= diff --git a/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java b/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java index d11396b630..d17eeb8fa6 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java @@ -623,10 +623,10 @@ class Timezone extends Structure { * The sysctl() function retrieves system information and allows processes with * appropriate privileges to set system information. The information available * from sysctl() consists of integers, strings, and tables. - * + *

* The state is described using a "Management Information Base" (MIB) style * name, listed in name, which is a namelen length array of integers. - * + *

* The information is copied into the buffer specified by oldp. The size of the * buffer is given by the location specified by oldlenp before the call, and * that location gives the amount of data copied after a successful call and @@ -635,32 +635,41 @@ class Timezone extends Structure { * as much data as fits in the buffer provided and returns with the error code * ENOMEM. If the old value is not desired, oldp and oldlenp should be set to * NULL. - * + *

* The size of the available data can be determined by calling sysctl() with the * NULL argument for oldp. The size of the available data will be returned in * the location pointed to by oldlenp. For some operations, the amount of space * may change often. For these operations, the system attempts to round up so * that the returned size is large enough for a call to return the data shortly * thereafter. - * + *

* To set a new value, newp is set to point to a buffer of length newlen from * which the requested value is to be taken. If a new value is not to be set, * newp should be set to NULL and newlen set to 0. * * @param name - * MIB array of integers + * a Management Information Base (MIB) array of integers * @param namelen - * length of the MIB array + * the length of the array in {@code name} * @param oldp - * Information retrieved + * A buffer to hold the information retrieved * @param oldlenp - * Size of information retrieved + * Size of the buffer, a pointer to a {@link size_t} value * @param newp - * Information to be written + * To set a new value, a buffer of information to be written. May be + * null if no value is to be set. * @param newlen - * Size of information to be written + * Size of the information to be written. May be 0 if no value is to + * be set. * @return 0 on success; sets errno on failure */ + int sysctl(int[] name, int namelen, Pointer oldp, size_t.ByReference oldlenp, Pointer newp, size_t newlen); + + /** + * @deprecated Use + * {@link #sysctl(int[], int, Pointer, Pointer, Pointer, com.sun.jna.platform.unix.LibCAPI.size_t)} + */ + @Deprecated int sysctl(int[] name, int namelen, Pointer oldp, IntByReference oldlenp, Pointer newp, int newlen); /** @@ -671,15 +680,24 @@ class Timezone extends Structure { * @param name * ASCII representation of the MIB name * @param oldp - * Information retrieved + * A buffer to hold the information retrieved * @param oldlenp - * Size of information retrieved + * Size of the buffer, a pointer to a {@link size_t} value * @param newp - * Information to be written + * To set a new value, a buffer of information to be written. May be + * null if no value is to be set. * @param newlen - * Size of information to be written + * Size of the information to be written. May be 0 if no value is to + * be set. * @return 0 on success; sets errno on failure */ + int sysctlbyname(String name, Pointer oldp, size_t.ByReference oldlenp, Pointer newp, size_t newlen); + + /** + * @deprecated Use + * {@link #sysctlbyname(String, Pointer, Pointer, Pointer, com.sun.jna.platform.unix.LibCAPI.size_t)} + */ + @Deprecated int sysctlbyname(String name, Pointer oldp, IntByReference oldlenp, Pointer newp, int newlen); /** @@ -705,12 +723,18 @@ class Timezone extends Structure { * ASCII representation of the name * @param mibp * Integer array containing the corresponding name vector. - * @param size + * @param sizep * On input, number of elements in the returned array; on output, the * number of entries copied. * @return 0 on success; sets errno on failure */ - int sysctlnametomib(String name, Pointer mibp, IntByReference size); + int sysctlnametomib(String name, Pointer mibp, size_t.ByReference sizep); + + /** + * @deprecated Use {@link #sysctlnametomib(String, Pointer, Pointer)} + */ + @Deprecated + int sysctlnametomib(String name, Pointer mibp, IntByReference sizep); /** * The host_processor_info function returns information about processors. diff --git a/contrib/platform/src/com/sun/jna/platform/unix/LibCAPI.java b/contrib/platform/src/com/sun/jna/platform/unix/LibCAPI.java index c2a9b9485e..934ee17602 100644 --- a/contrib/platform/src/com/sun/jna/platform/unix/LibCAPI.java +++ b/contrib/platform/src/com/sun/jna/platform/unix/LibCAPI.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2015 Goldstein Lyor, All Rights Reserved +/* Copyright (c) 2015 Goldstein Lyor, 2021 Daniel Widdis, All Rights Reserved * * The contents of this file is dual-licensed under 2 * alternative Open Source/Free licenses: LGPL 2.1 or later and @@ -43,6 +43,41 @@ class size_t extends IntegerType { private static final long serialVersionUID = 1L; + public static class ByReference extends com.sun.jna.ptr.ByReference { + public ByReference() { + this(0); + } + + public ByReference(long value) { + this(new size_t(value)); + } + + public ByReference(size_t value) { + super(Native.SIZE_T_SIZE); + setValue(value); + } + + public void setValue(long value) { + setValue(new size_t(value)); + } + + public void setValue(size_t value) { + if (Native.SIZE_T_SIZE > 4) { + getPointer().setLong(0, value.longValue()); + } else { + getPointer().setInt(0, value.intValue()); + } + } + + public long longValue() { + return Native.SIZE_T_SIZE > 4 ? getPointer().getLong(0) : getPointer().getInt(0); + } + + public size_t getValue() { + return new size_t(longValue()); + } + } + public size_t() { this(0); } diff --git a/contrib/platform/test/com/sun/jna/platform/ByReferencePlatformToStringTest.java b/contrib/platform/test/com/sun/jna/platform/ByReferencePlatformToStringTest.java index 902bb72806..f8953cf483 100644 --- a/contrib/platform/test/com/sun/jna/platform/ByReferencePlatformToStringTest.java +++ b/contrib/platform/test/com/sun/jna/platform/ByReferencePlatformToStringTest.java @@ -30,6 +30,7 @@ import com.sun.jna.Platform; import com.sun.jna.Pointer; +import com.sun.jna.platform.unix.LibCAPI.size_t; import com.sun.jna.platform.unix.X11.AtomByReference; import com.sun.jna.platform.unix.X11.WindowByReference; import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR; @@ -137,6 +138,9 @@ public void testPlatformToStrings() { SCODEByReference scodebr = new SCODEByReference(new SCODE(42)); parseAndTest(scodebr.toString(), "SCODE", "42"); + size_t.ByReference sizetbr = new size_t.ByReference(42); + parseAndTest(sizetbr.toString(), "size_t", "42"); + UINTByReference uibr = new UINTByReference(new UINT(42)); parseAndTest(uibr.toString(), "UINT", "42"); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java b/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java index 6b9af6ebca..b658eefb5e 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java @@ -54,7 +54,7 @@ import com.sun.jna.ptr.PointerByReference; import junit.framework.TestCase; - +import static com.sun.jna.platform.unix.LibCAPI.size_t; /** * Exercise the {@link SystemB} class. */ @@ -64,33 +64,36 @@ public void testSysctl() { final String mibName = "hw.logicalcpu"; final int nCpu = Runtime.getRuntime().availableProcessors(); - IntByReference size = new IntByReference(SystemB.INT_SIZE); - Pointer p = new Memory(size.getValue()); - int ret = SystemB.INSTANCE.sysctlbyname(mibName, p, size, null, 0); - assertEquals(ret, 0); + // This sysctl returns a 32-bit integer cpu count + Memory p = new Memory(SystemB.INT_SIZE); + size_t.ByReference plen = new size_t.ByReference(p.size()); + assertEquals(0, SystemB.INSTANCE.sysctlbyname(mibName, p, plen, null, size_t.ZERO)); // These values should be equal unless affinity is set, limiting nCpu assertTrue(p.getInt(0) >= nCpu); - size = new IntByReference(); - ret = SystemB.INSTANCE.sysctlnametomib(mibName, null, size); - assertEquals(ret, 0); - // Size should be 2 - assertEquals(size.getValue(), 2); - - Pointer mibp = new Memory(size.getValue() * SystemB.INT_SIZE); - ret = SystemB.INSTANCE.sysctlnametomib(mibName, mibp, size); - assertEquals(ret, 0); - // Size should be 2 - assertEquals(size.getValue(), 2); - - int[] mib = mibp.getIntArray(0, size.getValue()); + // Get the same value by converting the string to the MIB array + // Get the size of the MIB array + size_t.ByReference sizep = new size_t.ByReference(); + assertEquals(0, SystemB.INSTANCE.sysctlnametomib(mibName, null, sizep)); + // Array size should be 2 + long sizepval = sizep.longValue(); + assertEquals(2L, sizepval); + + // Allocate the correct size and fill the MIB array + Pointer mibp = new Memory(sizepval * SystemB.INT_SIZE); + assertEquals(0, SystemB.INSTANCE.sysctlnametomib(mibName, mibp, sizep)); + // Array size should still be 2 + sizepval = sizep.longValue(); + assertEquals(2L, sizepval); + + int[] mib = mibp.getIntArray(0, (int) sizepval); // mib should be { 6, 103(?) } assertEquals(mib.length, 2); assertEquals(mib[0], 6); - size = new IntByReference(SystemB.INT_SIZE); - p = new Memory(size.getValue()); - ret = SystemB.INSTANCE.sysctl(mib, mib.length, p, size, null, 0); + p = new Memory(SystemB.INT_SIZE); + plen = new size_t.ByReference(p.size()); + assertEquals(0, SystemB.INSTANCE.sysctl(mib, mib.length, p, plen, null, size_t.ZERO)); assertTrue(p.getInt(0) >= nCpu); } @@ -257,16 +260,16 @@ public void testStatfs() { public void testXswUsage() { XswUsage xswUsage = new XswUsage(); assertEquals(0, SystemB.INSTANCE.sysctlbyname("vm.swapusage", xswUsage.getPointer(), - new IntByReference(xswUsage.size()), null, 0)); + new size_t.ByReference(xswUsage.size()), null, size_t.ZERO)); xswUsage.read(); assertTrue(xswUsage.xsu_used <= xswUsage.xsu_total); } public void testProcessStructures() { // Calc max # of processes - IntByReference size = new IntByReference(4); - Memory mem = new Memory(4); - assertEquals(0, SystemB.INSTANCE.sysctlbyname("kern.maxproc", mem, size, null, 0)); + Memory mem = new Memory(SystemB.INT_SIZE); + size_t.ByReference size = new size_t.ByReference(mem.size()); + assertEquals(0, SystemB.INSTANCE.sysctlbyname("kern.maxproc", mem, size, null, size_t.ZERO)); int maxProc = mem.getInt(0); // Get list of pids @@ -330,15 +333,16 @@ public void testIFs() { int NET_RT_IFLIST2 = 6; int[] mib = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0 }; - IntByReference len = new IntByReference(); - assertEquals(0, SystemB.INSTANCE.sysctl(mib, 6, null, len, null, 0)); - // Add enough room for max size of IFmsgHdr to avoid JNA bounds check - // problems with worst case structure size - Memory buf = new Memory(len.getValue() + 112); - assertEquals(0, SystemB.INSTANCE.sysctl(mib, 6, buf, len, null, 0)); + size_t.ByReference len = new size_t.ByReference(); + assertEquals(0, SystemB.INSTANCE.sysctl(mib, 6, null, len, null, size_t.ZERO)); + // Add enough room in buffer for later iteration so that max size of IFmsgHdr + // or IFMsgHdr2 does not cause bounds check issues with worst case size. + Memory buf = new Memory(len.longValue() + 112); + // We still pass the original buffer size to native. + assertEquals(0, SystemB.INSTANCE.sysctl(mib, 6, buf, len, null, size_t.ZERO)); // Iterate offset from buf's pointer up to limit of buf - int lim = len.getValue(); + long lim = len.longValue(); int next = 0; while (next < lim) { // Get pointer to current native part of buf