Skip to content

Commit 50eb820

Browse files
committed
fix varargs on ARM
1 parent 51cab75 commit 50eb820

10 files changed

Lines changed: 87 additions & 24 deletions

File tree

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Bug Fixes
4343
* [#531](https://github.com/java-native-access/jna/pull/531): Ensure direct-mapped callbacks use the right calling convention - [@twall](https://github.com/twall).
4444
* [#566](https://github.com/java-native-access/jna/pull/566): Fix return type of Native#loadLibrary to match unconstrained generic [@lgoldstein](https://github.com/lgoldstein)
4545
* [#584](https://github.com/java-native-access/jna/pull/584): Promote float varargs to double - [@marco2357](https://github.com/marco2357).
46+
* [#588](https://github.com/java-native-access/jna/pull/588): Fix varargs calls on arm - [@twall](https://github.com/twall).
4647

4748
Release 4.2.1
4849
=============

build.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
<!-- jnidispatch library release version -->
7070
<property name="jni.major" value="5"/>
7171
<property name="jni.minor" value="0"/>
72-
<property name="jni.revision" value="1"/>
72+
<property name="jni.revision" value="0"/>
7373
<property name="jni.build" value="0"/> <!--${build.number}-->
7474
<property name="jni.version" value="${jni.major}.${jni.minor}.${jni.revision}"/>
7575
<property name="jni.md5" value="4f72f2799dfee6008a386bc40afd7428"/>

lib/native/linux-arm.jar

203 Bytes
Binary file not shown.

native/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ OS=$(shell uname | sed -e 's/CYGWIN.*/win32/g' \
5050
-e 's/AIX.*/aix/g' \
5151
-e 's/Linux.*/linux/g')
5252

53-
JNA_JNI_VERSION=5.0.1 # auto-generated by ant
53+
JNA_JNI_VERSION=5.0.0 # auto-generated by ant
5454
CHECKSUM=4f72f2799dfee6008a386bc40afd7428 # auto-generated by ant
5555

5656
JAVA_INCLUDES=-I"$(JAVA_HOME)/include" \

native/dispatch.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ extern "C" {
108108

109109
#define MASK_CC com_sun_jna_Function_MASK_CC
110110
#define THROW_LAST_ERROR com_sun_jna_Function_THROW_LAST_ERROR
111+
#define USE_VARARGS com_sun_jna_Function_USE_VARARGS
111112

112113
/* Cached class, field and method IDs */
113114
static jclass classObject;
@@ -436,6 +437,7 @@ dispatch(JNIEnv *env, void* func, jint flags, jobjectArray args,
436437
callconv_t callconv = flags & MASK_CC;
437438
const char* volatile throw_type = NULL;
438439
const char* volatile throw_msg = NULL;
440+
int fixed_args = (flags & USE_VARARGS) >> 7;
439441

440442
nargs = (*env)->GetArrayLength(env, args);
441443

@@ -610,7 +612,9 @@ dispatch(JNIEnv *env, void* func, jint flags, jobjectArray args,
610612
break;
611613
}
612614

613-
status = ffi_prep_cif(&cif, abi, nargs, return_type, arg_types);
615+
status = fixed_args
616+
? ffi_prep_cif_var(&cif, abi, fixed_args, nargs, return_type, arg_types)
617+
: ffi_prep_cif(&cif, abi, nargs, return_type, arg_types);
614618
if (!ffi_error(env, "Native call setup", status)) {
615619
PSTART();
616620
if ((flags & THROW_LAST_ERROR) != 0) {

native/testlib.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -855,12 +855,14 @@ fillDoubleBuffer(double *buf, int len, double value) {
855855
return len;
856856
}
857857

858+
#include "ffi.h"
859+
858860
EXPORT int32_t
859-
addInt32VarArgs(const char *fmt, ...) {
861+
addVarArgs(const char *fmt, ...) {
860862
va_list ap;
861863
int32_t sum = 0;
862864
va_start(ap, fmt);
863-
865+
864866
while (*fmt) {
865867
switch (*fmt++) {
866868
case 'd':
@@ -873,7 +875,7 @@ addInt32VarArgs(const char *fmt, ...) {
873875
sum += (int) va_arg(ap, int);
874876
break;
875877
case 'f': // float (promoted to ‘double’ when passed through ‘...’)
876-
case 'F': // double
878+
case 'g': // double
877879
sum += va_arg(ap, double);
878880
break;
879881
default:

src/com/sun/jna/Function.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ public interface PostCallRead {
5959
private static final int MASK_CC = 0x3F;
6060
/** Whether to throw an exception if last error is non-zero after call. */
6161
public static final int THROW_LAST_ERROR = 0x40;
62+
/** Mask for number of fixed args (1-3) for varargs calls. */
63+
public static final int USE_VARARGS = 0x180;
6264

6365
static final Integer INTEGER_TRUE = Integer.valueOf(-1);
6466
static final Integer INTEGER_FALSE = Integer.valueOf(0);
@@ -293,10 +295,10 @@ Object invoke(Method invokingMethod, Class<?>[] paramTypes, Class<?> returnType,
293295

294296
TypeMapper mapper = (TypeMapper)options.get(Library.OPTION_TYPE_MAPPER);
295297
boolean allowObjects = Boolean.TRUE.equals(options.get(Library.OPTION_ALLOW_OBJECTS));
296-
boolean isVarArgs = args.length > 0 && invokingMethod != null ? isVarArgs(invokingMethod) : false;
298+
int fixedArgs = args.length > 0 && invokingMethod != null ? fixedArgs(invokingMethod) : 0;
297299
for (int i=0; i < args.length; i++) {
298300
Class<?> paramType = invokingMethod != null
299-
? (isVarArgs && i >= paramTypes.length-1
301+
? (fixedArgs > 0 && i >= paramTypes.length-1
300302
? paramTypes[paramTypes.length-1].getComponentType()
301303
: paramTypes[i])
302304
: null;
@@ -316,7 +318,7 @@ Object invoke(Method invokingMethod, Class<?>[] paramTypes, Class<?> returnType,
316318
}
317319
}
318320

319-
Object result = invoke(args, nativeReturnType, allowObjects);
321+
Object result = invoke(args, nativeReturnType, allowObjects, fixedArgs);
320322
// Convert the result to a custom value/type if appropriate
321323
if (resultConverter != null) {
322324
FromNativeContext context;
@@ -362,7 +364,13 @@ Object invoke(Method invokingMethod, Class<?>[] paramTypes, Class<?> returnType,
362364

363365
/* @see NativeLibrary#NativeLibrary(String,String,long,Map) implementation */
364366
Object invoke(Object[] args, Class<?> returnType, boolean allowObjects) {
367+
return invoke(args, returnType, allowObjects, 0);
368+
}
369+
370+
/* @see NativeLibrary#NativeLibrary(String,String,long,Map) implementation */
371+
Object invoke(Object[] args, Class<?> returnType, boolean allowObjects, int fixedArgs) {
365372
Object result = null;
373+
int callFlags = this.callFlags | ((fixedArgs & 0x3) << 7);
366374
if (returnType == null || returnType==void.class || returnType==Void.class) {
367375
Native.invokeVoid(peer, callFlags, args);
368376
result = null;
@@ -752,6 +760,11 @@ static boolean isVarArgs(Method m) {
752760
return IS_VARARGS.isVarArgs(m);
753761
}
754762

763+
/** Varargs are only supported on 1.5+. */
764+
static int fixedArgs(Method m) {
765+
return IS_VARARGS.fixedArgs(m);
766+
}
767+
755768
private static class NativeMappedArray extends Memory implements PostCallRead {
756769
private final NativeMapped[] original;
757770
public NativeMappedArray(NativeMapped[] arg) {

src/com/sun/jna/VarArgsChecker.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ boolean isVarArgs(Method m) {
2525
return m.isVarArgs();
2626
}
2727

28+
int fixedArgs(Method m) {
29+
// In Java, final argument contains all "varargs"
30+
return m.getParameterTypes().length - 1;
31+
}
2832
}
2933

3034
/**
@@ -37,6 +41,9 @@ boolean isVarArgs(Method m) {
3741
return false;
3842
}
3943

44+
int fixedArgs(Method m) {
45+
return 0;
46+
}
4047
}
4148

4249
/**
@@ -68,4 +75,10 @@ static VarArgsChecker create() {
6875
*/
6976
abstract boolean isVarArgs(Method m);
7077

78+
/**
79+
* If variadic, returns the number of fixed arguments to the method.
80+
* @param m Method to be checked
81+
* @return Number of fixed arguments if the given method takes a variable number of arguments, zero otherwise.
82+
*/
83+
abstract int fixedArgs(Method m);
7184
}

test/com/sun/jna/VarArgsCheckerTest.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public void testNoVarArgs() throws Exception {
1616
final Method toCheckForVarArgs = VarArgsCheckerTest.class.getMethod("testNoVarArgs", new Class[0]);
1717
final boolean res = sut.isVarArgs(toCheckForVarArgs);
1818
// no matter if JVM 1.4 or 1.5+, the result should always be false
19-
assertFalse(res);
19+
assertFalse("Method should not be detected as varargs", res);
2020
}
2121

2222
public void testVarArgsExist() throws Exception {
@@ -25,10 +25,40 @@ public void testVarArgsExist() throws Exception {
2525
final boolean res = sut.isVarArgs(toCheckForVarArgs);
2626
// this test has to run with Java 1.5+, because this has a method with
2727
// varargs. So the result has to be true.
28-
assertTrue(res);
28+
assertTrue("Method should be detected as varargs", res);
29+
}
30+
31+
public void testFixedArgsOne() throws Exception {
32+
final VarArgsChecker checker = VarArgsChecker.create();
33+
final Method method = VarArgsCheckerTest.class.getMethod("methodWithOneFixedArg", new Class[]{String.class, Object[].class});
34+
final int res = checker.fixedArgs(method);
35+
// this test has to run with Java 1.5+, because this has a method with
36+
// varargs. So the result has to be true.
37+
assertEquals("Wrong number of fixed args", 1, res);
38+
}
39+
40+
public void testFixedArgsTwo() throws Exception {
41+
final VarArgsChecker checker = VarArgsChecker.create();
42+
final Method method = VarArgsCheckerTest.class.getMethod("methodWithTwoFixedArgs", new Class[]{String.class, String.class, Object[].class});
43+
final int res = checker.fixedArgs(method);
44+
// this test has to run with Java 1.5+, because this has a method with
45+
// varargs. So the result has to be true.
46+
assertEquals("Wrong number of fixed args", 2, res);
2947
}
3048

3149
public void methodWithVarArgs(String... args) {
32-
System.out.println();
50+
// nothing to do
51+
}
52+
53+
public void methodWithOneFixedArg(String fmt, Object... args) {
54+
// nothing to do
55+
}
56+
57+
public void methodWithTwoFixedArgs(String fmt, String fmt2, Object... args) {
58+
// nothing to do
59+
}
60+
61+
public static void main(String[] args) {
62+
junit.textui.TestRunner.run(VarArgsCheckerTest.class);
3363
}
3464
}

test/com/sun/jna/VarArgsTest.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ protected List<String> getFieldOrder() {
2929
return Arrays.asList("magic");
3030
}
3131
}
32-
public int addInt32VarArgs(String fmt, Number... args);
32+
public int addVarArgs(String fmt, Number... args);
3333
public String returnStringVarArgs(String fmt, Object... args);
3434
public void modifyStructureVarArgs(String fmt, Object arg1, Object... args);
3535
}
@@ -45,32 +45,32 @@ protected void tearDown() {
4545
public void testIntVarArgs() {
4646
int arg1 = 1;
4747
int arg2 = 2;
48-
assertEquals("VarArgs not added correctly", arg1 + arg2,
49-
lib.addInt32VarArgs("dd", Integer.valueOf(arg1), Integer.valueOf(arg2)));
48+
assertEquals("32-bit integer varargs not added correctly", arg1 + arg2,
49+
lib.addVarArgs("dd", Integer.valueOf(arg1), Integer.valueOf(arg2)));
5050
}
5151
public void testShortVarArgs() {
5252
short arg1 = 1;
5353
short arg2 = 2;
54-
assertEquals("VarArgs not added correctly", arg1 + arg2,
55-
lib.addInt32VarArgs("dd", Short.valueOf(arg1), Short.valueOf(arg2)));
54+
assertEquals("16-bit integer varargs not added correctly", arg1 + arg2,
55+
lib.addVarArgs("dd", Short.valueOf(arg1), Short.valueOf(arg2)));
5656
}
5757
public void testLongVarArgs() {
5858
short arg1 = 1;
5959
short arg2 = 2;
60-
assertEquals("VarArgs not added correctly", arg1 + arg2,
61-
lib.addInt32VarArgs("ll", Long.valueOf(arg1), Long.valueOf(arg2)));
60+
assertEquals("64-bit integer varargs not added correctly", arg1 + arg2,
61+
lib.addVarArgs("ll", Long.valueOf(arg1), Long.valueOf(arg2)));
6262
}
6363
public void testFloatVarArgs() {
6464
float arg1 = 1;
6565
float arg2 = 2;
66-
assertEquals("VarArgs not added correctly", (int)arg1 + (int)arg2,
67-
lib.addInt32VarArgs("ff", Float.valueOf(arg1), Float.valueOf(arg2)));
66+
assertEquals("float varargs not added correctly", (int)arg1 + (int)arg2,
67+
lib.addVarArgs("ff", Float.valueOf(arg1), Float.valueOf(arg2)));
6868
}
6969
public void testDoubleVarArgs() {
7070
double arg1 = 1;
7171
double arg2 = 2;
72-
assertEquals("VarArgs not added correctly", (int)arg1 + (int)arg2,
73-
lib.addInt32VarArgs("FF", Double.valueOf(arg1), Double.valueOf(arg2)));
72+
assertEquals("double varargs not added correctly", (int)arg1 + (int)arg2,
73+
lib.addVarArgs("gg", Double.valueOf(arg1), Double.valueOf(arg2)));
7474
}
7575
public void testStringVarArgs() {
7676
Object[] args = new Object[] { "Test" };
@@ -81,7 +81,7 @@ public void testStringVarArgs() {
8181
public void testAppendNullToVarargs() {
8282
Number[] args = new Number[] { Integer.valueOf(1) };
8383
assertEquals("No trailing NULL was appended to varargs list",
84-
1, lib.addInt32VarArgs("dd", args));
84+
1, lib.addVarArgs("dd", args));
8585
}
8686

8787
public void testModifyStructureInVarargs() {

0 commit comments

Comments
 (0)