Skip to content

Commit

Permalink
Define size_t.ByReference and fix macOS sysctl size_t* parameters (#1351
Browse files Browse the repository at this point in the history
)
  • Loading branch information
dbwiddis authored Jun 1, 2021
1 parent f89905a commit b7b48c9
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 49 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
=============
Expand Down
56 changes: 40 additions & 16 deletions contrib/platform/src/com/sun/jna/platform/mac/SystemB.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
* <p>
* The state is described using a "Management Information Base" (MIB) style
* name, listed in name, which is a namelen length array of integers.
*
* <p>
* 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
Expand All @@ -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.
*
* <p>
* 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.
*
* <p>
* 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);

/**
Expand All @@ -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);

/**
Expand All @@ -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.
Expand Down
37 changes: 36 additions & 1 deletion contrib/platform/src/com/sun/jna/platform/unix/LibCAPI.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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");

Expand Down
68 changes: 36 additions & 32 deletions contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand All @@ -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);
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit b7b48c9

Please sign in to comment.