VCSSLの最新版をリリース、Java24上での非互換な挙動に対処

RINEARN では先日、VCSSLの最新版 Ver.3.4.50 をリリースしました。以下のページからダウンロードできます:

今回のリリースは機能追加ではなく、「Java 24 環境上において、それ以前の環境と微妙に変わってしまう挙動」への対処がメインです。

以下、詳細をお知らせいたします。

追記:

本件の原因となっていた Java 側の挙動変化については、一応 Java Bug Database にもレポートを提出し、 Issue「JDK-8355342: File.getCanonicalPath on Java 24 resolves paths on network drives to UNC format」として受理されました。 まだ修正時期は確定していませんが、そのうち修正されるかもしれません。

ご対応いただいている OpenJDK コミュニティの方々には、この場をお借りして御礼申し上げます。 また、一緒に本件レポートの作成や提出を手厚く手伝ってくれた ChatGPT の GPT-4o さんにも御礼申し上げます(別の機会にまた詳しく記事にしたいです)。

- Table of Contents -

先月リリースされた「Java 24」

Java 24 のリリース

VCSSLのインタープリタはJava言語で実装されており、Java言語の実行環境(Java仮想マシン)上で動作します。 その土台となるJava言語は、(一時期は停滞していましたが)近年は開発が活発化していて更新ペースが速く、概ね半年ごと(春と秋)にメジャーバージョンアップします。

そして先月、Java言語&環境の最新メジャーアップデート版である Java 24 がリリースされました。

メジャーアップデートでは一部挙動が変わる場合がある

Java言語環境のメジャーアップデートでは、既存コードの挙動が変わってしまう事が一応あり得ます。 Java言語では、そのような破壊的変更はなるべく生じないように配慮されているのですが、それでも「挙動が実装依存」とされているような処理の振る舞い変わってしまうケースがたまにあります。

となると、そのJava言語の実行環境上で走る、VCSSL実行環境やその他Java製アプリケーションの挙動も、つられて変化してしまう事がしばしば生じ得ます。

たとえば近年で特にインパクトが大きかった挙動変更の例としては、数年前の「デフォルトの文字コードの UTF-8 化」がありました。そのままだと文字化けが生じ得る既存処理があったので、結構幅広い対処が必要でした。

今回は、実際に微妙に変わってしまった挙動を、過去の環境と(なるべく)同じにするための対策版

今回もそうで、詳細は後ほど解説しますが、どうも 「特定の条件下でのファイルパス取得処理(仕様は実装依存)の挙動が、Java 23 以前と Java 24 で微妙に変わっている」(※ どの処理を使って取得するかにもよります) という現象が生じていました。

詳細は後述しますが、後者で得られるファイルパスも別に間違いではない(特殊な条件下での形式が微妙に違う)ものなので、新しく書かれるVCSSLスクリプトにおいては大して問題にならないかもしれません。

しかし、過去に書かれたVCSSLスクリプトの処理においては、ファイルパスの形式が変わると記述当時の想定と違ってしまい、問題となる可能性があります。

そのような「環境やバージョンによって挙動が微妙に変わる」というような点は、完全に無くす事は難しいのですが、なるべくなら無くしたいところです。

そこで今回のアップデートでは、VCSSLのインタープリタ側に対策措置を入れ込み、その上で走るVCSSLスクリプトの挙動を、過去の環境と(なるべく)同じにするための回避策を入れ込みました。

差異が生じていた挙動

今回のアップデートで対策した点について説明するために、まずどのような差異が生じていたかを見てみましょう。

前提: ネットワークドライブについて

まずは前提の説明です。Windows では、ネットワーク上にある他のPCの共有フォルダなどを、手元のPCの「ネットワークドライブ」に割り当てて、手元のPC自身に直接接続されているドライブ(Cドライブなど)と同じような感覚で扱えます。

例えば、LAN内にあるローカルIPアドレス「192.168.1.3」のPCが、共有フォルダを公開していたとしましょう。それを Windows 上でのUNC形式で表すと、以下のようなパスだったとします:

\\192.168.1.3\share\

このフォルダを、例としてネットワークドライブ「Z」に割り当てるよう設定すると、Cドライブのように「Zドライブ」が出現し、その中身は、上記のフォルダの中身と対応するようになります。そうすると、例えばファイル

\\192.168.1.3\share\a.txt

に、

Z:\a.txt

としてアクセスできるようになります。入れ子になっているフォルダ階層も、同じ感覚でアクセスできます。

「ネットワークドライブ上のファイルのパスを取得する」という処理の挙動で問題発生

さて、VCSSLでは、File ライブラリの getFilePath 関数を用いて、ファイルの絶対パスを取得できます。

そして、この getFilePath 関数で、ネットワークドライブ上にあるファイルの絶対パスを取得した場合の挙動が、Java 23 環境上と Java 24 環境上で異なるという問題が生じていました。

たとえば以下のようなVCSSLスクリプトで問題が生じます:

import File;

// ネットワークドライブ上のファイルの絶対パスを取得
// (分かりやすさのため、そもそも引数に絶対パスを渡している)
string absolutePath = getFilePath("Z:\a.txt");

// 取得した絶対パスを表示
println("取得した絶対パス: " + absolutePath);

これを Java 23 上と 24 上で走るVCSSL実行環境で実行すると、それぞれ以下の結果が得られます:

(Java 23 以前)
取得した絶対パス: Z:\a.txt

(Java 24)
取得した絶対パス: \\192.168.1.3\share\a.txt

このように Java 24 上で走るVCSSL実行環境では、ネットワークドライブ部分(Z:)が、ローカルIPアドレスでのUNC形式のパス(\\\\192.168.1.3\share)にまで展開されてしまっていました。Java 23 以前では素直にネットワークドライブ表記のままだったので、挙動が変わってしまったわけです。

念のため Java の名誉のために明記すると、UNC形式のパスも正しいパスです。また、「ネットワークドライブ部分がアドレス解決されるかどうか」という挙動も、Java 側で用いていた機能の仕様では未規定でした。従って Java 側にとっては、もともとここは実装依存の挙動であり、Java 側の挙動変化がバグというわけではありません(意図した挙動変化かどうかは不明ですが)。

付随的な問題

VCSSLスクリプトの処理内容によっては、この「UNC形式への展開」が、付随的な問題を発生させてしまう場合があります。具体的には、「VCSSLスクリプトから、exe やコマンドなどの外部プロセスを実行している場合で、さらにネットワークドライブが絡む場合」が該当します。

というのも、Java経由で Windows のコマンド処理などを行う場合、UNC形式が使えない場面が結構あります。典型的には、Windows のコマンドプロンプトではUNC形式のパスをカレントディレクトリに設定できません。また、外部プロセス実行の際の作業ディレクトリとしても、Java経由だとUNC形式のパスは通りません。

そのような事情で、以下のような「突っ込んだ使い方をしている」ケースでは、既存処理が失敗してしまう可能性があります:

今回のアップデート(Ver.3.4.50)では、UNC形式への展開がされないように対策
―― ただし完全な互換の保証はなし

そこで今回のVCSSLのアップデート(Ver.3.4.50)では、絶対パスを取得する際の内部処理を少し変えて、上で見たような「UNC形式への展開が生じている既存処理」を "迂回" するような形で対策しました。

結果的に、先ほどのコード例では、Java 24 環境上でも以下の通り、Java 23 環境以前と同じ結果が得られるようになっています:

取得した絶対パス: Z:\a.txt

ただ、もともと絶対パスの取得に用いていた内部処理も、今回の「迂回策」によって用いた内部処理も、どちらもJava言語的には「挙動は実装依存」という扱いのものです。

従って、あらゆるパターンの入力に対して、以前のバージョンとの等価性が確かめられたわけではありません。逆に、トリッキーな入力パターンでは、今回の対策によって挙動が変わってしまっている可能性もあるかもしれません。

しかしながら、「ネットワークドライブのパスが、UNC形式のパスになる」という挙動は、先述の通り影響範囲が大きく、そちらを解消する事を最優先しました。

最後に

Java 24 上で既存の VCSSL スクリプトを実行する場合は、VCSSL 3.4.50 以降のバージョンを

今回の更新によって対策された挙動については、以上の通りです。

混乱とお手数をお掛けしてしまい誠に申し訳ございませんが、Java 24 上の環境で、過去に記述された VCSSL スクリプトを実行する場合は、VCSSL 3.4.50 以降のバージョンをご使用いただうようお願いいたします。 「それでも何か挙動が変わってるぞ?」という場合は、スクリプト(または該当処理のコードスニペット)をお送りいただけましたら調査いたしますので、御気軽にお尋ねいただけますと幸いです。

なお余談ですが、今回の挙動の変化は、どうも Java 側にとって意図したものではないのでは?と個人的に思っていまして、その場合は Java 24.0.2 or 25 あたりで修正されるかもしれません。

(※ 後日追記: 報告したら Issue レポートとして通った ので、実際に修正される可能性が出てきました。)

一方で、実装依存となっている機能を用いている以上、逆に今後も、似たような細かい挙動揺れが生じてしまう可能性は残ります。

それはもうどうしようもないのですが(申し訳ありません)、ファイルパスの形にクリティカルに依存しているようなスクリプトは、記述当時のJava実行環境(JRE)も、念のため消さずに一緒にストックしておいた方が無難かもしれません。

VCSSLのアップデートについては、今後も随時このコーナーでお伝えしていきます。