Hacker News の報告は、Rust における健全性(soundness)のバグを取り上げています。共変なフィールド代入によって、構造体のライフタイム要件を回避できるというものです。報告者は、Drop 実装を持つ Option<T> を内包するラッパー型 Q<T> を用いた小さなプログラムを共有しています。この Drop 実装は、格納された値を静的な Mutex<Vec<Box<dyn Any + Send>>> に移動させますが、'static で生存しない借用値に対してはこれは不可能なはずです。
この例では、ローカルの String が内側のスコープ内でラッパーに参照によって代入されています。そのため、借用はそのスコープが閉じると終了するはずです。ところが、ラッパーのフィールドが共変であるため、コンパイラはこの代入を受け入れ、参照はローカル変数の寿命を超えて保存されてしまいます。プログラムは拒否されることなくコンパイルされ、無関係なメモリの内容を出力します。
AddressSanitizer の下で実行すると、プログラムは stack-use-after-scope エラーでクラッシュします。これは、ダングリング参照が実際に参照外しされていることを裏付けるものです。報告によれば、この問題は現在の nightly ビルドや、少なくとも 1.85.0 までの安定版リリースで再現できるとのことです。投稿には、サニタイザーあり・なしの Compiler Explorer の例へのリンクが添えられています。
この発見は、変位(variance)が Drop ベースのストレージとどのように相互作用するかに健全性の穴があることを示しています。安全なコードが未定義動作を引き起こすことは決してあってはならないため、Rust のメンテナーはこの種の問題を高い優先度で扱います。
よくある質問:ダングリング参照があるのに、なぜこの Rust プログラムはコンパイルできるのですか?
フィールドの共変性により、コンパイラは寿命の短い参照の代入を受け入れます。その後、Drop 実装がその参照を 'static なコンテナに格納するため、ローカル変数の寿命を超えて使用されてしまいます。これは健全性のバグであり、本来コンパイラはこのコードを拒否すべきです。
出典: Hacker News · 要約:HeadlinesBriefing