forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of rust-lang#72270 - RalfJung:lint-ref-to-packed, r=oli-obk
add a lint against references to packed fields Creating a reference to an insufficiently aligned packed field is UB and should be disallowed, both inside and outside of `unsafe` blocks. However, currently there is no stable alternative (rust-lang#64490) so all we do right now is have a future incompatibility warning when doing this outside `unsafe` (rust-lang#46043). This adds an allow-by-default lint. @retep998 suggested this can help early adopters avoid issues. It also means we can then do a crater run where this is deny-by-default as suggested by @joshtriplett. I guess the main thing to bikeshed is the lint name. I am not particularly happy with "packed_references" as it sounds like the packed field has reference type. I chose this because it is similar to "safe_packed_borrows". What about "reference_to_packed" or "unaligned_reference" or so?
- Loading branch information
Showing
8 changed files
with
144 additions
and
20 deletions.
There are no files selected for viewing
This file contains 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,66 @@ | ||
use rustc_middle::mir::visit::{PlaceContext, Visitor}; | ||
use rustc_middle::mir::*; | ||
use rustc_middle::ty::{self, TyCtxt}; | ||
use rustc_session::lint::builtin::UNALIGNED_REFERENCES; | ||
|
||
use crate::transform::{MirPass, MirSource}; | ||
use crate::util; | ||
|
||
pub struct CheckPackedRef; | ||
|
||
impl<'tcx> MirPass<'tcx> for CheckPackedRef { | ||
fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { | ||
let param_env = tcx.param_env(src.instance.def_id()); | ||
let source_info = SourceInfo::outermost(body.span); | ||
let mut checker = PackedRefChecker { body, tcx, param_env, source_info }; | ||
checker.visit_body(&body); | ||
} | ||
} | ||
|
||
struct PackedRefChecker<'a, 'tcx> { | ||
body: &'a Body<'tcx>, | ||
tcx: TyCtxt<'tcx>, | ||
param_env: ty::ParamEnv<'tcx>, | ||
source_info: SourceInfo, | ||
} | ||
|
||
impl<'a, 'tcx> Visitor<'tcx> for PackedRefChecker<'a, 'tcx> { | ||
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { | ||
// Make sure we know where in the MIR we are. | ||
self.source_info = terminator.source_info; | ||
self.super_terminator(terminator, location); | ||
} | ||
|
||
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { | ||
// Make sure we know where in the MIR we are. | ||
self.source_info = statement.source_info; | ||
self.super_statement(statement, location); | ||
} | ||
|
||
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { | ||
if context.is_borrow() { | ||
if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { | ||
let source_info = self.source_info; | ||
let lint_root = self.body.source_scopes[source_info.scope] | ||
.local_data | ||
.as_ref() | ||
.assert_crate_local() | ||
.lint_root; | ||
self.tcx.struct_span_lint_hir( | ||
UNALIGNED_REFERENCES, | ||
lint_root, | ||
source_info.span, | ||
|lint| { | ||
lint.build(&format!("reference to packed field is unaligned",)) | ||
.note( | ||
"fields of packed structs are not properly aligned, and creating \ | ||
a misaligned reference is undefined behavior (even if that \ | ||
reference is never dereferenced)", | ||
) | ||
.emit() | ||
}, | ||
); | ||
} | ||
} | ||
} | ||
} |
This file contains 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 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 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 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 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 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,22 @@ | ||
#![deny(unaligned_references)] | ||
|
||
#[repr(packed)] | ||
pub struct Good { | ||
data: &'static u32, | ||
data2: [&'static u32; 2], | ||
aligned: [u8; 32], | ||
} | ||
|
||
fn main() { | ||
unsafe { | ||
let good = Good { data: &0, data2: [&0, &0], aligned: [0; 32] }; | ||
|
||
let _ = &good.data; //~ ERROR reference to packed field | ||
let _ = &good.data as *const _; //~ ERROR reference to packed field | ||
let _: *const _ = &good.data; //~ ERROR reference to packed field | ||
let _ = &good.data2[0]; //~ ERROR reference to packed field | ||
let _ = &*good.data; // ok, behind a pointer | ||
let _ = &good.aligned; // ok, has align 1 | ||
let _ = &good.aligned[2]; // ok, has align 1 | ||
} | ||
} |
This file contains 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,39 @@ | ||
error: reference to packed field is unaligned | ||
--> $DIR/unaligned_references.rs:14:17 | ||
| | ||
LL | let _ = &good.data; | ||
| ^^^^^^^^^^ | ||
| | ||
note: the lint level is defined here | ||
--> $DIR/unaligned_references.rs:1:9 | ||
| | ||
LL | #![deny(unaligned_references)] | ||
| ^^^^^^^^^^^^^^^^^^^^ | ||
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) | ||
|
||
error: reference to packed field is unaligned | ||
--> $DIR/unaligned_references.rs:15:17 | ||
| | ||
LL | let _ = &good.data as *const _; | ||
| ^^^^^^^^^^ | ||
| | ||
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) | ||
|
||
error: reference to packed field is unaligned | ||
--> $DIR/unaligned_references.rs:16:27 | ||
| | ||
LL | let _: *const _ = &good.data; | ||
| ^^^^^^^^^^ | ||
| | ||
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) | ||
|
||
error: reference to packed field is unaligned | ||
--> $DIR/unaligned_references.rs:17:17 | ||
| | ||
LL | let _ = &good.data2[0]; | ||
| ^^^^^^^^^^^^^^ | ||
| | ||
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) | ||
|
||
error: aborting due to 4 previous errors | ||
|
6e6bd63
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with the observation that "unaligned_reference" suggests a lint about any unaligned reference. We could use that, and then the lint may expand in the future. Or we could use a name specific to this lint, in which case I'd suggest
reference_to_packed
.