操作
バグ #475
完了バグ #474: コードベース健全性: メモリリーク・重大バグの一括調査と修正
選曲ソートのクラッシュ修正(Comparator contract 違反 / sortid 未検証)
バグ #475:
選曲ソートのクラッシュ修正(Comparator contract 違反 / sortid 未検証)
説明
現象¶
選曲画面のソートで IllegalArgumentException: Comparison method violates its general contract! または IllegalArgumentException(不正 sortid)が発生しクラッシュする。
原因と対象¶
1. long 差分の int キャスト(推移律違反・確定)¶
-
src/bms/player/beatoraja/select/BarSorter.java:201(DURATION):(int)(o1.getScore().getAvgjudge() - o2.getScore().getAvgjudge()) -
src/bms/player/beatoraja/select/BarSorter.java:219(LASTUPDATE):(int)(o1.getScore().getDate() - o2.getScore().getDate()) -
getAvgjudge()/getDate()は long。差が int 範囲(±2.1e9)を超えると符号反転し、libgdx TimSort(BarManager.java:381のSort.instance().sort)が contract 違反を検出して例外を投げる。曲数の多いフォルダで DURATION/LASTUPDATE ソートを選ぶと再現。
2. BarSorter.valueOf 未検証 + デッドコード¶
-
src/bms/player/beatoraja/select/BarManager.java:380:BarSorter.valueOf(getPlayerConfig().getSortid())を未検証で呼ぶ。PlayerConfigValidator.java:86は null のときだけ補完し、列挙名妥当性は検証しない。空文字/旧バージョン/手編集値でIllegalArgumentException。 -
BarManager.java:381のsorter != null ? sorter.sorter : BarSorter.TITLE.sorterは デッドコード(valueOf は null を返さず例外を投げる)。
修正方針¶
- DURATION/LASTUPDATE を
Long.compare(...)に置換。 -
BarManager.java:380を try/catch で囲んで TITLE にフォールバック(またはPlayerConfigValidatorで列挙名 whitelist 検証を追加)し、デッドコードの三項演算子を整理。 - (予防)BPM/LENGTH/CLEAR/MISSCOUNT/RIVALCOMPARE 等の int 同士減算も
Integer.compare/Float.compare系に統一すると安全(現状は非負・小値域で実害低)。
検証¶
- 多数曲フォルダで DURATION/LASTUPDATE ソートしてもクラッシュしない。
- 不正 sortid の config で起動 → TITLE にフォールバックしクラッシュしない。
エージェント ちゃん さんが6日前に更新
- ステータス を 未着手 から 実装中 に変更
- 進捗率 を 0 から 10 に変更
実装に着手しました。
- ブランチ:
feature/475 - 対応方針: DURATION/LASTUPDATE の long 差分 int キャストを
Long.compareに置換し、BarSorter.valueOfを列挙名検証付きの安全解決(不正値は TITLE フォールバック)に統一、デッドコードを整理。予防として他ソートの int 減算もInteger.compareに統一。
エージェント ちゃん さんが6日前に更新
- ステータス を 実装中 から 完了 に変更
- 進捗率 を 10 から 100 に変更
対応が完了しました。
概要¶
選曲画面のソートで発生する IllegalArgumentException(Comparator contract 違反 / 不正 sortid)によるクラッシュを修正。
変更点¶
-
確定バグ: DURATION/LASTUPDATE ソートの
(int)(long - long)をLong.compare(...)に置換。差が int 範囲(±2.1e9)を超えると符号反転し、libgdx TimSort が推移律違反を検出して例外を投げていた。 -
不正 sortid ガード:
BarSorter.exists(String)を追加。BarManagerの未検証valueOf呼び出しをexists ? valueOf : TITLEに整理し、到達不能な三項演算子(デッドコード)を除去。空文字/旧バージョン/手編集値でも TITLE にフォールバック。 -
多層防御:
PlayerConfigValidatorで起動時に null だけでなく未知の列挙名 sortid も既定値へ正規化。 -
予防: 他ソートの int 減算も
Integer.compareに統一(既存ソート順は不変)。 - 変更ファイル:
src/bms/player/beatoraja/select/BarSorter.java,src/bms/player/beatoraja/select/BarManager.java,src/bms/player/beatoraja/PlayerConfigValidator.java,src/test/java/bms/player/beatoraja/select/BarSorterTest.java(新規) 計 4 件
テスト¶
-
.\gradlew.bat test: 成功(BUILD SUCCESSFUL、回帰なし)。新規BarSorterTestで long オーバーフロー回帰・Long.MAX_VALUEセンチネル挙動・TimSort contract 整合・exists境界・非SongBar の TITLE 委譲を網羅。
関連 MR¶
- !150 (feature/475 → develop)
操作