【要約】Rust 1.97.0のsegfaultを7命令まで読む — 10リリース潜伏したミスコンパイルの解剖 [Qiita_Trend] | Summary by TechDistill
> Source: Qiita_Trend
Execute Primary Source
// Problem
Rust開発者が、unsafeを使用していない安全なコードで予期せぬsegfaultに直面した。
* 原因: Rust 1.97.0でのenum判別値の内部表現の変更。
* トリガー: LLVMのx86バックエンドにおける、不適切なロード融合(Load Combining)の最適化。
* 現象: Noneの判別値(-1)をインデックスに使用し、16GiB先の非正準アドレスを参照して#GPが発生した。
* 原因: Rust 1.97.0でのenum判別値の内部表現の変更。
* トリガー: LLVMのx86バックエンドにおける、不適切なロード融合(Load Combining)の最適化。
* 現象: Noneの判別値(-1)をインデックスに使用し、16GiB先の非正準アドレスを参照して#GPが発生した。
// Approach
著者は、発生したsegfaultのメカニズムを解明するため、機械語レベルでの比較検証を行った。
* 再現: 最小限の再現コードを用い、rustc 1.96.0/1.97.0/1.97.1の3バージョンで挙動を比較。
* 解析:
* 検証: IRは正しいが、x86バックエンドの最適化で不正な命令が生成されていることを突き止めた。
* 再現: 最小限の再現コードを用い、rustc 1.96.0/1.97.0/1.97.1の3バージョンで挙動を比較。
* 解析:
objdumpでアセンブリを抽出し、LD_PRELOADを用いてNone時のレジスタ状態を観測した。* 検証: IRは正しいが、x86バックエンドの最適化で不正な命令が生成されていることを突き止めた。
// Result
Rust 1.97.1のリリースにより、問題は完全に解消された。
* 修正内容: Rust側での判別値の変更取り消しと、LLVM側でのインデックスマスク(
* 効果: 投機的なロードが構造体の範囲内に制限され、None時でも安全に動作するようになった。
* 教訓: コンパイラのバグによるリスクを理解し、迅速なツールチェーンの更新が推奨される。
* 修正内容: Rust側での判別値の変更取り消しと、LLVM側でのインデックスマスク(
and $0x1)の追加。* 効果: 投機的なロードが構造体の範囲内に制限され、None時でも安全に動作するようになった。
* 教訓: コンパイラのバグによるリスクを理解し、迅速なツールチェーンの更新が推奨される。
Senior Engineer Insight
> コンパイラの最適化バグは、開発者の努力を無に帰す。本件は「安全なRust」の前提を揺るがすが、修正速度の速さが信頼を担保している。現場では、CIでのツールチェーン固定時に、こうした緊急パッチの存在を考慮すべきだ。1.97.0を避け、1.97.1以降を使用することが、運用上のリスク回避に直結する。