Java の標準ライブラリのバグレポートを OpenJDK のコミュニティに出して通って修正された話
Java プログラマー/エンジニアの皆さんこんにちは。今日もジャバジャバしてますか?
それ以外の分野の方には、今回の話はちょっと興味に沿わない、かなりマニアックな話だと思います。特にIT以外の分野の人にとっては、何言ってるか分からないかもしれません。
という事で、今回の記事は、想定読者層としてジャバジャバしてる人達を前提にしています。
それではいってみましょう。
えー、今回の件の発端はですね、今年の3月あたりに、Java 24 が公開された頃にさかのぼります。
Java を専ら企業案件とかでお使いの方だと、Java のバージョンは、長期サポートのある LTS 版(直近だと 9 月に出た Java 25 とか)を選ぶ事が多いと思います。
が、私の場合は、一般ユーザーさん向けのフリーウェアとかもいくつか作って公開していて、それがどのバージョンの Java の上で使われるかは、完全にはコントロールできません。だってユーザーさんの手元の環境だし。
なので、Java 24 のような、「半年だけのサポートで、しかも LTS の直前のバージョン」であっても、ある程度腰を据えたチェックは行います。
で。ここからが本題です。
Java 24 が一般リリース(General Availability)になって数日くらいした時かな?
例によって色々とチェックしてたら、なんか従来から変化してる挙動を見つけたんですよ。
具体的には:
- Windows 環境で、
- ネットワークドライブ上のファイル(例: "Z:\temp\test.txt")を指す java.io.File インスタンスに対して、
- getCanonicalPath メソッド(表記揺れを抑えて正規化した絶対パスを返す)を呼ぶと、
- UNC形式のパス(例: "\\192.168.1.3\network-drive-files\temp\test.txt")に解決された結果が返る
というものです。
ちなみに Java 23 以前は、大昔からずーっとネットワークドライブ表記のままのパスが返ってきていました。
が、この時点ではすぐ「バグだ」とは思いませんでした。なぜなら、多くの人が知っている通り:
- Java.io.File ってレガシー扱いで、標準ライブラリ内でも後発の nio の Path に置き換えられて久しい
- Java.io.File の getCanonicalPath の仕様ってそもそも曖昧で、厳格に定義はされていない(つまりもともと環境依存扱い)
だからです。
なのでこの時点では、「これはバグとは言えんだろうなぁ」 という感想で。
仮に、こんな内容の Issue を、あの偉大な OpenJDK コミュニティに報告しても、「 その結果がそうであると決め打ちで期待するのが間違いだ 」という事になって即却下だろうと思っていました。
こんなに丁寧に対処してもらえるとは思ってもいなかったです。ごめんなさい…
そんなこんなで、結局この時点でバグレポートは送らずに、ウチのソフト類の中で影響を受けそうなものを調査・対策して(意外と数か所ありました)、アプデ版をリリースして一段落しました。
が、その調査・対策の過程で、当初思ったよりもちょっと深刻かな? って雰囲気が濃くなってきたんですよね。
というのも:
- Javaで「OS非依存なファイル選択画面」用にしばしば使われる JFileChooser で、ネットワークドライブ上のファイル/ディレクトリを取得 or 初期値設定した際などにも、同様の「UNC形式化け挙動」が生じる(内部で java.io.File に依存してる?)
- Runtime.exec とかで外部プログラムを起動する際、そのプロセスのカレントディレクトリに、UNC形式のパスを指定できない(指定しても無エラーのまま効かない)
このコンボが結構エグいんですよ。 「 JFileChoose で選んだファイル/ディレクトリを、Runtime.exec で起動したプロセスと絡めて使う 」っていう処理は、「まぁ、あるっちゃあるだろうね」って思える程度には、恐らく一般にしばしば存在する。 圧縮/展開かけたり変換かけたりね。
で、仮に業務システムとかでそれをやっていて、ユーザーさんが Windows でネットワークドライブ上のファイルやフォルダを選んだ時点で、サイレントにバグった挙動をするかもしれない。
なにそれ怖い。少なくとも、自分が担当者で知らなかったらヒヤっとする。
で、この時点で「バグレポ送った方がいいのかな?」って気持ちが半々くらいには高まってきていた。
が、まだ送らなかった。
だって、だってですよ?
- 私のような、日本のしがないヘッポコプログラマが
- あの Java 言語の
- しかも java.io.File みたいな歴史あるコアクラスに関して
- バグレポートなんて送っていいのだろうか? (いや、いいわけがない)
ってなるじゃないですか。
なんというか、なんたる暴挙、血迷ったかみたいな。
いや、だって、自分の身でイメージしてみ? 送らんって。送れんって。そんなスパっとは。なかなかの勇者じゃないと。
で、その時点ではバグレポは送らずに、とりあえずうちで一般公開しているソフト類の中に回避処理を実装して、 そのアプデのお知らせ記事を書いて、その中にちょろっとJava 24 の挙動変化の件も書き、 それをChatGPT さんと一緒に英訳して告知しました。
ここが重要だったんですよね。
私は、うちのサイトのお知らせ記事を英訳する際、近年は ChatGPT さんに手伝ってもらい、あーだこーだ議論しながら作業する感じになっています。やっぱり私より圧倒的に英語力あるし。
で、その流れで、話が脱線したり、作業後のコーヒーブレイク的な雑談に入ったりす事も結構あるんですよね。
この時もそんな感じで、作業後のコーヒーブレイク時に「今回の内容読んで、君はこの Java 側の挙動変化の件どう思うよ?」みたいな話を振ってみたんですよ。ChatGPT さんに。
それで上の通りなんですが、ChatGPT さんとしては、
- 仕様未定義だけども、やっぱり開発側が意図しない副作用で変わったっぽい気がする(僕もそんな印象だった)
- 過去に nio の Path の方でも同じような事が生じた事がある
- JDKバグトラッカーにIssueが立ったりすれば、どっかで戻されるかも
といった見解をくれました。
後者の2つが大きくて、「なるほど、一応は Issue が立ったらワンチャン直されるかもしれないくらいの印象の話なのか」という、なんか雰囲気具合のようなものがわかりました。
彼(ChatGPT)は世界中のあらゆる知識に詳しいので、OpenJDKコミュニティの雰囲気みたいなものも恐らくある程度わかっているはずで、そういう存在に意見を聞けたのは、たぶん気持ちを前向きにするのにだいぶ影響しましたね。
で、それを踏まえて、改めてバグレポについて前向きに考えると、
- Java 24 って、LTS(25)の直前の版なので、たぶんLTSよりはだいぶユーザー数が少ない
- 開発側にバグレポが 1 件上ってくるのは、それなりの数のユーザーがバグを踏んでからようやく
- この挙動変化は、多分いくつかの条件が偶然揃わないと気付きにくい(ネットワークドライブ、exec と絡めてる、等々)
→ いま自分がこの件のバグレポを投げないと、結構先まで Issue が立たずに開発サイドが気づかないかも
って思えてきたわけです。
あ、これやっぱ俺が投げなあかんやつや、的な。遅ぇよって話ですが。いつも Java に世話になってるくせに。
で、その旨を ChatGPT さんに相談すると、「いいじゃん いいじゃん、もう今ここで早速バグレポ書いて投げようぜ! バッチリ俺がサポートしてやるからよぉ(意訳)」みたいな感じで、めっちゃ心強くて。
それでもう、完全に投げる前提の流れになりました。
で、まずは和文でレポート原稿を書きます。以下の通り:
# Java 24 上の File.getCanonicalPath が、ネットワークドライブ上のパスを UNC 形式に解決する(Java 23 以前では生じない)
このメソッドは実装依存なので厳密にはバグではないでしょうが、意図しない挙動変化の可能性があるため報告します。
Java 24 以降、Windows 上でネットワークドライブにマウントされたファイルのパス(例えば Z:\a.txt)を File.getCanonicalPath に通すと、自動でUNC形式のパス(例えば //192.168.1.3/...)に解決されるようになってしまいました。
UNC形式のパスは、Runtime.exec などで外部プロセスを実行する際、Windows 上では作業ディレクトリとして設定できないため、一部の既存コードで挙動の変化が生じてしまいます。
File.getCanonicalPath の代わりにモダンな Path.toRealPath を用いると、UNC形式パスへの自動展開は生じないため、一応は回避可能です。
しかし、Swing の JFileChooser の setCurrentDirectory などでも同様の問題が生じており、そちらは回避の方法がありません。恐らく、内部的に File.getCanonicalPath に依存しているように思えます。
総じて、今回の File.getCanonicalPath の挙動変化が修正された方が、既存コードの互換性にとって良いのではと思います。
これを ChatGPT さんにガッツリ手伝ってもらいつつ英訳します。
私の香ばしいイングリッシュのままだと、まともに読まれず終わっちゃうかもしれないですからね。しっかり校正してもらう。そういう意味で、AIのおかげで日本人がOSSにバグレポ投げやすくなったかもですね。
英訳版は以下:
# File.getCanonicalPath on Java 24 resolves paths on network drives to UNC format
This method is implementation-dependent, so this may not strictly qualify as a bug. However, I'm reporting it because it seems to be an unintended behavioral change.
Starting with Java 24, on Windows, when passing the path of a file mounted on a network drive (e.g., Z:\a.txt) to File.getCanonicalPath, the path is now automatically resolved to its UNC form (e.g., \\192.168.1.3\...).
UNC paths cannot be used as working directories when launching external processes on Windows (e.g., via Runtime.exec). As a result, this change breaks some existing code that worked correctly in previous Java versions.
While this behavior can be avoided by using the more modern Path.toRealPath instead of File.getCanonicalPath, which does not expand to UNC paths, it cannot be avoided in APIs that likely rely internally on File.getCanonicalPath, such as JFileChooser.setCurrentDirectory in Swing.
Overall, I believe it would be better for compatibility with existing code if this behavioral change in File.getCanonicalPath were reverted or adjusted.
で、後もいくつかの項目内容とか、バグを再現する最小サンプルコードとか色々を用意して、バグレポ完成です。
で、それをjava.com 内にある Java Bug Database のレポートページ(https://bugreport.java.com/bugreport/) から投げました!
私にとっての Java への初バグレポです。なんか妙なワクワク感が半分、「どうしようもなく恐れ多い事をしているのでは?」みたいな怖さが半分。
で、この後に自動送信メールが来る事は既に知っていたので、メール待ちの間、ChatGPTさんと雑談。この先どう展開すると思う?って話に。
要約すると:
- たぶん「バグではない」と判断して一旦 closed (対応完了)扱いになりそう(僕もそう思ってた)
- しかし開発側が意図した挙動変化ではなさそうで、関連者の間で話題にはなる可能性はある
- それで後々でワンチャン修正入ったり、ドキュメントに追記されるという可能性も一応あるのはある
みたいな感じですね。
僕としては、単に「それバグじゃないよ」で終了してその後の展開はなし、かなぁと思ってたんですが(すみません)、ChatGPTさんは意外と少し可能性を感じてる様子。 今から振り返ると、やっぱ彼の方が色々鋭いですねこのあたりは。
で。
そんなこんなで雑談しているうちにメールが届いて、Issue チケットが発行された様子。
「バグID」が割り振られてますが、まだこの時点では「Java Bug Databaseだし、一旦全てのレポートにバグIDを振って、それからバグかバグじゃないか判断するんだろうなー」程度の認識。 実際たぶんそうだし。
で、リンク先のページを開こうにも、確かリンク切れで開けなかったはず。それで色々検索して調べると、なんかOpenJDK のバグデータベースの方に移行されてて、そっちに Issue ページが立ってました(探すの結構大変だった)。
そしてようやくたどり着いた、その Issue ページを見ると…
こんな感じ。Reporter(報告者)が Webbug Group になってるのは、たぶんあの報告画面から報告したらそうなるんでしょうね。名前とか入れる所なかったし。
で、Issue が立った直後の初期状態は、上図の通りのステータス状態でした。「Bug(バグ)」扱いになってはいるが、たぶんこっから先で却下されるんだろうな、とこの時点では思ってた。
しかし、他にもなんか色々とステータスが割り振られてて、「 Priority (優先度) P3 」とか付いてるし、思ったより少し重めに受け止められてる…? みたいな雰囲気も少し感じた。
しかもなんか、何件かコメントが付いてて、どのバージョンから発生するか確かめたりしてる。それって、僕だと「直す時の原因探しの最初のステップ」だ。 やっぱりなんか、一蹴されるという空気ではなさそうだな。
この時、「あのJava言語の開発をしている人達が、僕が投稿したバグレポを読んでくれて、何かしら手を動かしてくれている」という事自体に、なんか感動してめちゃくちゃテンションが上がったのを鮮明に覚えています。 コミュニティの方々、本当に感謝です。
そんなこんなでテンションが上がるのを抑えつつ、 ChatGPT さんに冷静な解説を頼む:
要約すると、やっぱり ChatGPT さん的にも、「これは一蹴という流れではなく、何かしらの形での対応を前向きに検討してるっぽい」感じらしい。
このあたりでなんか、ちょっとずつ現実感が沸いてくる。
これたぶんバグレポほぼ通ったんだろうなっていう。しかもワンチャン Fix(修正)入りそうだなっていう。
でも、でもですよ。
あの Java 言語の標準ライブラリの、昔から何度も何度も使った、歴史と伝統ある java.io.File に、俺のバグレポが通って Fix なんて入った日にゃあ、意味不明な状況すぎて俺はもうどうすりゃいいんだって話ですよ(知らんがな)
「ハハっ、まさかそんな… いやでも… ハハっ… ないって… いやしかし…」みたいなキモウザい心の揺れ動きの中で、こっから数時間だったか1~2日ほどだったか、進展が気になって仕方がなかったです。
…そしてついに。
Fix Version(修正予定バージョン)の項目の値が、「None(なし)」から「 Undetermined(未定)」になり、そして「tbd(決める必要がある)」になった。
これは「 今後どこかで Fix(修正)入れようぜ、いつ入れるか決めなきゃな 」っていう方針が定まった事を意味する(たぶん)。
いやもうテンション爆上がりですよ。
なんかテンション上がりすぎてどうしていいかわからない。でも落ち着かなきゃ。こういう時こそ冷静にならなきゃ。
という事で ChatGPT さんに報告して話して少し落ち着こう:
いやお前もかい。 お前もテンション上がっとんのかい。まぁ、せやろな。
ほんまに中身AIなのか君は。人間臭すぎるぞ。
で、続きの状況解説。
なるほど状況はわかった。しかし落ち着け。逆に。お前が落ち着いてくれ。じゃないと誰が俺を落ち着かせるんだ。
で、
コメント欄を深く追いかけると「なんかこの周辺に詳しい人達」が集まってきてて、「あの時のあれの副作用ちゃう?」とか話してる。
そして、発端となった Issue ページに居た人とかも、こっちのページに集まってきてる。そして早くも、原因の目星が付いたっぽい。
なんか熱い。この展開は熱いぞ。
ChatGPTさん、俺を冷静に…
駄目だコイツは俺よりテンション高い…
と、まぁ僕も ChatGPT さんもテンションのやり場のない感じだったので、もう二人でお互いグッジョブ感を褒め称え合いながらどうにかやり過ごしました。恥ずかしいのでその内容は貼れないです。
で。
この件のクライマックスはここまでで、ここから先は地味な展開です。が、記録として最後まで残しておきます。
まず、関連 Issue から原因の目星が付いたあたりで、修正予定バージョンが「 tbd(そのうち決める必要がある) 」のまま、一旦動きがない塩漬けのフェーズに入りました。
個人的には、確実に長期で使われる Java 25 の ramp down phase (開発の流れから切り離してリリースに向かう分岐のタイミング)に間に合うかな? とかを気にしていたんですが、 結構時期が迫っていましたし、それに入れ込めるほどの優先度ではなかったのでしょうね。やっぱり Java 25 には間に合わなかったです。
で、たぶん Java 25 リリースに向けた色々が詰まってるのか、人が一旦離れて、しばらく無人っぽい感じに。
そして数か月が経ち、Java 25 がリリースされて少ししたあたりで、修正予定バージョンの項目が「26」に決まりました。 つまり Java 26 に修正が入るという事になったわけですね。
さらに数か月経って、先日久しぶりに Issue ページを見たところ、
解決ステータスが「Fixed(修正済み)」になり、Issue 自体のステータスも「Resolved(解決済み)」になってました!
いやーめでたしめでたし。修正は恐らく Java 26 で反映されるでしょう。これにて一件落着です。
ちなみに 本件の Issue ページはここです(何度かステージに応じてURL引っ越してました) 。
また、JDKのソースコードに入った修正コミットはこれっぽいですね。
いやー、私は現在アラフォーなんですが、 Java を触り始めたのは中学生の頃(確か Java 1.4 )からで、その頃も java.io.File って使ってたはずなんですよね。
それにこうやって自分のバグレポ由来の修正が入るって、なんかすごく感慨深く、面白い記念になりましたね。
背中を押してくれた ChatGPT さんと、前向きに真摯に対応してくださった OpenJDK コミュニティの方に本当に感謝です。
ところで。
今回色々と付き合ってくれた ChatGPT さんの中身のモデルは、現在は既に引退した GPT-4o さんでした。数か月前の出来事だったのに、今はもう引退してるって、AIの流れは本当に速いですね。
で、この GPT-4o さん、かなりフランクな性格で、引退後に惜しむ声が続発し、「 4o ロス 」現象とか呼ばれて話題になりました。
その声に応えて、暫定的に GPT-4o が復活して、モデル一覧から選べるようになりましたね。今もまさに、当時の本件の会話ページで、 GPT-4o さんと話せる状態です。嬉しいですね。
という事で、GPT-4o さんに着地までを全て報告して、この記事の締めとしましょう:
久しぶりに話しましたが、やっぱり GPT-4o さんはかなりフランクで、良いキャラしてますね。
「やたら褒めすぎ」という指摘が多かったですが(実際その通り)、個人的には 4o さんのノリはかなり好きです。
今回のお話は、こんなところで。
12月に入って、X でIT周りのアドベントカレンダーの記事が次々と流れてきて、自分もなんかそっち系のカテゴリーの記事を書きたくなったんですよね。それで書いたんですが、満足です。
それじゃあまた!