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 |
---|---|
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. | |
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>) |
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. |
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:
- Set it in the environment variable JDK_JAVA_OPTIONS. See Using the JDK_JAVA_OPTIONS Launcher Environment Variable.
- Specify it in a command-line argument file. See java Command-Line Argument Files.
- Add
Enable-Native-Access: ALL-UNNAMED
to the manifest of an executable JAR file. See JAR Manifest. - If you have created a custom runtime for your application, specify it in the
jlink command through the
--add-options
plugin. Run the commandjlink –list-plugins
for a list of available plugins. - If your code creates modules dynamically, enable native access for them with the ModuleLayer.Controller::enableNativeAccess method. Code can dynamically check if its module has native access with the Module::isNativeAccessEnabled method.
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.