8307610: Linker::nativeLinker should not be restricted (mainline)
Reviewed-by: jvernee
This commit is contained in:
parent
ecc1d85dbe
commit
ba9714d44c
src/java.base/share/classes
test/jdk/java/foreign
enablenativeaccess
org/openjdk/foreigntest
panama_module/org/openjdk/foreigntest
handles
invoker_module/handle/invoker
lookup_module/handle/lookup
@ -430,11 +430,6 @@ public sealed interface Linker permits AbstractLinker {
|
||||
/**
|
||||
* Returns a linker for the ABI associated with the underlying native platform. The underlying native platform
|
||||
* is the combination of OS and processor where the Java runtime is currently executing.
|
||||
* <p>
|
||||
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
|
||||
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
|
||||
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
|
||||
* restricted methods, and use safe and supported functionalities, where possible.
|
||||
*
|
||||
* @apiNote It is not currently possible to obtain a linker for a different combination of OS and processor.
|
||||
* @implNote The libraries exposed by the {@linkplain #defaultLookup() default lookup} associated with the returned
|
||||
@ -443,11 +438,8 @@ public sealed interface Linker permits AbstractLinker {
|
||||
*
|
||||
* @return a linker for the ABI associated with the underlying native platform.
|
||||
* @throws UnsupportedOperationException if the underlying native platform is not supported.
|
||||
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled.
|
||||
*/
|
||||
@CallerSensitive
|
||||
static Linker nativeLinker() {
|
||||
Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "nativeLinker");
|
||||
return SharedUtils.getSystemLinker();
|
||||
}
|
||||
|
||||
@ -458,6 +450,11 @@ public sealed interface Linker permits AbstractLinker {
|
||||
* {@snippet lang=java :
|
||||
* linker.downcallHandle(function).bindTo(symbol);
|
||||
* }
|
||||
* <p>
|
||||
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
|
||||
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
|
||||
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
|
||||
* restricted methods, and use safe and supported functionalities, where possible.
|
||||
*
|
||||
* @param symbol the address of the target function.
|
||||
* @param function the function descriptor of the target function.
|
||||
@ -466,11 +463,10 @@ public sealed interface Linker permits AbstractLinker {
|
||||
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker.
|
||||
* or if the symbol is {@link MemorySegment#NULL}
|
||||
* @throws IllegalArgumentException if an invalid combination of linker options is given.
|
||||
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled.
|
||||
*/
|
||||
default MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Option... options) {
|
||||
SharedUtils.checkSymbol(symbol);
|
||||
return downcallHandle(function, options).bindTo(symbol);
|
||||
}
|
||||
@CallerSensitive
|
||||
MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Option... options);
|
||||
|
||||
/**
|
||||
* Creates a method handle which is used to call a foreign function with the given signature.
|
||||
@ -502,6 +498,11 @@ public sealed interface Linker permits AbstractLinker {
|
||||
* The returned method handle will throw an {@link IllegalArgumentException} if the {@link MemorySegment}
|
||||
* representing the target address of the foreign function is the {@link MemorySegment#NULL} address.
|
||||
* The returned method handle will additionally throw {@link NullPointerException} if any argument passed to it is {@code null}.
|
||||
* <p>
|
||||
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
|
||||
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
|
||||
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
|
||||
* restricted methods, and use safe and supported functionalities, where possible.
|
||||
*
|
||||
* @param function the function descriptor of the target function.
|
||||
* @param options any linker options.
|
||||
@ -509,7 +510,9 @@ public sealed interface Linker permits AbstractLinker {
|
||||
* from the provided function descriptor.
|
||||
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker.
|
||||
* @throws IllegalArgumentException if an invalid combination of linker options is given.
|
||||
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled.
|
||||
*/
|
||||
@CallerSensitive
|
||||
MethodHandle downcallHandle(FunctionDescriptor function, Option... options);
|
||||
|
||||
/**
|
||||
@ -533,6 +536,11 @@ public sealed interface Linker permits AbstractLinker {
|
||||
* could wrap all code in the target method handle in a try/catch block that catches any {@link Throwable}, for
|
||||
* instance by using the {@link java.lang.invoke.MethodHandles#catchException(MethodHandle, Class, MethodHandle)}
|
||||
* method handle combinator, and handle exceptions as desired in the corresponding catch block.
|
||||
* <p>
|
||||
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
|
||||
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
|
||||
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
|
||||
* restricted methods, and use safe and supported functionalities, where possible.
|
||||
*
|
||||
* @param target the target method handle.
|
||||
* @param function the upcall stub function descriptor.
|
||||
@ -545,7 +553,9 @@ public sealed interface Linker permits AbstractLinker {
|
||||
* @throws IllegalStateException if {@code arena.scope().isAlive() == false}
|
||||
* @throws WrongThreadException if {@code arena} is a confined arena, and this method is called from a
|
||||
* thread {@code T}, other than the arena's owner thread.
|
||||
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled.
|
||||
*/
|
||||
@CallerSensitive
|
||||
MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, Arena arena, Linker.Option... options);
|
||||
|
||||
/**
|
||||
|
@ -34,6 +34,8 @@ import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker;
|
||||
import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker;
|
||||
import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker;
|
||||
import jdk.internal.foreign.layout.AbstractLayout;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
|
||||
import java.lang.foreign.AddressLayout;
|
||||
import java.lang.foreign.GroupLayout;
|
||||
@ -67,7 +69,21 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
|
||||
private final SoftReferenceCache<LinkRequest, UpcallStubFactory> UPCALL_CACHE = new SoftReferenceCache<>();
|
||||
|
||||
@Override
|
||||
public MethodHandle downcallHandle(FunctionDescriptor function, Option... options) {
|
||||
@CallerSensitive
|
||||
public final MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Option... options) {
|
||||
Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "downcallHandle");
|
||||
SharedUtils.checkSymbol(symbol);
|
||||
return downcallHandle0(function, options).bindTo(symbol);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CallerSensitive
|
||||
public final MethodHandle downcallHandle(FunctionDescriptor function, Option... options) {
|
||||
Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "downcallHandle");
|
||||
return downcallHandle0(function, options);
|
||||
}
|
||||
|
||||
private final MethodHandle downcallHandle0(FunctionDescriptor function, Option... options) {
|
||||
Objects.requireNonNull(function);
|
||||
Objects.requireNonNull(options);
|
||||
checkLayouts(function);
|
||||
@ -82,10 +98,13 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
|
||||
return handle;
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options);
|
||||
|
||||
@Override
|
||||
public MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, Arena arena, Linker.Option... options) {
|
||||
@CallerSensitive
|
||||
public final MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, Arena arena, Linker.Option... options) {
|
||||
Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "upcallStub");
|
||||
Objects.requireNonNull(arena);
|
||||
Objects.requireNonNull(target);
|
||||
Objects.requireNonNull(function);
|
||||
|
@ -24,6 +24,8 @@
|
||||
package org.openjdk.foreigntest;
|
||||
|
||||
import java.lang.foreign.*;
|
||||
import java.lang.foreign.Linker.Option;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Method;
|
||||
@ -36,31 +38,25 @@ public class PanamaMainUnnamedModule {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
testReflection();
|
||||
testSetAccessible();
|
||||
testInvoke();
|
||||
testDirectAccess();
|
||||
testJNIAccess();
|
||||
}
|
||||
|
||||
public static void testReflection() throws Throwable {
|
||||
Method method = Linker.class.getDeclaredMethod("nativeLinker");
|
||||
method.invoke(null);
|
||||
}
|
||||
|
||||
public static void testSetAccessible() throws Throwable {
|
||||
Method method = Linker.class.getDeclaredMethod("nativeLinker");
|
||||
method.setAccessible(true);
|
||||
method.invoke(null);
|
||||
Linker linker = Linker.nativeLinker();
|
||||
Method method = Linker.class.getDeclaredMethod("downcallHandle", FunctionDescriptor.class, Option[].class);
|
||||
method.invoke(linker, FunctionDescriptor.ofVoid(), new Linker.Option[0]);
|
||||
}
|
||||
|
||||
public static void testInvoke() throws Throwable {
|
||||
var mh = MethodHandles.lookup().findStatic(Linker.class, "nativeLinker",
|
||||
MethodType.methodType(Linker.class));
|
||||
var linker = (Linker)mh.invokeExact();
|
||||
var mh = MethodHandles.lookup().findVirtual(Linker.class, "downcallHandle",
|
||||
MethodType.methodType(MethodHandle.class, FunctionDescriptor.class, Linker.Option[].class));
|
||||
var downcall = (MethodHandle)mh.invokeExact(Linker.nativeLinker(), FunctionDescriptor.ofVoid(), new Linker.Option[0]);
|
||||
}
|
||||
|
||||
public static void testDirectAccess() {
|
||||
Linker.nativeLinker();
|
||||
Linker.nativeLinker().downcallHandle(FunctionDescriptor.ofVoid());
|
||||
}
|
||||
|
||||
public static void testJNIAccess() {
|
||||
|
@ -27,8 +27,8 @@ import java.lang.foreign.*;
|
||||
|
||||
public class PanamaMain {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Trying to get Linker");
|
||||
Linker.nativeLinker();
|
||||
System.out.println("Got Linker");
|
||||
System.out.println("Trying to obtain a downcall handle");
|
||||
Linker.nativeLinker().downcallHandle(FunctionDescriptor.ofVoid());
|
||||
System.out.println("Got downcall handle");
|
||||
}
|
||||
}
|
||||
|
6
test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainDirect.java
6
test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainDirect.java
@ -33,9 +33,9 @@ public class PanamaMainDirect {
|
||||
}
|
||||
|
||||
public static void testDirectAccessCLinker() {
|
||||
System.out.println("Trying to get Linker");
|
||||
Linker.nativeLinker();
|
||||
System.out.println("Got Linker");
|
||||
System.out.println("Trying to obtain a downcall handle");
|
||||
Linker.nativeLinker().downcallHandle(FunctionDescriptor.ofVoid());
|
||||
System.out.println("Got downcall handle");
|
||||
}
|
||||
|
||||
public static void testDirectAccessMemorySegment() {
|
||||
|
11
test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainInvoke.java
11
test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainInvoke.java
@ -34,11 +34,12 @@ public class PanamaMainInvoke {
|
||||
}
|
||||
|
||||
public static void testInvokenativeLinker() throws Throwable {
|
||||
System.out.println("Trying to get Linker");
|
||||
var mh = MethodHandles.lookup().findStatic(Linker.class, "nativeLinker",
|
||||
MethodType.methodType(Linker.class));
|
||||
var linker = (Linker)mh.invokeExact();
|
||||
System.out.println("Got Linker");
|
||||
Linker linker = Linker.nativeLinker();
|
||||
System.out.println("Trying to obtain a downcall handle");
|
||||
var mh = MethodHandles.lookup().findVirtual(Linker.class, "downcallHandle",
|
||||
MethodType.methodType(MethodHandle.class, FunctionDescriptor.class, Linker.Option[].class));
|
||||
var handle = (MethodHandle)mh.invokeExact(linker, FunctionDescriptor.ofVoid(), new Linker.Option[0]);
|
||||
System.out.println("Got downcall handle");
|
||||
}
|
||||
|
||||
public static void testInvokeMemorySegment() throws Throwable {
|
||||
|
11
test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainJNI.java
11
test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainJNI.java
@ -1,5 +1,8 @@
|
||||
package org.openjdk.foreigntest;
|
||||
|
||||
import java.lang.foreign.FunctionDescriptor;
|
||||
import java.lang.foreign.Linker;
|
||||
|
||||
public class PanamaMainJNI {
|
||||
|
||||
static {
|
||||
@ -11,10 +14,10 @@ public class PanamaMainJNI {
|
||||
}
|
||||
|
||||
public static void testDirectAccessCLinker() {
|
||||
System.out.println("Trying to get Linker");
|
||||
nativeLinker0();
|
||||
System.out.println("Got Linker");
|
||||
System.out.println("Trying to get downcall handle");
|
||||
nativeLinker0(Linker.nativeLinker(), FunctionDescriptor.ofVoid(), new Linker.Option[0]);
|
||||
System.out.println("Got downcall handle");
|
||||
}
|
||||
|
||||
static native void nativeLinker0();
|
||||
static native void nativeLinker0(Linker linker, FunctionDescriptor desc, Linker.Option[] options);
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ package org.openjdk.foreigntest;
|
||||
|
||||
import java.lang.foreign.*;
|
||||
import java.lang.foreign.Arena;
|
||||
import java.lang.foreign.Linker.Option;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class PanamaMainReflection {
|
||||
@ -34,10 +35,11 @@ public class PanamaMainReflection {
|
||||
}
|
||||
|
||||
public static void testReflectionnativeLinker() throws Throwable {
|
||||
System.out.println("Trying to get Linker");
|
||||
Method method = Linker.class.getDeclaredMethod("nativeLinker");
|
||||
method.invoke(null);
|
||||
System.out.println("Got Linker");
|
||||
Linker linker = Linker.nativeLinker();
|
||||
System.out.println("Trying to get downcall handle");
|
||||
Method method = Linker.class.getDeclaredMethod("downcallHandle", FunctionDescriptor.class, Option[].class);
|
||||
method.invoke(linker, FunctionDescriptor.ofVoid(), new Linker.Option[0]);
|
||||
System.out.println("Got downcall handle");
|
||||
}
|
||||
|
||||
public static void testReflectionMemorySegment() throws Throwable {
|
||||
|
@ -25,21 +25,32 @@
|
||||
#include "jni.h"
|
||||
#include "testlib_threads.h"
|
||||
|
||||
void call(void* ctxt) {
|
||||
JavaVM *jvm = (JavaVM*) ctxt;
|
||||
typedef struct {
|
||||
JavaVM* jvm;
|
||||
jobject linker;
|
||||
jobject desc;
|
||||
jarray opts;
|
||||
} Context;
|
||||
|
||||
void call(void* arg) {
|
||||
Context* context = (Context*)arg;
|
||||
JNIEnv* env;
|
||||
jvm->AttachCurrentThread((void**)&env, NULL);
|
||||
context->jvm->AttachCurrentThread((void**)&env, NULL);
|
||||
jclass linkerClass = env->FindClass("java/lang/foreign/Linker");
|
||||
jmethodID nativeLinkerMethod = env->GetStaticMethodID(linkerClass, "nativeLinker", "()Ljava/lang/foreign/Linker;");
|
||||
env->CallStaticVoidMethod(linkerClass, nativeLinkerMethod);
|
||||
jvm->DetachCurrentThread();
|
||||
jmethodID nativeLinkerMethod = env->GetMethodID(linkerClass, "downcallHandle",
|
||||
"(Ljava/lang/foreign/FunctionDescriptor;[Ljava/lang/foreign/Linker$Option;)Ljava/lang/invoke/MethodHandle;");
|
||||
env->CallVoidMethod(context->linker, nativeLinkerMethod, context->desc, context->opts);
|
||||
context->jvm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_openjdk_foreigntest_PanamaMainJNI_nativeLinker0(JNIEnv *env, jclass cls) {
|
||||
JavaVM* jvm;
|
||||
env->GetJavaVM(&jvm);
|
||||
run_in_new_thread_and_join(call, jvm);
|
||||
Java_org_openjdk_foreigntest_PanamaMainJNI_nativeLinker0(JNIEnv *env, jclass cls, jobject linker, jobject desc, jarray opts) {
|
||||
Context context;
|
||||
env->GetJavaVM(&context.jvm);
|
||||
context.linker = linker;
|
||||
context.desc = desc;
|
||||
context.opts = opts;
|
||||
run_in_new_thread_and_join(call, &context);
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ public class MethodHandleInvoker {
|
||||
|
||||
static final Map<Class<?>, Object> DEFAULT_VALUES = new HashMap<>();
|
||||
|
||||
static <Z> void addDefaultMapping(Class<Z> carrier, Z value) {
|
||||
static void addDefaultMapping(Class<?> carrier, Object value) {
|
||||
DEFAULT_VALUES.put(carrier, value);
|
||||
}
|
||||
|
||||
@ -67,7 +67,7 @@ public class MethodHandleInvoker {
|
||||
addDefaultMapping(Linker.class, Linker.nativeLinker());
|
||||
addDefaultMapping(Path.class, Path.of("nonExistent"));
|
||||
addDefaultMapping(String.class, "Hello!");
|
||||
addDefaultMapping(Runnable.class, () -> {});
|
||||
addDefaultMapping(Runnable.class, (Runnable)() -> {});
|
||||
addDefaultMapping(MethodHandle.class, MethodHandles.identity(int.class));
|
||||
addDefaultMapping(Charset.class, Charset.defaultCharset());
|
||||
addDefaultMapping(MethodType.class, MethodType.methodType(void.class));
|
||||
@ -88,6 +88,8 @@ public class MethodHandleInvoker {
|
||||
addDefaultMapping(AddressLayout.class, ValueLayout.ADDRESS);
|
||||
addDefaultMapping(SymbolLookup.class, SymbolLookup.loaderLookup());
|
||||
addDefaultMapping(Consumer.class, (Consumer<Object>)(Object o) -> {});
|
||||
addDefaultMapping(FunctionDescriptor.class, FunctionDescriptor.ofVoid());
|
||||
addDefaultMapping(Linker.Option[].class, null);
|
||||
addDefaultMapping(byte.class, (byte)0);
|
||||
addDefaultMapping(boolean.class, true);
|
||||
addDefaultMapping(char.class, (char)0);
|
||||
@ -105,10 +107,9 @@ public class MethodHandleInvoker {
|
||||
}
|
||||
|
||||
static Object makeArg(Class<?> clazz) {
|
||||
Object value = DEFAULT_VALUES.get(clazz);
|
||||
if (value == null) {
|
||||
if (!DEFAULT_VALUES.containsKey(clazz)) {
|
||||
throw new UnsupportedOperationException(clazz.getName());
|
||||
}
|
||||
return value;
|
||||
return DEFAULT_VALUES.get(clazz);
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
import java.lang.foreign.FunctionDescriptor;
|
||||
import java.lang.foreign.MemorySegment;
|
||||
import java.lang.foreign.SymbolLookup;
|
||||
|
||||
@ -49,8 +50,12 @@ public class MethodHandleLookup {
|
||||
static Object[][] restrictedMethods() {
|
||||
try {
|
||||
return new Object[][]{
|
||||
{ MethodHandles.lookup().findStatic(Linker.class, "nativeLinker",
|
||||
MethodType.methodType(Linker.class)), "Linker::nativeLinker" },
|
||||
{ MethodHandles.lookup().findVirtual(Linker.class, "downcallHandle",
|
||||
MethodType.methodType(MethodHandle.class, FunctionDescriptor.class, Linker.Option[].class)), "Linker::downcallHandle/1" },
|
||||
{ MethodHandles.lookup().findVirtual(Linker.class, "downcallHandle",
|
||||
MethodType.methodType(MethodHandle.class, MemorySegment.class, FunctionDescriptor.class, Linker.Option[].class)), "Linker::downcallHandle/2" },
|
||||
{ MethodHandles.lookup().findVirtual(Linker.class, "upcallStub",
|
||||
MethodType.methodType(MemorySegment.class, MethodHandle.class, FunctionDescriptor.class, Arena.class, Linker.Option[].class)), "Linker::upcallStub" },
|
||||
{ MethodHandles.lookup().findVirtual(MemorySegment.class, "reinterpret",
|
||||
MethodType.methodType(MemorySegment.class, long.class)),
|
||||
"MemorySegment::reinterpret/1" },
|
||||
|
Loading…
x
Reference in New Issue
Block a user