validator: Extend aliasing check to a call terminator

This commit is contained in:
Tomasz Miąsko 2020-10-30 00:00:00 +00:00
parent 388ef34904
commit b816e5dfb4

View File

@ -10,8 +10,8 @@ use rustc_middle::mir::{
visit::{PlaceContext, Visitor}, visit::{PlaceContext, Visitor},
}; };
use rustc_middle::mir::{ use rustc_middle::mir::{
AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, Rvalue, AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceRef,
SourceScope, Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo, Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo,
}; };
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
@ -46,7 +46,15 @@ impl<'tcx> MirPass<'tcx> for Validator {
.iterate_to_fixpoint() .iterate_to_fixpoint()
.into_results_cursor(body); .into_results_cursor(body);
TypeChecker { when: &self.when, body, tcx, param_env, mir_phase, storage_liveness } TypeChecker {
when: &self.when,
body,
tcx,
param_env,
mir_phase,
storage_liveness,
place_cache: Vec::new(),
}
.visit_body(body); .visit_body(body);
} }
} }
@ -150,6 +158,7 @@ struct TypeChecker<'a, 'tcx> {
param_env: ParamEnv<'tcx>, param_env: ParamEnv<'tcx>,
mir_phase: MirPhase, mir_phase: MirPhase,
storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive>, storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive>,
place_cache: Vec<PlaceRef<'tcx>>,
} }
impl<'a, 'tcx> TypeChecker<'a, 'tcx> { impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
@ -391,7 +400,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
self.check_edge(location, *unwind, EdgeKind::Unwind); self.check_edge(location, *unwind, EdgeKind::Unwind);
} }
} }
TerminatorKind::Call { func, destination, cleanup, .. } => { TerminatorKind::Call { func, args, destination, cleanup, .. } => {
let func_ty = func.ty(&self.body.local_decls, self.tcx); let func_ty = func.ty(&self.body.local_decls, self.tcx);
match func_ty.kind() { match func_ty.kind() {
ty::FnPtr(..) | ty::FnDef(..) => {} ty::FnPtr(..) | ty::FnDef(..) => {}
@ -406,6 +415,32 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
if let Some(cleanup) = cleanup { if let Some(cleanup) = cleanup {
self.check_edge(location, *cleanup, EdgeKind::Unwind); self.check_edge(location, *cleanup, EdgeKind::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.
self.place_cache.clear();
if let Some((destination, _)) = destination {
self.place_cache.push(destination.as_ref());
}
for arg in args {
if let Operand::Move(place) = arg {
self.place_cache.push(place.as_ref());
}
}
let all_len = self.place_cache.len();
self.place_cache.sort_unstable();
self.place_cache.dedup();
let has_duplicates = all_len != self.place_cache.len();
if has_duplicates {
self.fail(
location,
format!(
"encountered overlapping memory in `Call` terminator: {:?}",
terminator.kind,
),
);
}
} }
TerminatorKind::Assert { cond, target, cleanup, .. } => { TerminatorKind::Assert { cond, target, cleanup, .. } => {
let cond_ty = cond.ty(&self.body.local_decls, self.tcx); let cond_ty = cond.ty(&self.body.local_decls, self.tcx);