diff options
| author | Ralf Jung <post@ralfj.de> | 2020-05-16 16:17:07 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2020-05-25 10:56:47 +0200 |
| commit | b27e649537770ba6631f3347974e3ae7e082adfe (patch) | |
| tree | ec0a3951fda5ac5407c65e326513f8d8b61d1cf8 | |
| parent | 2679c38fc33b5f69ce3c502c81315aa889035191 (diff) | |
| download | rust-b27e649537770ba6631f3347974e3ae7e082adfe.tar.gz rust-b27e649537770ba6631f3347974e3ae7e082adfe.zip | |
add a lint against references to packed fields
| -rw-r--r-- | src/librustc_mir/transform/check_packed_ref.rs | 66 | ||||
| -rw-r--r-- | src/librustc_mir/transform/mod.rs | 6 | ||||
| -rw-r--r-- | src/librustc_session/lint/builtin.rs | 9 | ||||
| -rw-r--r-- | src/test/ui/lint/packed_reference.rs | 25 | ||||
| -rw-r--r-- | src/test/ui/lint/packed_reference.stderr | 23 |
5 files changed, 127 insertions, 2 deletions
diff --git a/src/librustc_mir/transform/check_packed_ref.rs b/src/librustc_mir/transform/check_packed_ref.rs new file mode 100644 index 00000000000..9e07a4599f6 --- /dev/null +++ b/src/librustc_mir/transform/check_packed_ref.rs @@ -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::PACKED_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( + PACKED_REFERENCES, + lint_root, + source_info.span, + |lint| { + lint.build(&format!("reference to packed field is not allowed",)) + .note( + "fields of packed structs might be misaligned, and creating \ + a misaligned reference is undefined behavior (even if that \ + reference is never dereferenced)", + ) + .emit() + }, + ); + } + } + } +} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 0551ed5a15d..7d2f8903624 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -17,6 +17,7 @@ pub mod add_call_guards; pub mod add_moves_for_packed_drops; pub mod add_retag; pub mod check_consts; +pub mod check_packed_ref; pub mod check_unsafety; pub mod cleanup_post_borrowck; pub mod const_prop; @@ -211,10 +212,11 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs { validator.qualifs_in_return_place() } +/// Make MIR ready for const evaluation. This is run on all MIR, not just on consts! fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> Steal<Body<'_>> { let def_id = def_id.expect_local(); - // Unsafety check uses the raw mir, so make sure it is run + // Unsafety check uses the raw mir, so make sure it is run. let _ = tcx.unsafety_check_result(def_id); let mut body = tcx.mir_built(def_id).steal(); @@ -230,6 +232,8 @@ fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> Steal<Body<'_>> { None, MirPhase::Const, &[&[ + // MIR-level lints. + &check_packed_ref::CheckPackedRef, // What we need to do constant evaluation. &simplify::SimplifyCfg::new("initial"), &rustc_peek::SanityCheck, diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index 3d03e46683e..0753e9e4b73 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -217,9 +217,15 @@ declare_lint! { } declare_lint! { + pub PACKED_REFERENCES, + Allow, + "detects unaligned references to fields of packed structs", +} + +declare_lint! { pub SAFE_PACKED_BORROWS, Warn, - "safe borrows of fields of packed structs were was erroneously allowed", + "safe borrows of fields of packed structs were erroneously allowed", @future_incompatible = FutureIncompatibleInfo { reference: "issue #46043 <https://github.com/rust-lang/rust/issues/46043>", edition: None, @@ -545,6 +551,7 @@ declare_lint_pass! { INVALID_TYPE_PARAM_DEFAULT, CONST_ERR, RENAMED_AND_REMOVED_LINTS, + PACKED_REFERENCES, SAFE_PACKED_BORROWS, PATTERNS_IN_FNS_WITHOUT_BODY, MISSING_FRAGMENT_SPECIFIER, diff --git a/src/test/ui/lint/packed_reference.rs b/src/test/ui/lint/packed_reference.rs new file mode 100644 index 00000000000..d588ffd2120 --- /dev/null +++ b/src/test/ui/lint/packed_reference.rs @@ -0,0 +1,25 @@ +#![deny(packed_references)] + +#[repr(packed)] +pub struct Good { + data: &'static u32, + data2: [&'static u32; 2], + aligned: [u8; 32], +} + +#[repr(packed)] +pub struct JustArray { + array: [u32], +} + +fn main() { + unsafe { + let good = Good { data: &0, data2: [&0, &0], aligned: [0; 32] }; + + let _ = &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 + } +} diff --git a/src/test/ui/lint/packed_reference.stderr b/src/test/ui/lint/packed_reference.stderr new file mode 100644 index 00000000000..094fb4f34d3 --- /dev/null +++ b/src/test/ui/lint/packed_reference.stderr @@ -0,0 +1,23 @@ +error: reference to packed field is not allowed + --> $DIR/packed_reference.rs:19:17 + | +LL | let _ = &good.data; + | ^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/packed_reference.rs:1:9 + | +LL | #![deny(packed_references)] + | ^^^^^^^^^^^^^^^^^ + = note: fields of packed structs might be misaligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +error: reference to packed field is not allowed + --> $DIR/packed_reference.rs:20:17 + | +LL | let _ = &good.data2[0]; + | ^^^^^^^^^^^^^^ + | + = note: fields of packed structs might be misaligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +error: aborting due to 2 previous errors + |
