[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
This commit is contained in:
Tanguy Leroux 2015-02-27 15:49:57 +01:00
parent a90e5c03b7
commit c457499cb2
3 changed files with 44 additions and 28 deletions

View File

@ -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

View File

@ -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<NativeHandlerCallback> 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

View File

@ -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
}
}
}