Restricted Methods

Some methods in the Foreign Function and Memory (FFM) API are unsafe and therefore restricted. If used incorrectly, restricted methods can crash the JVM and may silently result in memory corruption.

You must enable native access if an application calls any of the following restricted methods:

Table 12-1 Restricted Methods from the FFM API

Methods Reasoning Behind Restricting the Methods

java.lang.ModuleLayer.Controller.enableNativeAccess(Module)

The method enables native access for the specified module if the caller's module has native access. This method is restricted because it propagates privileges to call restricted methods.

AddressLayout.withTargetLayout(MemoryLayout)

Once you have an address layout with a given target layout, you can use it in a dereference operation, for example, MemorySegment.get(AddressLayout, long), to resize the segment being read, which is unsafe.

Linker.downcallHandle(FunctionDescriptor, Linker.Option...)

Linker.downcallHandle(MemorySegment, FunctionDescriptor, Linker.Option...)

Creating a downcall method handle is intrinsically unsafe. A linker has no way to verify that the provided function descriptor is compatible with the function being called.

A symbol in a foreign library does not typically contain enough signature information, such as arity and the types of foreign function parameters, to enable the linker at runtime to validate linkage requests. When a client interacts with a downcall method handle obtained through an invalid linkage request, for example, by specifying a function descriptor featuring too many argument layouts, the result of such an interaction is unspecified and can lead to JVM crashes.

Linker.upcallStub(MethodHandle, FunctionDescriptor, Arena, Linker.Option...)

As with creating downcall handles, the linker can't check whether the function pointer you are creating (like the qsort comparator in the example in Upcalls: Passing Java Code as a Function Pointer to a Foreign Function) is the correct one for the for the downcall you are passing it to (like the qsort method handle in the same example).

MemorySegment.reinterpret(long)

MemorySegment.reinterpret(long, Arena, Consumer<MemorySegment>)

MemorySegment.reinterpret(Arena, Consumer<MemorySegment>)

These methods allows you to change the size and lifetime of an existing segment by creating a new alias to the same region of memory. See Foreign Functions That Return Pointers for more information.

The spatial or temporal bounds associated with the memory segment alias returned by these methods might be incorrect. For example, consider a region of memory that's 10 bytes long that's backing a zero-length memory segment. An application might overestimate the size of the region and use MemorySegment::reinterpret to obtain a segment that's 100 bytes long. Later, this might result in attempts to dereference memory outside the bounds of the region, which might cause a JVM crash or, even worse, result in silent memory corruption.

SymbolLookup.libraryLookup(String, Arena)

SymbolLookup.libraryLookup(Path, Arena)

Loading a library can always cause execution of native code. For example, on Linux, they can be executed through dlopen hooks.

Enabling Native Access

To enable native access for specific modules on the module path, specify a comma-separated list of module names:

java --enable-native-access=M1,M2,... MyApp

To enable native access for all code on the class path, use the following command-line option:

java --enable-native-access=ALL-UNNAMED MyApp

You can also specify the --enable-native-access option as follows:

Enabling Native Access More Selectively

The --enable-native-access=ALL-UNNAMED option lifts native access restrictions for all classes on the class path. It’s recommended that you enable native access more selectively by moving JAR files that use the FFM API to the module path. This allows native access to be enabled for those JAR files specifically, not for the entire class path. You can move a JAR file from the class path to the module path without it being modularized. The Java runtime will treat it as an automatic module whose name is based on its file name. See Incremental Modularization with Automatic Modules.

Controlling the Effect of Native Access Restrictions

If native access is not enabled for a module, then it is illegal for code in that module to call a restricted method. You can specify what happens when such a module calls a restricted method by setting the --illegal-native-access command-line option to one of the following values:

  • allow: Allows the restricted operation to proceed.
  • warn: Allows the restricted operation to proceed and issues a warning the first time that an illegal native access occurs in a particular module. At most one warning per module is issued. This is the default value in JDK 24 and later.
  • deny: Throws an IllegalCallerException for every illegal native access operation. This will be the default value in a future release of the JDK.