制限されるメソッド

外部関数およびメモリー(FFM) APIの一部のメソッドは安全ではないため、制限されます。制限されたメソッドは、正しく使用しないと、JVMをクラッシュさせ、メモリーの破損につながる可能性があります(エラーは表示されません)。

実行するアプリケーションで、次に示す制限されたメソッドのいずれかが呼び出されると、Javaランタイムによって警告メッセージが出力されます:モジュールMのコードで、これらの制限されたメソッドまたは安全でないメソッドを警告が表示されずに使用できるようにするには、--enable-native-access=Mコマンドライン・オプションを指定します。複数のモジュールはカンマ区切りリストで指定します。クラス・パス上のすべてのコードで警告なしの使用を可能にするには、--enable-native-access=ALL-UNNAMEDオプションを指定します。

表12-1 FFM APIの制限されたメソッド

メソッド メソッドが制限される理由

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

メソッドは、呼出し元のモジュールにネイティブ・アクセスがある場合に、指定されたモジュールのネイティブ・アクセスを有効にします。このメソッドは、制限されたメソッドを呼び出す権限を伝播するため、制限されています。

AddressLayout.withTargetLayout(MemoryLayout)

特定のターゲット・レイアウトでアドレス・レイアウトを作成したら、それを参照解除操作(MemorySegment.get(AddressLayout, longなど)で使用して、読取り対象のセグメントをサイズ変更できますが、これは安全ではありません。

Linker.downcallhandle(FunctionDescriptor, Linker.Option...)

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

ダウンコール・メソッド・ハンドルの作成は、本質的に安全ではありません。リンカーには、指定された関数ディスクリプタが呼び出される関数と互換であることを検証する方法がありません。

通常、外部ライブラリのシンボルには、十分なシグネチャ情報(外部関数パラメータの個数や型など)が含まれていないため、リンカーが実行時にリンク要求を検証できません。クライアントがやり取りするダウンコール・メソッド・ハンドルが、無効なリンク要求によって取得されていたとき(たとえば、指定した関数ディスクリプタの引数レイアウトが多すぎた場合など)、このようなやり取りの結果は未指定となり、JVMがクラッシュする可能性があります。

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

ダウンコール・ハンドルの作成と同様に、リンカーは、作成する関数ポインタ(「アップコール: Javaコードを関数ポインタとして外部関数に渡す」の例のqsortコンパレータなど)が、それを渡すダウンコール(同じ例のqsortメソッド・ハンドルなど)の正しいポインタかどうかを確認できません。

MemorySegment.reinterpret(long)

MemorySegment.reinterpret(long, Arena, Consumer)

MemorySegment.reinterpret(Arena, Consumer)

これらのメソッドを使用すると、メモリーの同じ領域に新しい別名を作成することで、既存のセグメントのサイズと存続期間を変更できます。詳細は、「ポインタを返す外部関数」を参照してください。

これらのメソッドによって返されるメモリー・セグメント別名に関連付けられた空間的または時間的な境界が正しくない可能性があります。たとえば、長さが10バイトのメモリー領域が長さゼロのメモリー・セグメントを支えているとします。アプリケーションはリージョンのサイズを過大評価し、MemorySegment::reinterpretを使用して100バイトの長さのセグメントを取得する可能性があります。このために、後で領域の境界外のメモリーへの逆参照が試行される可能性があり、JVMクラッシュが発生したり、さらにはエラーが表示されずにメモリーが破損したりすることさえあります。

SymbolLookup.libraryLookup(String, Arena)

SymbolLookup.libraryLookup(Path, Arena)

ライブラリをロードすると、常にネイティブ・コードが実行される可能性があります。たとえば、Linuxでは、dlopenフックを使用して実行できます。