-
Notifications
You must be signed in to change notification settings - Fork 547
Document unsafety checking #1847
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# Unsafety Checking | ||
|
||
Certain expressions in Rust can violate memory safety and as such need to be | ||
inside an `unsafe` block or function. The compiler will also warn if an unsafe | ||
block is used without any corresponding unsafe operations. | ||
|
||
## Overview | ||
|
||
The unsafety check is located in the [`check_unsafety`] module. It performs a | ||
walk over the [THIR] of a function and all of its closures and inline constants. | ||
It keeps track of the unsafe context: whether it has entered an `unsafe` block. | ||
If an unsafe operation is used outside of an `unsafe` block, then an error is | ||
reported. If an unsafe operation is used in an unsafe block then that block is | ||
marked as used for [the unused_unsafe lint](#the-unused_unsafe-lint). | ||
|
||
The unsafety check needs type information so could potentially be done on the | ||
HIR, making use of typeck results, THIR or MIR. THIR is chosen because there are | ||
fewer cases to consider than in HIR, for example unsafe function calls and | ||
unsafe method calls have the same representation in THIR. The check is not done | ||
on MIR because safety checks do not depend on control flow so MIR is not | ||
necessary to use and MIR doesn't have as precise spans for some expressions. | ||
|
||
Most unsafe operations can be identified by checking the `ExprKind` in THIR and | ||
checking the type of the argument. For example, dereferences of a raw pointer | ||
correspond to `ExprKind::Deref`s with an argument that has a raw pointer type. | ||
|
||
Looking for unsafe Union field accesses is a bit more complex because writing to | ||
a field of a union is safe. The checker tracks when it's visiting the left-hand | ||
side of an assignment expression and allows union fields to directly appear | ||
there, while erroring in all other cases. Union field accesses can also occur | ||
in patterns, so those have to be walked as well. | ||
|
||
The other complicated safety check is for writes to fields of layout constrained | ||
structs (such as [`NonNull`]). These are found by looking for the borrow or | ||
assignment expression and then visiting the subexpression being borrowed or | ||
assigned with a separate visitor. | ||
|
||
[THIR]: ./thir.md | ||
[`check_unsafety`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_build/check_unsafety/index.html | ||
[`NonNull`]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html | ||
|
||
## The unused_unsafe lint | ||
|
||
The unused_unsafe lint reports `unsafe` blocks that can be removed. The unsafety | ||
checker records whenever it finds an operation that requires unsafe. The lint is | ||
then reported if either: | ||
|
||
- An `unsafe` block contains no unsafe operations | ||
- An `unsafe` block is within another unsafe block, and the outer block | ||
isn't considered unused | ||
|
||
```rust | ||
#![deny(unused_unsafe)] | ||
let y = 0; | ||
let x: *const u8 = core::ptr::addr_of!(y); | ||
unsafe { // lint reported for this block | ||
unsafe { | ||
let z = *x; | ||
} | ||
let safe_expr = 123; | ||
} | ||
unsafe { | ||
unsafe { // lint reported for this block | ||
let z = *x; | ||
} | ||
let unsafe_expr = *x; | ||
} | ||
``` | ||
|
||
## Other checks involving `unsafe` | ||
|
||
[Unsafe traits] require an `unsafe impl` to be implemented, the check for this | ||
is done as part of [coherence]. The `unsafe_code` lint is run as a lint pass on | ||
the ast that searches for unsafe blocks, functions and implementations, as well | ||
as certain unsafe attributes. | ||
|
||
[Unsafe traits]: https://doc.rust-lang.org/reference/items/traits.html#unsafe-traits | ||
[coherence]: /home/matthew/rust/compiler/rustc_hir_analysis/src/coherence/unsafety.rs | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.