From c457499cb2122ff2d670d3732ca52d0a11c99671 Mon Sep 17 00:00:00 2001 From: Tanguy Leroux Date: Fri, 27 Feb 2015 15:49:57 +0100 Subject: [PATCH] [Native] Use direct mapping call in Kernel32Library This commit modifies the Kernel32Library to use direct mapping instead of a proxy class when doing native calls on Windows platforms. It also adds the "createSecurityManager" permission to the tests.policy file, and adds unit tests that should have failed when the Java security manager is enabled. Closes #9802 --- dev-tools/tests.policy | 2 + .../common/jna/Kernel32Library.java | 42 ++++++++++--------- ...l32LibraryTests.java => NativesTests.java} | 28 +++++++++---- 3 files changed, 44 insertions(+), 28 deletions(-) rename src/test/java/org/elasticsearch/common/jna/{Kernel32LibraryTests.java => NativesTests.java} (78%) diff --git a/dev-tools/tests.policy b/dev-tools/tests.policy index 8e485d7af1a..82e23fca6fd 100644 --- a/dev-tools/tests.policy +++ b/dev-tools/tests.policy @@ -70,7 +70,9 @@ grant { // needed by groovy scripting permission java.lang.RuntimePermission "getProtectionDomain"; + // needed for natives calls permission java.lang.RuntimePermission "loadLibrary.*"; + permission java.lang.RuntimePermission "createSecurityManager"; // reflection hacks: // needed for Striped64 (what is this doing), also enables unmap hack diff --git a/src/main/java/org/elasticsearch/common/jna/Kernel32Library.java b/src/main/java/org/elasticsearch/common/jna/Kernel32Library.java index 68005f1a3ca..386da4a5401 100644 --- a/src/main/java/org/elasticsearch/common/jna/Kernel32Library.java +++ b/src/main/java/org/elasticsearch/common/jna/Kernel32Library.java @@ -20,7 +20,6 @@ package org.elasticsearch.common.jna; import com.google.common.collect.ImmutableList; -import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.win32.StdCallLibrary; import org.elasticsearch.common.logging.ESLogger; @@ -37,17 +36,18 @@ public class Kernel32Library { private static ESLogger logger = Loggers.getLogger(Kernel32Library.class); - private Kernel32 internal; - + // Callbacks must be kept around in order to be able to be called later, + // when the Windows ConsoleCtrlHandler sends an event. private List callbacks = new ArrayList<>(); + // Native library instance must be kept around for the same reason. private final static class Holder { private final static Kernel32Library instance = new Kernel32Library(); } private Kernel32Library() { try { - internal = (Kernel32)Native.synchronizedLibrary((Kernel32)Native.loadLibrary("kernel32", Kernel32.class)); + Native.register("kernel32"); logger.debug("windows/Kernel32 library loaded"); } catch (NoClassDefFoundError e) { logger.warn("JNA not found. native methods and handlers will be disabled."); @@ -60,14 +60,19 @@ public class Kernel32Library { return Holder.instance; } + /** + * Adds a Console Ctrl Handler. + * + * @param handler + * @return true if the handler is correctly set + * @throws java.lang.UnsatisfiedLinkError if the Kernel32 library is not loaded or if the native function is not found + * @throws java.lang.NoClassDefFoundError if the library for native calls is missing + */ public boolean addConsoleCtrlHandler(ConsoleCtrlHandler handler) { - if (internal == null) { - throw new UnsupportedOperationException("windows/Kernel32 library not loaded, console ctrl handler cannot be set"); - } boolean result = false; if (handler != null) { NativeHandlerCallback callback = new NativeHandlerCallback(handler); - result = internal.SetConsoleCtrlHandler(callback, true); + result = SetConsoleCtrlHandler(callback, true); if (result) { callbacks.add(callback); } @@ -79,17 +84,16 @@ public class Kernel32Library { return ImmutableList.builder().addAll(callbacks).build(); } - interface Kernel32 extends Library { - - /** - * Registers a Console Ctrl Handler. - * - * @param handler - * @param add - * @return true if the handler is correctly set - */ - public boolean SetConsoleCtrlHandler(StdCallLibrary.StdCallCallback handler, boolean add); - } + /** + * Native call to the Kernel32 API to set a new Console Ctrl Handler. + * + * @param handler + * @param add + * @return true if the handler is correctly set + * @throws java.lang.UnsatisfiedLinkError if the Kernel32 library is not loaded or if the native function is not found + * @throws java.lang.NoClassDefFoundError if the library for native calls is missing + */ + public native boolean SetConsoleCtrlHandler(StdCallLibrary.StdCallCallback handler, boolean add); /** * Handles consoles event with WIN API diff --git a/src/test/java/org/elasticsearch/common/jna/Kernel32LibraryTests.java b/src/test/java/org/elasticsearch/common/jna/NativesTests.java similarity index 78% rename from src/test/java/org/elasticsearch/common/jna/Kernel32LibraryTests.java rename to src/test/java/org/elasticsearch/common/jna/NativesTests.java index 089cfe0663f..6c99f1132fb 100644 --- a/src/test/java/org/elasticsearch/common/jna/Kernel32LibraryTests.java +++ b/src/test/java/org/elasticsearch/common/jna/NativesTests.java @@ -20,7 +20,6 @@ package org.elasticsearch.common.jna; import org.apache.lucene.util.Constants; -import org.apache.lucene.util.LuceneTestCase.AwaitsFix; import org.elasticsearch.common.jna.Kernel32Library.ConsoleCtrlHandler; import org.elasticsearch.test.ElasticsearchTestCase; import org.junit.After; @@ -32,8 +31,7 @@ import java.util.Map; import static org.hamcrest.Matchers.equalTo; -@AwaitsFix(bugUrl = "https://github.com/elasticsearch/elasticsearch/issues/9802") -public class Kernel32LibraryTests extends ElasticsearchTestCase { +public class NativesTests extends ElasticsearchTestCase { /** * Those properties are set by the JNA Api and if not ignored, @@ -65,7 +63,16 @@ public class Kernel32LibraryTests extends ElasticsearchTestCase { } @Test - public void testKernel32Library() { + public void testTryMlockall() { + Natives.tryMlockall(); + + if (Constants.WINDOWS) { + assertFalse("Memory locking is not available on Windows platforms", Natives.LOCAL_MLOCKALL); + } + } + + @Test + public void testAddConsoleCtrlHandler() { ConsoleCtrlHandler handler = new ConsoleCtrlHandler() { @Override public boolean handle(int code) { @@ -73,18 +80,21 @@ public class Kernel32LibraryTests extends ElasticsearchTestCase { } }; - assertNotNull(Kernel32Library.getInstance()); - assertThat(Kernel32Library.getInstance().getCallbacks().size(), equalTo(0)); + Natives.addConsoleCtrlHandler(handler); if (Constants.WINDOWS) { - assertTrue(Kernel32Library.getInstance().addConsoleCtrlHandler(handler)); + assertNotNull(Kernel32Library.getInstance()); assertThat(Kernel32Library.getInstance().getCallbacks().size(), equalTo(1)); + } else { + assertNotNull(Kernel32Library.getInstance()); + assertThat(Kernel32Library.getInstance().getCallbacks().size(), equalTo(0)); + try { Kernel32Library.getInstance().addConsoleCtrlHandler(handler); fail("should have thrown an unsupported operation exception"); - } catch (UnsupportedOperationException e) { - assertThat(e.getMessage(), e.getMessage().contains("console ctrl handler cannot be set"), equalTo(true)); + } catch (UnsatisfiedLinkError e) { + // UnsatisfiedLinkError is expected } } }