From a28c4b09527db98c964cd6a6222cc1cf01fb119a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 10 Feb 2016 15:18:34 +0100 Subject: [PATCH 1/8] refactor aggregates --- src/bin/miri.rs | 4 ++- src/interpreter.rs | 84 +++++++++++++++++++++++++++------------------- 2 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 7867526f26..92e81b58cd 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -24,6 +24,8 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn main() { - let args: Vec = std::env::args().collect(); + let mut args: Vec = std::env::args().collect(); + args.push(String::from("--sysroot")); + args.push(format!("{}/.multirust/toolchains/nightly", std::env::var("HOME").unwrap())); rustc_driver::run_compiler(&args, &mut MiriCompilerCalls); } diff --git a/src/interpreter.rs b/src/interpreter.rs index 764deac8d1..b461e815b8 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -17,18 +17,32 @@ enum Value { Pointer(Pointer), Adt { variant: usize, data_ptr: Pointer }, Func(def_id::DefId), + Aggregate(Vec), } #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -enum Pointer { +enum PointerKind { Stack(usize), // TODO(tsion): Heap } +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +struct Pointer { + projection: Vec, + kind: PointerKind, +} + impl Pointer { - fn offset(self, i: usize) -> Self { - match self { - Pointer::Stack(p) => Pointer::Stack(p + i), + fn offset(&self, offset: usize) -> Pointer { + Pointer { + projection: self.projection.iter().cloned().chain(Some(offset)).collect(), + kind: self.kind, + } + } + fn stack(ptr: usize) -> Pointer { + Pointer { + projection: Vec::new(), + kind: PointerKind::Stack(ptr), } } } @@ -65,12 +79,12 @@ struct Frame { num_args: usize, num_vars: usize, num_temps: usize, - num_aggregate_fields: usize, + num_alloc: usize, } impl Frame { fn size(&self) -> usize { - self.num_args + self.num_vars + self.num_temps + self.num_aggregate_fields + self.num_args + self.num_vars + self.num_temps + self.num_alloc } fn arg_offset(&self, i: usize) -> usize { @@ -110,7 +124,7 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { num_args: mir.arg_decls.len(), num_vars: mir.var_decls.len(), num_temps: mir.temp_decls.len(), - num_aggregate_fields: 0, + num_alloc: 0, }; self.value_stack.extend(iter::repeat(Value::Uninit).take(frame.size())); @@ -128,12 +142,12 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { self.value_stack.truncate(frame.offset); } - fn allocate_aggregate(&mut self, size: usize) -> Pointer { + fn stack_alloc(&mut self) -> Pointer { let frame = self.call_stack.last_mut().expect("missing call frame"); - frame.num_aggregate_fields += size; + frame.num_alloc += 1; - let ptr = Pointer::Stack(self.value_stack.len()); - self.value_stack.extend(iter::repeat(Value::Uninit).take(size)); + let ptr = Pointer::stack(self.value_stack.len()); + self.value_stack.push(Value::Uninit); ptr } @@ -237,10 +251,13 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { match *lvalue { mir::Lvalue::ReturnPointer => - frame.return_ptr.expect("ReturnPointer used in a function with no return value"), - mir::Lvalue::Arg(i) => Pointer::Stack(frame.arg_offset(i as usize)), - mir::Lvalue::Var(i) => Pointer::Stack(frame.var_offset(i as usize)), - mir::Lvalue::Temp(i) => Pointer::Stack(frame.temp_offset(i as usize)), + frame.return_ptr + .as_ref() + .expect("ReturnPointer used in a function with no return value") + .clone(), + mir::Lvalue::Arg(i) => Pointer::stack(frame.arg_offset(i as usize)), + mir::Lvalue::Var(i) => Pointer::stack(frame.var_offset(i as usize)), + mir::Lvalue::Temp(i) => Pointer::stack(frame.temp_offset(i as usize)), mir::Lvalue::Projection(ref proj) => { // proj.base: Lvalue @@ -330,20 +347,11 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { Value::Pointer(self.eval_lvalue(lvalue)) } - mir::Rvalue::Aggregate(mir::AggregateKind::Adt(ref adt_def, variant, _substs), + mir::Rvalue::Aggregate(mir::AggregateKind::Adt(_adt_def, variant, _substs), ref operands) => { - let max_fields = adt_def.variants - .iter() - .map(|v| v.fields.len()) - .max() - .unwrap_or(0); - - let ptr = self.allocate_aggregate(max_fields); - - for (i, operand) in operands.iter().enumerate() { - let val = self.eval_operand(operand); - self.write_pointer(ptr.offset(i), val); - } + let operands = operands.iter().map(|operand| self.eval_operand(operand)).collect(); + let ptr = self.stack_alloc(); + self.write_pointer(ptr.clone(), Value::Aggregate(operands)); Value::Adt { variant: variant, data_ptr: ptr } } @@ -390,14 +398,22 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { } fn read_pointer(&self, p: Pointer) -> Value { - match p { - Pointer::Stack(offset) => self.value_stack[offset].clone(), + let mut val = match p.kind { + PointerKind::Stack(offset) => &self.value_stack[offset], + }; + for offset in p.projection { + if let Value::Aggregate(ref v) = *val { + val = &v[offset]; + } else { + panic!("tried to offset a non-aggregate"); + } } + val.clone() } fn write_pointer(&mut self, p: Pointer, val: Value) { - match p { - Pointer::Stack(offset) => self.value_stack[offset] = val, + match p.kind { + PointerKind::Stack(offset) => self.value_stack[offset] = val, } } } @@ -411,8 +427,8 @@ pub fn interpret_start_points<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &MirMap<'tcx> println!("Interpreting: {}", item.name); let mut interpreter = Interpreter::new(tcx, mir_map); - let return_ptr = Pointer::Stack(0); - interpreter.call(mir, &[], Some(return_ptr)); + let return_ptr = Pointer::stack(0); + interpreter.call(mir, &[], Some(return_ptr.clone())); let val_str = format!("{:?}", interpreter.read_pointer(return_ptr)); if !check_expected(&val_str, attr) { From 88e7c12982f0fe68b5a2eb32d1a25741e51bd4a3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 10 Feb 2016 15:19:02 +0100 Subject: [PATCH 2/8] add heap --- src/interpreter.rs | 31 ++++++++++++++++++++++++++++++- test/basic.rs | 9 ++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/interpreter.rs b/src/interpreter.rs index b461e815b8..430d9e11a1 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -6,6 +6,7 @@ use syntax::ast::Attribute; use syntax::attr::AttrMetaMethods; use std::iter; +use std::collections::HashMap; const TRACE_EXECUTION: bool = false; @@ -23,7 +24,7 @@ enum Value { #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] enum PointerKind { Stack(usize), - // TODO(tsion): Heap + Heap(usize), } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] @@ -45,6 +46,12 @@ impl Pointer { kind: PointerKind::Stack(ptr), } } + fn heap(ptr: usize) -> Pointer { + Pointer { + projection: Vec::new(), + kind: PointerKind::Heap(ptr), + } + } } /// A stack frame: @@ -105,6 +112,8 @@ struct Interpreter<'a, 'tcx: 'a> { mir_map: &'a MirMap<'tcx>, value_stack: Vec, call_stack: Vec, + heap: HashMap, + heap_idx: usize, } impl<'a, 'tcx> Interpreter<'a, 'tcx> { @@ -114,6 +123,8 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { mir_map: mir_map, value_stack: vec![Value::Uninit], // Allocate a spot for the top-level return value. call_stack: Vec::new(), + heap: HashMap::new(), + heap_idx: 1, } } @@ -356,6 +367,8 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { Value::Adt { variant: variant, data_ptr: ptr } } + mir::Rvalue::Box(_) => Value::Pointer(self.heap_alloc()), + ref r => panic!("can't handle rvalue: {:?}", r), } } @@ -400,6 +413,10 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { fn read_pointer(&self, p: Pointer) -> Value { let mut val = match p.kind { PointerKind::Stack(offset) => &self.value_stack[offset], + PointerKind::Heap(idx) => { + debug_assert!(idx < self.heap_idx, "use before alloc"); + self.heap.get(&idx).expect("use after free") + }, }; for offset in p.projection { if let Value::Aggregate(ref v) = *val { @@ -414,8 +431,20 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { fn write_pointer(&mut self, p: Pointer, val: Value) { match p.kind { PointerKind::Stack(offset) => self.value_stack[offset] = val, + PointerKind::Heap(idx) => { + debug_assert!(idx < self.heap_idx, "use before alloc"); + *self.heap.get_mut(&idx).expect("use after free") = val; + }, + } } + + fn heap_alloc(&mut self) -> Pointer { + let idx = self.heap_idx; + self.heap_idx += 1; + assert!(self.heap.insert(idx, Value::Uninit).is_none()); + Pointer::heap(idx) + } } pub fn interpret_start_points<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &MirMap<'tcx>) { diff --git a/test/basic.rs b/test/basic.rs index 70bb9c3bb8..6fba25ec25 100644 --- a/test/basic.rs +++ b/test/basic.rs @@ -1,4 +1,4 @@ -#![feature(custom_attribute)] +#![feature(custom_attribute, box_syntax)] #![allow(dead_code, unused_attributes)] #[miri_run(expected = "Int(1)")] @@ -173,4 +173,11 @@ fn cross_crate_fn_call() -> i32 { if 1i32.is_positive() { 1 } else { 0 } } +/// Test boxing and unboxing a value +#[miri_run(expected = "Int(42)")] +fn boxing() -> i32 { + let x = box 42; + *x +} + fn main() {} From 35ecb135d805b20c6f0041d744b0402eeca95334 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 10 Feb 2016 15:19:26 +0100 Subject: [PATCH 3/8] implement debug logging --- Cargo.lock | 57 ++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 4 ++++ src/bin/miri.rs | 2 ++ src/interpreter.rs | 13 ++++++++--- src/lib.rs | 1 + 5 files changed, 74 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b86c754ccd..ff8ac3a9f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,4 +1,61 @@ [root] name = "miri" version = "0.1.0" +dependencies = [ + "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "aho-corasick" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "env_logger" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.48 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "log" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memchr" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index 9396477cd3..78db058621 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,7 @@ license = "ISC" [[bin]] name = "miri" doc = false + +[dependencies] +log = "*" +env_logger = "*" diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 92e81b58cd..cf5187e301 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -3,6 +3,7 @@ extern crate miri; extern crate rustc; extern crate rustc_driver; +extern crate env_logger; use miri::interpreter; use rustc::session::Session; @@ -24,6 +25,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn main() { + env_logger::init().unwrap(); let mut args: Vec = std::env::args().collect(); args.push(String::from("--sysroot")); args.push(format!("{}/.multirust/toolchains/nightly", std::env::var("HOME").unwrap())); diff --git a/src/interpreter.rs b/src/interpreter.rs index 430d9e11a1..8acf9063b0 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -278,10 +278,12 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { match proj.elem { mir::ProjectionElem::Field(field) => { + debug!("field index: {:?}", field); base_ptr.offset(field.index()) } mir::ProjectionElem::Downcast(_, variant) => { + debug!("downcast: {:?}", variant); let adt_val = self.read_pointer(base_ptr); if let Value::Adt { variant: actual_variant, data_ptr } = adt_val { debug_assert_eq!(variant, actual_variant); @@ -292,6 +294,7 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { } mir::ProjectionElem::Deref => { + debug!("deref"); let ptr_val = self.read_pointer(base_ptr); if let Value::Pointer(ptr) = ptr_val { ptr @@ -407,10 +410,12 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { } fn read_lvalue(&self, lvalue: &mir::Lvalue) -> Value { + debug!("read_lvalue: {:?}", lvalue); self.read_pointer(self.eval_lvalue(lvalue)) } fn read_pointer(&self, p: Pointer) -> Value { + debug!("read_pointer: {:?}", p); let mut val = match p.kind { PointerKind::Stack(offset) => &self.value_stack[offset], PointerKind::Heap(idx) => { @@ -453,7 +458,7 @@ pub fn interpret_start_points<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &MirMap<'tcx> if attr.check_name("miri_run") { let item = tcx.map.expect_item(id); - println!("Interpreting: {}", item.name); + print!("Interpreting: {}... ", item.name); let mut interpreter = Interpreter::new(tcx, mir_map); let return_ptr = Pointer::stack(0); @@ -475,9 +480,11 @@ fn check_expected(actual: &str, attr: &Attribute) -> bool { let expected = meta_item.value_str().unwrap(); if actual == &expected[..] { - println!("Test passed!\n"); + println!("ok"); } else { - println!("Actual value:\t{}\nExpected value:\t{}\n", actual, expected); + println!("FAILED"); + println!("\tActual value:\t{}", actual); + println!("\tExpected value:\t{}", expected); } return true; diff --git a/src/lib.rs b/src/lib.rs index da83e7db92..14391d5bba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,5 +3,6 @@ extern crate rustc; extern crate rustc_mir; extern crate syntax; +#[macro_use] extern crate log; pub mod interpreter; From b85780e372c670cb7fa4f25141334891d55a52c4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 10 Feb 2016 15:19:52 +0100 Subject: [PATCH 4/8] typo --- src/interpreter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interpreter.rs b/src/interpreter.rs index 8acf9063b0..fab623446d 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -79,7 +79,7 @@ impl Pointer { #[derive(Debug)] struct Frame { /// A pointer to a stack cell to write the return value of the current call, if it's not a - /// divering call. + /// diverging call. return_ptr: Option, offset: usize, From 794844b757691be6ca35a9236ed29736a0402c81 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 10 Feb 2016 15:57:25 +0100 Subject: [PATCH 5/8] port flag-style debugging to log-style --- src/interpreter.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/interpreter.rs b/src/interpreter.rs index fab623446d..f595282ac3 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -8,8 +8,6 @@ use syntax::attr::AttrMetaMethods; use std::iter; use std::collections::HashMap; -const TRACE_EXECUTION: bool = false; - #[derive(Clone, Debug, PartialEq)] enum Value { Uninit, @@ -163,15 +161,16 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { } fn call(&mut self, mir: &Mir, args: &[Value], return_ptr: Option) { + debug!("call"); self.push_stack_frame(mir, args, return_ptr); let mut block = mir::START_BLOCK; loop { - if TRACE_EXECUTION { println!("Entering block: {:?}", block); } + debug!("Entering block: {:?}", block); let block_data = mir.basic_block_data(block); for stmt in &block_data.statements { - if TRACE_EXECUTION { println!("{:?}", stmt); } + debug!("{:?}", stmt); match stmt.kind { mir::StatementKind::Assign(ref lvalue, ref rvalue) => { @@ -186,7 +185,7 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { } } - if TRACE_EXECUTION { println!("{:?}", block_data.terminator()); } + debug!("{:?}", block_data.terminator()); match *block_data.terminator() { mir::Terminator::Return => break, @@ -340,6 +339,7 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { } fn eval_rvalue(&mut self, rvalue: &mir::Rvalue) -> Value { + debug!("eval_rvalue: {:?}", rvalue); match *rvalue { mir::Rvalue::Use(ref operand) => self.eval_operand(operand), From f0cff7a9011b05fb65978279c622fb1931c88f70 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 10 Feb 2016 15:57:45 +0100 Subject: [PATCH 6/8] make sure we never read from an uninit value --- src/interpreter.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/interpreter.rs b/src/interpreter.rs index f595282ac3..a94e4017e8 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -430,6 +430,9 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { panic!("tried to offset a non-aggregate"); } } + if let Value::Uninit = *val { + panic!("reading uninitialized value at {:?}", p); + } val.clone() } From 119a1f8fd7772db2ab9ededd656f067639a263c5 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 10 Feb 2016 15:58:16 +0100 Subject: [PATCH 7/8] create a stack per frame --- src/interpreter.rs | 87 ++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/src/interpreter.rs b/src/interpreter.rs index a94e4017e8..4db863acec 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -5,7 +5,6 @@ use rustc_mir::mir_map::MirMap; use syntax::ast::Attribute; use syntax::attr::AttrMetaMethods; -use std::iter; use std::collections::HashMap; #[derive(Clone, Debug, PartialEq)] @@ -21,7 +20,7 @@ enum Value { #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] enum PointerKind { - Stack(usize), + Stack { frame: usize, stack: usize }, Heap(usize), } @@ -38,12 +37,14 @@ impl Pointer { kind: self.kind, } } - fn stack(ptr: usize) -> Pointer { + + fn stack(frame: usize, stack: usize) -> Pointer { Pointer { projection: Vec::new(), - kind: PointerKind::Stack(ptr), + kind: PointerKind::Stack { frame: frame, stack: stack }, } } + fn heap(ptr: usize) -> Pointer { Pointer { projection: Vec::new(), @@ -79,36 +80,42 @@ struct Frame { /// A pointer to a stack cell to write the return value of the current call, if it's not a /// diverging call. return_ptr: Option, + stack: Vec, - offset: usize, num_args: usize, num_vars: usize, num_temps: usize, - num_alloc: usize, + + id: usize, } impl Frame { - fn size(&self) -> usize { - self.num_args + self.num_vars + self.num_temps + self.num_alloc - } - fn arg_offset(&self, i: usize) -> usize { - self.offset + i + i } fn var_offset(&self, i: usize) -> usize { - self.offset + self.num_args + i + self.num_args + i } fn temp_offset(&self, i: usize) -> usize { - self.offset + self.num_args + self.num_vars + i + self.num_args + self.num_vars + i + } + + fn stack_alloc(&mut self) -> Pointer { + let ptr = Pointer::stack(self.id, self.stack.len()); + self.stack.push(Value::Uninit); + ptr + } + + fn stack_ptr(&self, idx: usize) -> Pointer { + Pointer::stack(self.id, idx) } } struct Interpreter<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, mir_map: &'a MirMap<'tcx>, - value_stack: Vec, call_stack: Vec, heap: HashMap, heap_idx: usize, @@ -119,7 +126,6 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { Interpreter { tcx: tcx, mir_map: mir_map, - value_stack: vec![Value::Uninit], // Allocate a spot for the top-level return value. call_stack: Vec::new(), heap: HashMap::new(), heap_idx: 1, @@ -127,19 +133,18 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { } fn push_stack_frame(&mut self, mir: &Mir, args: &[Value], return_ptr: Option) { - let frame = Frame { + let mut frame = Frame { return_ptr: return_ptr, - offset: self.value_stack.len(), num_args: mir.arg_decls.len(), num_vars: mir.var_decls.len(), num_temps: mir.temp_decls.len(), - num_alloc: 0, + stack: vec![Value::Uninit; mir.arg_decls.len() + mir.var_decls.len() + mir.temp_decls.len()], + id: self.call_stack.len(), }; - self.value_stack.extend(iter::repeat(Value::Uninit).take(frame.size())); - for (i, arg) in args.iter().enumerate() { - self.value_stack[frame.arg_offset(i)] = arg.clone(); + let i = frame.arg_offset(i); + frame.stack[i] = arg.clone(); } self.call_stack.push(frame); @@ -147,17 +152,7 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { } fn pop_stack_frame(&mut self) { - let frame = self.call_stack.pop().expect("tried to pop stack frame, but there were none"); - self.value_stack.truncate(frame.offset); - } - - fn stack_alloc(&mut self) -> Pointer { - let frame = self.call_stack.last_mut().expect("missing call frame"); - frame.num_alloc += 1; - - let ptr = Pointer::stack(self.value_stack.len()); - self.value_stack.push(Value::Uninit); - ptr + self.call_stack.pop().expect("tried to pop stack frame, but there were none"); } fn call(&mut self, mir: &Mir, args: &[Value], return_ptr: Option) { @@ -256,8 +251,16 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { self.pop_stack_frame(); } + fn frame(&self) -> &Frame { + self.call_stack.last().expect("missing call frame") + } + + fn frame_mut(&mut self) -> &mut Frame { + self.call_stack.last_mut().expect("missing call frame") + } + fn eval_lvalue(&self, lvalue: &mir::Lvalue) -> Pointer { - let frame = self.call_stack.last().expect("missing call frame"); + let frame = self.frame(); match *lvalue { mir::Lvalue::ReturnPointer => @@ -265,9 +268,9 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { .as_ref() .expect("ReturnPointer used in a function with no return value") .clone(), - mir::Lvalue::Arg(i) => Pointer::stack(frame.arg_offset(i as usize)), - mir::Lvalue::Var(i) => Pointer::stack(frame.var_offset(i as usize)), - mir::Lvalue::Temp(i) => Pointer::stack(frame.temp_offset(i as usize)), + mir::Lvalue::Arg(i) => frame.stack_ptr(frame.arg_offset(i as usize)), + mir::Lvalue::Var(i) => frame.stack_ptr(frame.var_offset(i as usize)), + mir::Lvalue::Temp(i) => frame.stack_ptr(frame.temp_offset(i as usize)), mir::Lvalue::Projection(ref proj) => { // proj.base: Lvalue @@ -364,7 +367,7 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { mir::Rvalue::Aggregate(mir::AggregateKind::Adt(_adt_def, variant, _substs), ref operands) => { let operands = operands.iter().map(|operand| self.eval_operand(operand)).collect(); - let ptr = self.stack_alloc(); + let ptr = self.frame_mut().stack_alloc(); self.write_pointer(ptr.clone(), Value::Aggregate(operands)); Value::Adt { variant: variant, data_ptr: ptr } @@ -417,15 +420,15 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { fn read_pointer(&self, p: Pointer) -> Value { debug!("read_pointer: {:?}", p); let mut val = match p.kind { - PointerKind::Stack(offset) => &self.value_stack[offset], + PointerKind::Stack{ frame, stack } => &self.call_stack[frame].stack[stack], PointerKind::Heap(idx) => { debug_assert!(idx < self.heap_idx, "use before alloc"); self.heap.get(&idx).expect("use after free") }, }; - for offset in p.projection { + for offset in &p.projection { if let Value::Aggregate(ref v) = *val { - val = &v[offset]; + val = &v[*offset]; } else { panic!("tried to offset a non-aggregate"); } @@ -438,7 +441,7 @@ impl<'a, 'tcx> Interpreter<'a, 'tcx> { fn write_pointer(&mut self, p: Pointer, val: Value) { match p.kind { - PointerKind::Stack(offset) => self.value_stack[offset] = val, + PointerKind::Stack{ frame, stack } => self.call_stack[frame].stack[stack] = val, PointerKind::Heap(idx) => { debug_assert!(idx < self.heap_idx, "use before alloc"); *self.heap.get_mut(&idx).expect("use after free") = val; @@ -464,7 +467,7 @@ pub fn interpret_start_points<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &MirMap<'tcx> print!("Interpreting: {}... ", item.name); let mut interpreter = Interpreter::new(tcx, mir_map); - let return_ptr = Pointer::stack(0); + let return_ptr = interpreter.heap_alloc(); interpreter.call(mir, &[], Some(return_ptr.clone())); let val_str = format!("{:?}", interpreter.read_pointer(return_ptr)); From c5c1028f3d968a92b49990346c755fc01c0681e2 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 10 Feb 2016 15:58:32 +0100 Subject: [PATCH 8/8] abort after finding one `miri_run` attribute --- src/interpreter.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/interpreter.rs b/src/interpreter.rs index 4db863acec..2e0ed9a3ea 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -474,6 +474,7 @@ pub fn interpret_start_points<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &MirMap<'tcx> if !check_expected(&val_str, attr) { println!("=> {}\n", val_str); } + break; } } }