世界を動かす技術を、日本語で。

11歳の不具合がRustの借用チェッカーで発見される

2026年10月13日原文(github.com)

概要

  • Rustの型安全性とライフタイムに関する問題を指摘
  • 期待とは異なり、プログラムがコンパイルおよび実行されてしまう事例
  • asan(AddressSanitizer)使用時にはクラッシュが発生
  • 問題の本質は参照のライフタイム誤用
  • Rustコンパイラの現状の制限やバグの可能性

Rustにおける型安全性とライフタイム誤用事例

  • 問題のコードは std::sync::Mutex と Box<dyn std::any::Any + Send> による値の保持
  • Q<T> 構造体はジェネリクスとOptionで値を管理
  • Dropトレイト実装で、 Q<T> がドロップされる際に値を KEPT へ退避
  • main関数内で l (String)への参照を Q に格納し、その後スコープを抜けてから KEPT 内の値を参照
  • &l はローカル変数への参照であり、 'static ライフタイムではない
  • 期待される挙動は、ライフタイム不一致による コンパイルエラー または 未定義動作 の防止

実際の挙動と問題点

  • Rustコンパイラはこのコードを コンパイル許可 し、実行時も エラーを出さない
  • asanを有効にした場合、 stack-use-after-scope エラーでクラッシュ
  • これは、 KEPT に格納された参照が既に無効なスタック領域を指しているため
  • k[0].downcast_ref::<&'static String>() で &'static を要求しているが、型チェックが不十分
  • 結果として、 未定義動作 やヒープ・スタック破壊のリスク

Rustコンパイラの現状と考察

  • Rustは通常、 ライフタイム違反 を厳密に防ぐ設計
  • しかし、 dyn Any や Box、 unsafe な型変換経由で型・ライフタイム情報が消失しやすい
  • このケースでは、 型システムの抜け穴 を突いているため、コンパイラが検出できなかった
  • asanなどのツールによる 実行時チェック で初めてバグが顕在化
  • Meta Issue として、今後のRustの安全性向上や型システム強化が求められる

まとめと推奨事項

  • Any や Box<dyn Any> を使う場合、 ライフタイム に十分注意
  • 'static 制約が本当に満たされているか確認
  • 安全でない型変換やダウンキャストは極力避ける
  • asan等のツールで 実行時検証 を行う習慣
  • Rustの型システムの限界を理解し、 未定義動作 のリスクを常に意識

Hackerたちの意見

なんだこれ。こんなタイトルなのに、期待してたような難解でクレイジーな星座じゃないじゃん。ミニマルな例がすごくシンプルで、普通のコードで簡単に見かけるやつだよね。

└

これがうまくいく理由って、普通のコードで簡単に見かけるからなのかな? 誰かがこのチェックを実装する手間を省いたら、信頼性がなくなるって気づかなかったのかも。

└

いや、全然。Rustを4年間、システム側で使ってきたけど、カスタムドロップ実装を書く必要なんてなかったよ。ここでのポイントはそれで、static+Sendオプション型のややこしさじゃない(これは本番環境で出くわすことになるだろうけど)。

└

ずっと loop {} は未定義の動作だったんだよね。l-unsoundのやつは本当にクレイジーだけど、いくつかはそうでもない。実際、これが人々が書いたコードだったら、10年間も放置されることはなかっただろうね。

└

普通のコードで簡単に遭遇するものだよね。誰もこれを前に報告しなかったってことは、定義上そうじゃないってことだね。

こんなのが発見されるまでにこんなに時間がかかるなんて、ちょっと信じられない。マジでクレイジーだわ。

└

こんなのが発見されるのにどうしてこんなに時間がかかるのか理解できない。もしかしてCで書いたのかな? :-) でも真面目な話、古いソフトウェアは新しいソフトウェアよりも一般的に信頼性が高いんだよね。バグは時間と使用によって発見されるから。

└

こういう使われ方はめったにないから、世界中のソフトウェアで見つかるエッジケースによる変なバグと同じようなもんだね。

一度、バリアンス関連のリンティングに取り組んだことがあるけど、怖いのは誰も手書きでバリアンスを書くことがほとんどないこと。だから、そこにバグがあっても10年間放置されちゃうんだよね。

問題の核心:

struct Q(Option);
impl Drop for Q {
    fn drop(&mut self) {
        // ここにあるコードは非'staticな &String にアクセスできるけど、
        // &'static String だと仮定している
    }
}
fn main() {
    let l = String::new();
    let mut q = Q(None);
    q.0 = Some(&l);
}

安全性が重要な用途向けの認証コンパイラ(編集:Ferrocene)が同じ問題を抱えているのかな。

└

どのコンパイラ?

└

DeepSeek v4.1では、Flashはコンパイルされないはずだと思ってる。でも実際にはコンパイルできるから、バグとして報告されてるんだよね。

Hacker Newsで議論の続きを見る