Skip to content

Commit f906c54

Browse files
authored
Merge pull request rust-lang#272 from oli-obk/mir-validate
Mir validate
2 parents 46324c2 + 791dbaf commit f906c54

File tree

11 files changed

+898
-46
lines changed

11 files changed

+898
-46
lines changed

Cargo.lock

Lines changed: 70 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/librustc_mir/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ env_logger = "0.3.3"
3232
log = "0.3.6"
3333
log_settings = "0.1.1"
3434
cargo_metadata = "0.2"
35+
regex = "0.2.2"
36+
lazy_static = "0.2.8"
3537

3638
[dev-dependencies]
3739
compiletest_rs = "0.2.6"

src/librustc_mir/interpret/error.rs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::error::Error;
22
use std::fmt;
33
use rustc::mir;
44
use rustc::ty::{FnSig, Ty, layout};
5-
use memory::{MemoryPointer, Kind};
5+
use memory::{MemoryPointer, LockInfo, AccessKind, Kind};
66
use rustc_const_math::ConstMathErr;
77
use syntax::codemap::Span;
88

@@ -51,6 +51,30 @@ pub enum EvalError<'tcx> {
5151
required: u64,
5252
has: u64,
5353
},
54+
MemoryLockViolation {
55+
ptr: MemoryPointer,
56+
len: u64,
57+
frame: usize,
58+
access: AccessKind,
59+
lock: LockInfo,
60+
},
61+
MemoryAcquireConflict {
62+
ptr: MemoryPointer,
63+
len: u64,
64+
kind: AccessKind,
65+
lock: LockInfo,
66+
},
67+
InvalidMemoryLockRelease {
68+
ptr: MemoryPointer,
69+
len: u64,
70+
frame: usize,
71+
lock: LockInfo,
72+
},
73+
DeallocatedLockedMemory {
74+
ptr: MemoryPointer,
75+
lock: LockInfo,
76+
},
77+
ValidationFailure(String),
5478
CalledClosureAsFunction,
5579
VtableForArgumentlessMethod,
5680
ModifiedConstantMemory,
@@ -97,6 +121,16 @@ impl<'tcx> Error for EvalError<'tcx> {
97121
"pointer offset outside bounds of allocation",
98122
InvalidNullPointerUsage =>
99123
"invalid use of NULL pointer",
124+
MemoryLockViolation { .. } =>
125+
"memory access conflicts with lock",
126+
MemoryAcquireConflict { .. } =>
127+
"new memory lock conflicts with existing lock",
128+
ValidationFailure(..) =>
129+
"type validation failed",
130+
InvalidMemoryLockRelease { .. } =>
131+
"invalid attempt to release write lock",
132+
DeallocatedLockedMemory { .. } =>
133+
"tried to deallocate memory in conflict with a lock",
100134
ReadPointerAsBytes =>
101135
"a raw memory access tried to access part of a pointer value as raw bytes",
102136
ReadBytesAsPointer =>
@@ -196,6 +230,25 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
196230
if access { "memory access" } else { "pointer computed" },
197231
ptr.offset, ptr.alloc_id, allocation_size)
198232
},
233+
MemoryLockViolation { ptr, len, frame, access, ref lock } => {
234+
write!(f, "{:?} access by frame {} at {:?}, size {}, is in conflict with lock {:?}",
235+
access, frame, ptr, len, lock)
236+
}
237+
MemoryAcquireConflict { ptr, len, kind, ref lock } => {
238+
write!(f, "new {:?} lock at {:?}, size {}, is in conflict with lock {:?}",
239+
kind, ptr, len, lock)
240+
}
241+
InvalidMemoryLockRelease { ptr, len, frame, ref lock } => {
242+
write!(f, "frame {} tried to release memory write lock at {:?}, size {}, but cannot release lock {:?}",
243+
frame, ptr, len, lock)
244+
}
245+
DeallocatedLockedMemory { ptr, ref lock } => {
246+
write!(f, "tried to deallocate memory at {:?} in conflict with lock {:?}",
247+
ptr, lock)
248+
}
249+
ValidationFailure(ref err) => {
250+
write!(f, "type validation failed: {}", err)
251+
}
199252
NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
200253
FunctionPointerTyMismatch(sig, got) =>
201254
write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig, got),

src/librustc_mir/interpret/eval_context.rs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::fmt::Write;
44
use rustc::hir::def_id::DefId;
55
use rustc::hir::map::definitions::DefPathData;
66
use rustc::middle::const_val::ConstVal;
7+
use rustc::middle::region::CodeExtent;
78
use rustc::mir;
89
use rustc::traits::Reveal;
910
use rustc::ty::layout::{self, Layout, Size};
@@ -21,6 +22,7 @@ use memory::{Memory, MemoryPointer, TlsKey, HasMemory};
2122
use memory::Kind as MemoryKind;
2223
use operator;
2324
use value::{PrimVal, PrimValKind, Value, Pointer};
25+
use validation::ValidationQuery;
2426

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

34+
#[allow(dead_code)]
35+
// FIXME(@RalfJung): validation branch
36+
/// Lvalues that were suspended by the validation subsystem, and will be recovered later
37+
pub(crate) suspended: HashMap<DynamicLifetime, Vec<ValidationQuery<'tcx>>>,
38+
3239
/// Precomputed statics, constants and promoteds.
3340
pub(crate) globals: HashMap<GlobalId<'tcx>, Global<'tcx>>,
3441

@@ -112,6 +119,12 @@ pub enum StackPopCleanup {
112119
None,
113120
}
114121

122+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
123+
pub struct DynamicLifetime {
124+
pub frame: usize,
125+
pub region: Option<CodeExtent>, // "None" indicates "until the function ends"
126+
}
127+
115128
#[derive(Copy, Clone, Debug)]
116129
pub struct ResourceLimits {
117130
pub memory_size: u64,
@@ -134,6 +147,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
134147
EvalContext {
135148
tcx,
136149
memory: Memory::new(&tcx.data_layout, limits.memory_size),
150+
suspended: HashMap::new(),
137151
globals: HashMap::new(),
138152
stack: Vec::new(),
139153
stack_limit: limits.stack_limit,
@@ -169,6 +183,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
169183
&self.stack
170184
}
171185

186+
#[inline]
187+
pub fn cur_frame(&self) -> usize {
188+
assert!(self.stack.len() > 0);
189+
self.stack.len() - 1
190+
}
191+
172192
/// Returns true if the current frame or any parent frame is part of a ctfe.
173193
///
174194
/// Used to disable features in const eval, which do not have a rfc enabling
@@ -336,6 +356,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
336356
stmt: 0,
337357
});
338358

359+
let cur_frame = self.cur_frame();
360+
self.memory.set_cur_frame(cur_frame);
361+
339362
if self.stack.len() > self.stack_limit {
340363
Err(EvalError::StackFrameLimitReached)
341364
} else {
@@ -345,7 +368,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
345368

346369
pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
347370
::log_settings::settings().indentation -= 1;
371+
self.memory.locks_lifetime_ended(None);
348372
let frame = self.stack.pop().expect("tried to pop a stack frame, but there were none");
373+
if !self.stack.is_empty() {
374+
// TODO: IS this the correct time to start considering these accesses as originating from the returned-to stack frame?
375+
let cur_frame = self.cur_frame();
376+
self.memory.set_cur_frame(cur_frame);
377+
}
349378
match frame.return_to_block {
350379
StackPopCleanup::MarkStatic(mutable) => if let Lvalue::Global(id) = frame.return_lvalue {
351380
let global_value = self.globals.get_mut(&id)
@@ -1551,9 +1580,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
15511580
if let Lvalue::Local { frame, local } = lvalue {
15521581
let mut allocs = Vec::new();
15531582
let mut msg = format!("{:?}", local);
1554-
let last_frame = self.stack.len() - 1;
1555-
if frame != last_frame {
1556-
write!(msg, " ({} frames up)", last_frame - frame).unwrap();
1583+
if frame != self.cur_frame() {
1584+
write!(msg, " ({} frames up)", self.cur_frame() - frame).unwrap();
15571585
}
15581586
write!(msg, ":").unwrap();
15591587

0 commit comments

Comments
 (0)