Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8307615

Linker::nativeLinker should not be restricted (mainline)

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P2 P2
    • 21
    • core-libs
    • None
    • behavioral
    • minimal
    • Hide
      This change will likely pose no issues to existing clients of the FFM API, as it simply moves the restricted method checks. As such, existing clients which only use the native linker in safe ways (e.g. to interact with the linker's `defaultLookup`) might be able to do so w/o restricted method warnings.
      Show
      This change will likely pose no issues to existing clients of the FFM API, as it simply moves the restricted method checks. As such, existing clients which only use the native linker in safe ways (e.g. to interact with the linker's `defaultLookup`) might be able to do so w/o restricted method warnings.
    • Java API
    • SE

      Summary

      The method restriction on Linker::nativeLinker is too broad.

      Problem

      Restricted methods are implemented with caller sensitive methods (@CallerSensitive). When defining a new instance caller sensitive method, extra care must be taken, as all overridden implementations must, themselves, also be marked as caller sensitive. When the Foreign Linker API was first introduced, we had no way to enforce this constraint, given that Linker used to be a regular interface.

      Now that we have sealed interfaces, we can make sure that implementations of the Linker interface can only be defined within the JDK itself. As such, we can move the restricted method constraints where they belong, that is in the Linker::downcallHandle and Linker::upcallStub methods (which is where the integrity of the platform might be violated).

      Solution

      We propose the following API changes:

      • the Linker::nativeLinker factory should be marked as unrestricted;
      • the methods Linker::downcallHandle(FunctionDescriptor, Linker.Options...), Linker::downcallHandle(MemorySegment, FunctionDescriptor, Linker.Options...) and Linker::upcallStub(MethodHandle, FunctionDescriptor, Linker.Options...) should be marked as restricted.

      Specification

      Below is the javadoc of the affected methods (Note: the only changes are in the section documenting the method restrictions, as well as in the @throws clause, which, for restricted methods has to take IllegalCallerException into account):

          /**
           * 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.
           *
           * @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
           * linker are the native libraries loaded in the process where the Java runtime is currently executing. For example,
           * on Linux, these libraries typically include {@code libc}, {@code libm} and {@code libdl}.
           *
           * @return a linker for the ABI associated with the underlying native platform.
           * @throws UnsupportedOperationException if the underlying native platform is not supported.
           */
          static Linker nativeLinker() {
              return SharedUtils.getSystemLinker();
          }
          /**
           * Creates a method handle which is used to call a foreign function with the given signature and address.
           * <p>
           * Calling this method is equivalent to the following code:
           * {@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.
           * @param options  any linker options.
           * @return a downcall method handle. The method handle type is <a href="Linker.html#downcall-method-handles"><em>inferred</em></a>
           * @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.
           */
          @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.
           * <p>
           * The Java {@linkplain java.lang.invoke.MethodType method type} associated with the returned method handle is
           * {@linkplain FunctionDescriptor#toMethodType() derived} from the argument and return layouts in the function descriptor,
           * but features an additional leading parameter of type {@link MemorySegment}, from which the address of the target
           * foreign function is derived. Moreover, if the function descriptor's return layout is a group layout, the resulting
           * downcall method handle accepts an additional leading parameter of type {@link SegmentAllocator}, which is used by
           * the linker runtime to allocate the memory region associated with the struct returned by the downcall method handle.
           * <p>
           * Upon invoking a downcall method handle, the linker runtime will guarantee the following for any argument
           * {@code A} of type {@link MemorySegment} whose corresponding layout is an {@linkplain AddressLayout address layout}:
           * <ul>
           *     <li>{@code A.scope().isAlive() == true}. Otherwise, the invocation throws {@link IllegalStateException};</li>
           *     <li>The invocation occurs in a thread {@code T} such that {@code A.isAccessibleBy(T) == true}.
           *     Otherwise, the invocation throws {@link WrongThreadException}; and</li>
           *     <li>{@code A} is kept alive during the invocation. For instance, if {@code A} has been obtained using a
           *     {@linkplain Arena#ofShared()} shared arena}, any attempt to {@linkplain Arena#close() close}
           *     the shared arena while the downcall method handle is executing will result in an {@link IllegalStateException}.</li>
           *</ul>
           * <p>
           * Moreover, if the provided function descriptor's return layout is an {@linkplain AddressLayout address layout},
           * invoking the returned method handle will return a native segment associated with
           * a fresh scope that is always alive. Under normal conditions, the size of the returned segment is {@code 0}.
           * However, if the function descriptor's return layout has a {@linkplain AddressLayout#targetLayout()} {@code T},
           * then the size of the returned segment is set to {@code T.byteSize()}.
           * <p>
           * 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.
           * @return a downcall method handle. The method handle type is <a href="Linker.html#downcall-method-handles"><em>inferred</em></a>
           * 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);
         /**
           * Creates a stub which can be passed to other foreign functions as a function pointer, associated with the given
           * arena. Calling such a function pointer from foreign code will result in the execution of the provided
           * method handle.
           * <p>
           * The returned memory segment's address points to the newly allocated upcall stub, and is associated with
           * the provided arena. As such, the lifetime of the returned upcall stub segment is controlled by the
           * provided arena. For instance, if the provided arena is a confined arena, the returned
           * upcall stub segment will be deallocated when the provided confined arena is {@linkplain Arena#close() closed}.
           * <p>
           * An upcall stub argument whose corresponding layout is an {@linkplain AddressLayout address layout}
           * is a native segment associated with a fresh scope that is always alive.
           * Under normal conditions, the size of this segment argument is {@code 0}.
           * However, if the address layout has a {@linkplain AddressLayout#targetLayout()} {@code T}, then the size of the
           * segment argument is set to {@code T.byteSize()}.
           * <p>
           * The target method handle should not throw any exceptions. If the target method handle does throw an exception,
           * the VM will exit with a non-zero exit code. To avoid the VM aborting due to an uncaught exception, clients
           * 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.
           * @param arena the arena associated with the returned upcall stub segment.
           * @param options  any linker options.
           * @return a zero-length segment whose address is the address of the upcall stub.
           * @throws IllegalArgumentException if the provided function descriptor is not supported by this linker.
           * @throws IllegalArgumentException if it is determined that the target method handle can throw an exception, or if the target method handle
           * has a type that does not match the upcall stub <a href="Linker.html#upcall-stubs"><em>inferred type</em></a>.
           * @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);

            mcimadamore Maurizio Cimadamore
            mcimadamore Maurizio Cimadamore
            Jorn Vernee
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: