MIR validation: reject in-place argument/return for packed fields
This commit is contained in:
parent
0b31792ef1
commit
739144fc5b
@ -20,6 +20,8 @@
|
||||
use rustc_target::abi::{Size, FIRST_VARIANT};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::util::is_within_packed;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
enum EdgeKind {
|
||||
Unwind,
|
||||
@ -93,6 +95,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
cfg_checker.visit_body(body);
|
||||
cfg_checker.check_cleanup_control_flow();
|
||||
|
||||
// Also run the TypeChecker.
|
||||
for (location, msg) in validate_types(tcx, self.mir_phase, param_env, body) {
|
||||
cfg_checker.fail(location, msg);
|
||||
}
|
||||
@ -418,14 +421,34 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
|
||||
self.check_unwind_edge(location, *unwind);
|
||||
|
||||
// The call destination place and Operand::Move place used as an argument might be
|
||||
// passed by a reference to the callee. Consequently they must be non-overlapping.
|
||||
// Currently this simply checks for duplicate places.
|
||||
// passed by a reference to the callee. Consequently they must be non-overlapping
|
||||
// and cannot be packed. Currently this simply checks for duplicate places.
|
||||
self.place_cache.clear();
|
||||
self.place_cache.insert(destination.as_ref());
|
||||
if is_within_packed(self.tcx, &self.body.local_decls, *destination).is_some() {
|
||||
// This is bad! The callee will expect the memory to be aligned.
|
||||
self.fail(
|
||||
location,
|
||||
format!(
|
||||
"encountered packed place in `Call` terminator destination: {:?}",
|
||||
terminator.kind,
|
||||
),
|
||||
);
|
||||
}
|
||||
let mut has_duplicates = false;
|
||||
for arg in args {
|
||||
if let Operand::Move(place) = arg {
|
||||
has_duplicates |= !self.place_cache.insert(place.as_ref());
|
||||
if is_within_packed(self.tcx, &self.body.local_decls, *place).is_some() {
|
||||
// This is bad! The callee will expect the memory to be aligned.
|
||||
self.fail(
|
||||
location,
|
||||
format!(
|
||||
"encountered `Move` of a packed place in `Call` terminator: {:?}",
|
||||
terminator.kind,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,7 +456,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
|
||||
self.fail(
|
||||
location,
|
||||
format!(
|
||||
"encountered overlapping memory in `Call` terminator: {:?}",
|
||||
"encountered overlapping memory in `Move` arguments to `Call` terminator: {:?}",
|
||||
terminator.kind,
|
||||
),
|
||||
);
|
||||
@ -532,6 +555,8 @@ fn visit_source_scope(&mut self, scope: SourceScope) {
|
||||
}
|
||||
}
|
||||
|
||||
/// A faster version of the validation pass that only checks those things which may break when apply
|
||||
/// generic substitutions.
|
||||
pub fn validate_types<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mir_phase: MirPhase,
|
||||
|
@ -34,13 +34,14 @@ pub fn is_disaligned<'tcx, L>(
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
// We cannot figure out the layout. Conservatively assume that this is disaligned.
|
||||
debug!("is_disaligned({:?}) - true", place);
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_within_packed<'tcx, L>(
|
||||
pub fn is_within_packed<'tcx, L>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
local_decls: &L,
|
||||
place: Place<'tcx>,
|
||||
|
@ -5,7 +5,7 @@
|
||||
mod compare_types;
|
||||
mod type_name;
|
||||
|
||||
pub use self::alignment::is_disaligned;
|
||||
pub use self::alignment::{is_disaligned, is_within_packed};
|
||||
pub use self::check_validity_requirement::check_validity_requirement;
|
||||
pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype};
|
||||
pub use self::type_name::type_name;
|
||||
|
Loading…
Reference in New Issue
Block a user