From d48f7913df92c62cce3e93ba4afb5649af18a1fd Mon Sep 17 00:00:00 2001 From: Florian Kistner Date: Thu, 3 Dec 2020 13:55:32 +0100 Subject: [PATCH 1/2] Fix illegal access exceptions, when retrieving options for private library 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. --- build.xml | 4 +- src/com/sun/jna/Native.java | 1 + .../PrivateDirectCallbacksTest.java | 82 +++++++++++++++++++ .../PrivateLibraryInfoTest.java | 31 +++++++ 4 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 test/com/sun/jna/different_package/PrivateDirectCallbacksTest.java create mode 100644 test/com/sun/jna/different_package/PrivateLibraryInfoTest.java diff --git a/build.xml b/build.xml index 32b1c5d870..f9d96f6320 100644 --- a/build.xml +++ b/build.xml @@ -1256,7 +1256,7 @@ cd .. - + @@ -1282,7 +1282,7 @@ cd .. - + diff --git a/src/com/sun/jna/Native.java b/src/com/sun/jna/Native.java index 0cf39faf40..fa32c89df9 100644 --- a/src/com/sun/jna/Native.java +++ b/src/com/sun/jna/Native.java @@ -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(field.get(null))); break; } diff --git a/test/com/sun/jna/different_package/PrivateDirectCallbacksTest.java b/test/com/sun/jna/different_package/PrivateDirectCallbacksTest.java new file mode 100644 index 0000000000..bbd38b899c --- /dev/null +++ b/test/com/sun/jna/different_package/PrivateDirectCallbacksTest.java @@ -0,0 +1,82 @@ +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); + } +} diff --git a/test/com/sun/jna/different_package/PrivateLibraryInfoTest.java b/test/com/sun/jna/different_package/PrivateLibraryInfoTest.java new file mode 100644 index 0000000000..83bfe6663f --- /dev/null +++ b/test/com/sun/jna/different_package/PrivateLibraryInfoTest.java @@ -0,0 +1,31 @@ +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)); + } +} From 3f19a5c38bceb1bd5343b1fcb325f4267f47fd03 Mon Sep 17 00:00:00 2001 From: Florian Kistner Date: Thu, 3 Dec 2020 16:51:39 +0100 Subject: [PATCH 2/2] Add required copyright notice and document in CHANGES --- CHANGES.md | 1 + .../PrivateDirectCallbacksTest.java | 23 +++++++++++++++++++ .../PrivateLibraryInfoTest.java | 23 +++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 3438291585..3673fbd6f8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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 ============= diff --git a/test/com/sun/jna/different_package/PrivateDirectCallbacksTest.java b/test/com/sun/jna/different_package/PrivateDirectCallbacksTest.java index bbd38b899c..60e88c0974 100644 --- a/test/com/sun/jna/different_package/PrivateDirectCallbacksTest.java +++ b/test/com/sun/jna/different_package/PrivateDirectCallbacksTest.java @@ -1,3 +1,26 @@ +/* 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.*; diff --git a/test/com/sun/jna/different_package/PrivateLibraryInfoTest.java b/test/com/sun/jna/different_package/PrivateLibraryInfoTest.java index 83bfe6663f..3f782ce899 100644 --- a/test/com/sun/jna/different_package/PrivateLibraryInfoTest.java +++ b/test/com/sun/jna/different_package/PrivateLibraryInfoTest.java @@ -1,3 +1,26 @@ +/* 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;