Skip to content

Commit

Permalink
Merge pull request rust-lang#272 from oli-obk/mir-validate
Browse files Browse the repository at this point in the history
Mir validate
  • Loading branch information
oli-obk authored Jul 26, 2017
2 parents 46324c2 + 791dbaf commit f906c54
Show file tree
Hide file tree
Showing 11 changed files with 898 additions and 46 deletions.
70 changes: 70 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/librustc_mir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ env_logger = "0.3.3"
log = "0.3.6"
log_settings = "0.1.1"
cargo_metadata = "0.2"
regex = "0.2.2"
lazy_static = "0.2.8"

[dev-dependencies]
compiletest_rs = "0.2.6"
55 changes: 54 additions & 1 deletion src/librustc_mir/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::error::Error;
use std::fmt;
use rustc::mir;
use rustc::ty::{FnSig, Ty, layout};
use memory::{MemoryPointer, Kind};
use memory::{MemoryPointer, LockInfo, AccessKind, Kind};
use rustc_const_math::ConstMathErr;
use syntax::codemap::Span;

Expand Down Expand Up @@ -51,6 +51,30 @@ pub enum EvalError<'tcx> {
required: u64,
has: u64,
},
MemoryLockViolation {
ptr: MemoryPointer,
len: u64,
frame: usize,
access: AccessKind,
lock: LockInfo,
},
MemoryAcquireConflict {
ptr: MemoryPointer,
len: u64,
kind: AccessKind,
lock: LockInfo,
},
InvalidMemoryLockRelease {
ptr: MemoryPointer,
len: u64,
frame: usize,
lock: LockInfo,
},
DeallocatedLockedMemory {
ptr: MemoryPointer,
lock: LockInfo,
},
ValidationFailure(String),
CalledClosureAsFunction,
VtableForArgumentlessMethod,
ModifiedConstantMemory,
Expand Down Expand Up @@ -97,6 +121,16 @@ impl<'tcx> Error for EvalError<'tcx> {
"pointer offset outside bounds of allocation",
InvalidNullPointerUsage =>
"invalid use of NULL pointer",
MemoryLockViolation { .. } =>
"memory access conflicts with lock",
MemoryAcquireConflict { .. } =>
"new memory lock conflicts with existing lock",
ValidationFailure(..) =>
"type validation failed",
InvalidMemoryLockRelease { .. } =>
"invalid attempt to release write lock",
DeallocatedLockedMemory { .. } =>
"tried to deallocate memory in conflict with a lock",
ReadPointerAsBytes =>
"a raw memory access tried to access part of a pointer value as raw bytes",
ReadBytesAsPointer =>
Expand Down Expand Up @@ -196,6 +230,25 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
if access { "memory access" } else { "pointer computed" },
ptr.offset, ptr.alloc_id, allocation_size)
},
MemoryLockViolation { ptr, len, frame, access, ref lock } => {
write!(f, "{:?} access by frame {} at {:?}, size {}, is in conflict with lock {:?}",
access, frame, ptr, len, lock)
}
MemoryAcquireConflict { ptr, len, kind, ref lock } => {
write!(f, "new {:?} lock at {:?}, size {}, is in conflict with lock {:?}",
kind, ptr, len, lock)
}
InvalidMemoryLockRelease { ptr, len, frame, ref lock } => {
write!(f, "frame {} tried to release memory write lock at {:?}, size {}, but cannot release lock {:?}",
frame, ptr, len, lock)
}
DeallocatedLockedMemory { ptr, ref lock } => {
write!(f, "tried to deallocate memory at {:?} in conflict with lock {:?}",
ptr, lock)
}
ValidationFailure(ref err) => {
write!(f, "type validation failed: {}", err)
}
NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
FunctionPointerTyMismatch(sig, got) =>
write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig, got),
Expand Down
34 changes: 31 additions & 3 deletions src/librustc_mir/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::fmt::Write;
use rustc::hir::def_id::DefId;
use rustc::hir::map::definitions::DefPathData;
use rustc::middle::const_val::ConstVal;
use rustc::middle::region::CodeExtent;
use rustc::mir;
use rustc::traits::Reveal;
use rustc::ty::layout::{self, Layout, Size};
Expand All @@ -21,6 +22,7 @@ use memory::{Memory, MemoryPointer, TlsKey, HasMemory};
use memory::Kind as MemoryKind;
use operator;
use value::{PrimVal, PrimValKind, Value, Pointer};
use validation::ValidationQuery;

pub struct EvalContext<'a, 'tcx: 'a> {
/// The results of the type checker, from rustc.
Expand All @@ -29,6 +31,11 @@ pub struct EvalContext<'a, 'tcx: 'a> {
/// The virtual memory system.
pub(crate) memory: Memory<'a, 'tcx>,

#[allow(dead_code)]
// FIXME(@RalfJung): validation branch
/// Lvalues that were suspended by the validation subsystem, and will be recovered later
pub(crate) suspended: HashMap<DynamicLifetime, Vec<ValidationQuery<'tcx>>>,

/// Precomputed statics, constants and promoteds.
pub(crate) globals: HashMap<GlobalId<'tcx>, Global<'tcx>>,

Expand Down Expand Up @@ -112,6 +119,12 @@ pub enum StackPopCleanup {
None,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct DynamicLifetime {
pub frame: usize,
pub region: Option<CodeExtent>, // "None" indicates "until the function ends"
}

#[derive(Copy, Clone, Debug)]
pub struct ResourceLimits {
pub memory_size: u64,
Expand All @@ -134,6 +147,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
EvalContext {
tcx,
memory: Memory::new(&tcx.data_layout, limits.memory_size),
suspended: HashMap::new(),
globals: HashMap::new(),
stack: Vec::new(),
stack_limit: limits.stack_limit,
Expand Down Expand Up @@ -169,6 +183,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
&self.stack
}

#[inline]
pub fn cur_frame(&self) -> usize {
assert!(self.stack.len() > 0);
self.stack.len() - 1
}

/// Returns true if the current frame or any parent frame is part of a ctfe.
///
/// Used to disable features in const eval, which do not have a rfc enabling
Expand Down Expand Up @@ -336,6 +356,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
stmt: 0,
});

let cur_frame = self.cur_frame();
self.memory.set_cur_frame(cur_frame);

if self.stack.len() > self.stack_limit {
Err(EvalError::StackFrameLimitReached)
} else {
Expand All @@ -345,7 +368,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {

pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
::log_settings::settings().indentation -= 1;
self.memory.locks_lifetime_ended(None);
let frame = self.stack.pop().expect("tried to pop a stack frame, but there were none");
if !self.stack.is_empty() {
// TODO: IS this the correct time to start considering these accesses as originating from the returned-to stack frame?
let cur_frame = self.cur_frame();
self.memory.set_cur_frame(cur_frame);
}
match frame.return_to_block {
StackPopCleanup::MarkStatic(mutable) => if let Lvalue::Global(id) = frame.return_lvalue {
let global_value = self.globals.get_mut(&id)
Expand Down Expand Up @@ -1551,9 +1580,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
if let Lvalue::Local { frame, local } = lvalue {
let mut allocs = Vec::new();
let mut msg = format!("{:?}", local);
let last_frame = self.stack.len() - 1;
if frame != last_frame {
write!(msg, " ({} frames up)", last_frame - frame).unwrap();
if frame != self.cur_frame() {
write!(msg, " ({} frames up)", self.cur_frame() - frame).unwrap();
}
write!(msg, ":").unwrap();

Expand Down
Loading

0 comments on commit f906c54

Please sign in to comment.