|
| 1 | +# Unsafety Checking |
| 2 | + |
| 3 | +Certain expressions in Rust can violate memory safety and as such need to be |
| 4 | +inside an `unsafe` block or function. The compiler will also warn if an unsafe |
| 5 | +block is used without any corresponding unsafe operations. |
| 6 | + |
| 7 | +## Overview |
| 8 | + |
| 9 | +The unsafety check is located in the [`check_unsafety`] module. It performs a |
| 10 | +walk over the [THIR] of a function and all of its closures and inline constants. |
| 11 | +It keeps track of the unsafe context: whether it has entered an `unsafe` block. |
| 12 | +If an unsafe operation is used outside of an `unsafe` block, then an error is |
| 13 | +reported. If an unsafe operation is used in an unsafe block then that block is |
| 14 | +marked as used for [the unused_unsafe lint](#the-unused_unsafe-lint). |
| 15 | + |
| 16 | +The unsafety check needs type information so could potentially be done on the |
| 17 | +HIR, making use of typeck results, THIR or MIR. THIR is chosen because there are |
| 18 | +fewer cases to consider than in HIR, for example unsafe function calls and |
| 19 | +unsafe method calls have the same representation in THIR. The check is not done |
| 20 | +on MIR because safety checks do not depend on control flow so MIR is not |
| 21 | +necessary to use and MIR doesn't have as precise spans for some expressions. |
| 22 | + |
| 23 | +Most unsafe operations can be identified by checking the `ExprKind` in THIR and |
| 24 | +checking the type of the argument. For example, dereferences of a raw pointer |
| 25 | +correspond to `ExprKind::Deref`s with an argument that has a raw pointer type. |
| 26 | + |
| 27 | +Looking for unsafe Union field accesses is a bit more complex because writing to |
| 28 | +a field of a union is safe. The checker tracks when it's visiting the left-hand |
| 29 | +side of an assignment expression and allows union fields to directly appear |
| 30 | +there, while erroring in all other cases. Union field accesses can also occur |
| 31 | +in patterns, so those have to be walked as well. |
| 32 | + |
| 33 | +The other complicated safety check is for writes to fields of layout constrained |
| 34 | +structs (such as [`NonNull`]). These are found by looking for the borrow or |
| 35 | +assignment expression and then visiting the subexpression being borrowed or |
| 36 | +assigned with a separate visitor. |
| 37 | + |
| 38 | +[THIR]: ./thir.md |
| 39 | +[`check_unsafety`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_build/check_unsafety/index.html |
| 40 | +[`NonNull`]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html |
| 41 | + |
| 42 | +## The unused_unsafe lint |
| 43 | + |
| 44 | +The unused_unsafe lint reports `unsafe` blocks that can be removed. The unsafety |
| 45 | +checker records whenever it finds an operation that requires unsafe. The lint is |
| 46 | +then reported if either: |
| 47 | + |
| 48 | +- An `unsafe` block contains no unsafe operations |
| 49 | +- An `unsafe` block is within another unsafe block, and the outer block |
| 50 | + isn't considered unused |
| 51 | + |
| 52 | +```rust |
| 53 | +#![deny(unused_unsafe)] |
| 54 | +let y = 0; |
| 55 | +let x: *const u8 = core::ptr::addr_of!(y); |
| 56 | +unsafe { // lint reported for this block |
| 57 | + unsafe { |
| 58 | + let z = *x; |
| 59 | + } |
| 60 | + let safe_expr = 123; |
| 61 | +} |
| 62 | +unsafe { |
| 63 | + unsafe { // lint reported for this block |
| 64 | + let z = *x; |
| 65 | + } |
| 66 | + let unsafe_expr = *x; |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +## Other checks involving `unsafe` |
| 71 | + |
| 72 | +[Unsafe traits] require an `unsafe impl` to be implemented, the check for this |
| 73 | +is done as part of [coherence]. The `unsafe_code` lint is run as a lint pass on |
| 74 | +the ast that searches for unsafe blocks, functions and implementations, as well |
| 75 | +as certain unsafe attributes. |
| 76 | + |
| 77 | +[Unsafe traits]: https://doc.rust-lang.org/reference/items/traits.html#unsafe-traits |
| 78 | +[coherence]: /home/matthew/rust/compiler/rustc_hir_analysis/src/coherence/unsafety.rs |
| 79 | + |
0 commit comments