unsafe 性チェック
Rust の特定の式はメモリ安全性に違反する可能性があるため、unsafe ブロックまたは関数の内部に置く必要があります。
コンパイラは、対応する unsafe 操作がないのに unsafe ブロックが使用されている場合にも警告します。
概要
unsafe 性チェックは check_unsafety モジュールにあります。
これは、関数とそのすべてのクロージャおよびインライン定数の THIR を走査します。
unsafe コンテキスト、つまり unsafe ブロックに入ったかどうかを追跡します。
unsafe 操作が unsafe ブロックの外で使用された場合は、エラーが報告されます。
unsafe 操作が unsafe ブロック内で使用された場合、
そのブロックは unused_unsafe lint のために使用済みとしてマークされます。
unsafe 性チェックには型情報が必要なので、 HIR 上で typeck の結果、THIR、または MIR を利用して行うことも潜在的には可能です。 THIR が選ばれているのは、 HIR よりも考慮すべきケースが少ないためです。たとえば unsafe 関数呼び出しと unsafe メソッド呼び出しは THIR では同じ表現になります。 このチェックが MIR 上で行われないのは、安全性チェックが制御フローに依存しないため、 MIR を使用する必要がないからです。 また、MIR には一部の式について十分に正確な span がありません。
ほとんどの unsafe 操作は、THIR の ExprKind を確認し、
引数の型を確認することで識別できます。
たとえば、生ポインタのデリファレンスは、
生ポインタ型を持つ引数を伴う ExprKind::Deref に対応します。
unsafe な Union フィールドアクセスを探すのは、少し複雑です。union のフィールドへの書き込みは安全だからです。 チェッカーは、代入式の左辺を訪問しているタイミングを追跡し、 union フィールドがそこに直接現れることを許可する一方で、 それ以外のすべての場合にはエラーにします。 Union フィールドアクセスはパターン内にも現れる可能性があるため、それらも走査する必要があります。
unused_unsafe lint
unused_unsafe lint は、削除可能な unsafe ブロックを報告します。
unsafe 性チェッカーは、unsafe を必要とする操作を見つけるたびに記録します。
その後、次のいずれかの場合に lint が報告されます。
unsafeブロックに unsafe 操作が含まれていないunsafeブロックが別の unsafe ブロック内にあり、外側のブロックが未使用と見なされていない
#![allow(unused)]
#![deny(unused_unsafe)]
fn main() {
let y = 0;
let x: *const u8 = core::ptr::addr_of!(y);
unsafe { // このブロックに対して lint が報告される
unsafe {
let z = *x;
}
let safe_expr = 123;
}
unsafe {
unsafe { // このブロックに対して lint が報告される
let z = *x;
}
let unsafe_expr = *x;
}
}
unsafe を伴うその他のチェック
Unsafe traits は実装するために unsafe impl を必要とし、このチェックは coherence の一部として行われます。
unsafe_code lint は、unsafe ブロック、関数、実装、および特定の unsafe 属性を検索する ast 上の lint パスとして実行されます。