Skip to content

Commit

Permalink
Fix illegal access exceptions, when retrieving options for private li…
Browse files Browse the repository at this point in the history
…brary interfaces with an instance field

 Since direct mapped classes may retrieve options for the first time, only when a callback is passed or returned, this could happen unexpectedly.
  • Loading branch information
fkistner authored and matthiasblaesing committed Dec 6, 2020
1 parent 3b47eff commit 578220e
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Bug Fixes
* [#1275](https://github.com/java-native-access/jna/issues/1275): Fix `CFStringRef#stringValue` for empty Strings - [@dyorgio](https://github.com/dyorgio).
* [#1279](https://github.com/java-native-access/jna/issues/1279): Remove `DLLCallback` import from `CallbackReference` - [@dyorgio](https://github.com/dyorgio).
* [#1278](https://github.com/java-native-access/jna/pull/1278): Improve compatibility of `c.s.j.p.WindowUtils#getProcessFilePath` and fix unittests for windows 32bit intel - [@matthiasblaesing](https://github.com/matthiasblaesing).
* [#1284](https://github.com/java-native-access/jna/pull/1284): Fix illegal access exceptions, when retrieving options for private library interfaces with an instance field - [@fkistner](https://github.com/fkistner).

Release 5.6.0
=============
Expand Down
4 changes: 2 additions & 2 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1256,7 +1256,7 @@ cd ..
</and>
</condition>
<property name="tests.platform" value=""/>
<property name="tests.include" value="com/sun/jna/*Test.java"/>
<property name="tests.include" value="com/sun/jna/*Test.java com/sun/jna/different_package/*Test.java"/>
<property name="tests.exclude" value=""/>
<property name="tests.exclude-patterns" value=""/>
<condition property="java.awt.headless" value="true">
Expand All @@ -1282,7 +1282,7 @@ cd ..
<formatter type="xml"/>
<batchtest todir="${results.junit}">
<fileset dir="${test.src}" excludes="${tests.exclude-patterns}">
<include name="${tests.include}"/>
<patternset includes="${tests.include}"/>
<include name="${tests.platform}"/>
<exclude name="${tests.exclude}"/>
</fileset>
Expand Down
1 change: 1 addition & 0 deletions src/com/sun/jna/Native.java
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,7 @@ private static void loadLibraryInstance(Class<?> cls) {
if (field.getType() == cls
&& Modifier.isStatic(field.getModifiers())) {
// Ensure the field gets initialized by reading it
field.setAccessible(true); // interface might be private
libraries.put(cls, new WeakReference<Object>(field.get(null)));
break;
}
Expand Down
105 changes: 105 additions & 0 deletions test/com/sun/jna/different_package/PrivateDirectCallbacksTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/* Copyright (c) 2020 Florian Kistner, All Rights Reserved
*
* The contents of this file is dual-licensed under 2
* alternative Open Source/Free licenses: LGPL 2.1 or later and
* Apache License 2.0. (starting with JNA version 4.0.0).
*
* You can freely decide which license you want to apply to
* the project.
*
* You may obtain a copy of the LGPL License at:
*
* http://www.gnu.org/licenses/licenses.html
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "LGPL2.1".
*
* You may obtain a copy of the Apache License at:
*
* http://www.apache.org/licenses/
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "AL2.0".
*/
package com.sun.jna.different_package;

import com.sun.jna.*;
import junit.framework.TestCase;

public class PrivateDirectCallbacksTest extends TestCase {
private interface PrivateWithCallbackArgumentTestLibrary extends Library {
PrivateWithCallbackArgumentTestLibrary INSTANCE = new DirectPrivateWithCallbackArgumentTestLibrary();

interface VoidCallback extends Callback {
void callback();
}

void callVoidCallback(VoidCallback c);
}

private static class DirectPrivateWithCallbackArgumentTestLibrary implements PrivateWithCallbackArgumentTestLibrary {
@Override
public native void callVoidCallback(VoidCallback c);

static {
Native.register("testlib");
}
}

public void testCallVoidCallback() {
final boolean[] called = {false};
PrivateWithCallbackArgumentTestLibrary.VoidCallback cb = new PrivateWithCallbackArgumentTestLibrary.VoidCallback() {
@Override
public void callback() {
called[0] = true;
}
};
PrivateWithCallbackArgumentTestLibrary.INSTANCE.callVoidCallback(cb);
assertTrue("Callback not called", called[0]);
}

private interface PrivateWithCallbackReturnTestLibrary extends Library {
PrivateWithCallbackReturnTestLibrary INSTANCE = new DirectPrivateWithCallbackReturnTestLibrary();

interface Int32CallbackX extends Callback {
int callback(int arg);
}

Int32CallbackX returnCallback();

Int32CallbackX returnCallbackArgument(Int32CallbackX cb);
}

private static class DirectPrivateWithCallbackReturnTestLibrary implements PrivateWithCallbackReturnTestLibrary {
@Override
public native Int32CallbackX returnCallback();

@Override
public native Int32CallbackX returnCallbackArgument(Int32CallbackX cb);

static {
Native.register("testlib");
}
}

public void testInvokeCallback() {
PrivateWithCallbackReturnTestLibrary.Int32CallbackX cb = PrivateWithCallbackReturnTestLibrary.INSTANCE.returnCallback();
assertNotNull("Callback should not be null", cb);
assertEquals("Callback should be callable", 1, cb.callback(1));

PrivateWithCallbackReturnTestLibrary.Int32CallbackX cb2 = new PrivateWithCallbackReturnTestLibrary.Int32CallbackX() {
@Override
public int callback(int arg) {
return 0;
}
};
assertSame("Java callback should be looked up",
cb2, PrivateWithCallbackReturnTestLibrary.INSTANCE.returnCallbackArgument(cb2));
assertSame("Existing native function wrapper should be reused",
cb, PrivateWithCallbackReturnTestLibrary.INSTANCE.returnCallbackArgument(cb));
}

public static void main(java.lang.String[] argList) {
junit.textui.TestRunner.run(PrivateDirectCallbacksTest.class);
}
}
54 changes: 54 additions & 0 deletions test/com/sun/jna/different_package/PrivateLibraryInfoTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* Copyright (c) 2020 Florian Kistner, All Rights Reserved
*
* The contents of this file is dual-licensed under 2
* alternative Open Source/Free licenses: LGPL 2.1 or later and
* Apache License 2.0. (starting with JNA version 4.0.0).
*
* You can freely decide which license you want to apply to
* the project.
*
* You may obtain a copy of the LGPL License at:
*
* http://www.gnu.org/licenses/licenses.html
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "LGPL2.1".
*
* You may obtain a copy of the Apache License at:
*
* http://www.apache.org/licenses/
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "AL2.0".
*/
package com.sun.jna.different_package;

import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
import junit.framework.TestCase;

public class PrivateLibraryInfoTest extends TestCase {
private interface TestLibrary extends Library {
@SuppressWarnings("unused")
TestLibrary INSTANCE = new TestLibrary() {
};

interface VoidCallback extends Callback {
void callback();
}
}

public void testLibraryInfo() {
assertTrue(Native.getLibraryOptions(TestLibrary.class).containsKey(Library.OPTION_TYPE_MAPPER));
}

public void testCallbackLibraryInfo() {
TestLibrary.VoidCallback cb = new TestLibrary.VoidCallback() {
@Override
public void callback() {
}
};
assertTrue(Native.getLibraryOptions(cb.getClass()).containsKey(Library.OPTION_TYPE_MAPPER));
}
}

0 comments on commit 578220e

Please sign in to comment.