From 55ce704ae75f0005b0bc7821e7e23fe07db0b5ab Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 30 May 2016 15:27:10 +0200 Subject: [PATCH 1/5] don't generate test suites --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 9b013809ba..66bbc729e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,10 @@ version = "0.1.0" [[bin]] doc = false name = "miri" +test = false + +[lib] +test = false [dependencies] byteorder = "0.4.2" From b78ca5f7e1e07d1f6e6980a1af0d7f4315978362 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 30 May 2016 15:27:52 +0200 Subject: [PATCH 2/5] replace `panic!`s with `Result` --- src/error.rs | 6 ++++++ src/interpreter.rs | 51 +++++++++++++++++++++++----------------------- src/memory.rs | 6 +++--- src/primval.rs | 37 ++++++++++++++++----------------- 4 files changed, 52 insertions(+), 48 deletions(-) diff --git a/src/error.rs b/src/error.rs index 65dd187fa0..ec75ab4452 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,5 +1,6 @@ use std::error::Error; use std::fmt; +use rustc::mir::repr as mir; #[derive(Clone, Debug)] pub enum EvalError { @@ -11,6 +12,8 @@ pub enum EvalError { ReadBytesAsPointer, InvalidPointerMath, ReadUndefBytes, + InvalidBoolOp(mir::BinOp), + Unimplemented(String), } pub type EvalResult = Result; @@ -34,6 +37,9 @@ impl Error for EvalError { "attempted to do math or a comparison on pointers into different allocations", EvalError::ReadUndefBytes => "attempted to read undefined bytes", + EvalError::InvalidBoolOp(_) => + "invalid boolean operation", + EvalError::Unimplemented(ref msg) => msg, } } diff --git a/src/interpreter.rs b/src/interpreter.rs index 8e8565b50c..8734427f07 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -392,11 +392,11 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { TerminatorTarget::Call } - abi => panic!("can't handle function with {:?} ABI", abi), + abi => return Err(EvalError::Unimplemented(format!("can't handle function with {:?} ABI", abi))), } } - _ => panic!("can't handle callee of type {:?}", func_ty), + _ => return Err(EvalError::Unimplemented(format!("can't handle callee of type {:?}", func_ty))), } } @@ -470,7 +470,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { } StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { - let offset = self.nonnull_offset(adt_ty, nndiscr, discrfield); + let offset = self.nonnull_offset(adt_ty, nndiscr, discrfield)?; let nonnull = adt_ptr.offset(offset.bytes() as isize); self.read_nonnull_discriminant_value(nonnull, nndiscr)? } @@ -620,7 +620,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { self.memory.write_uint(dest, n * elem_size, dest_size)?; } - _ => panic!("unimplemented: size_of_val::<{:?}>", ty), + _ => return Err(EvalError::Unimplemented(format!("unimplemented: size_of_val::<{:?}>", ty))), } } } @@ -631,7 +631,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { } "uninit" => self.memory.mark_definedness(dest, dest_size, false)?, - name => panic!("can't handle intrinsic: {}", name), + name => return Err(EvalError::Unimplemented(format!("unimplemented intrinsic: {}", name))), } // Since we pushed no stack frame, the main loop will act @@ -693,7 +693,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { self.memory.write_int(dest, result, dest_size)?; } - _ => panic!("can't call C ABI function: {}", link_name), + _ => return Err(EvalError::Unimplemented(format!("can't call C ABI function: {}", link_name))), } // Since we pushed no stack frame, the main loop will act @@ -748,7 +748,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { let ptr = self.eval_operand(operand)?; let ty = self.operand_ty(operand); let val = self.read_primval(ptr, ty)?; - self.memory.write_primval(dest, primval::unary_op(un_op, val))?; + self.memory.write_primval(dest, primval::unary_op(un_op, val)?)?; } Aggregate(ref kind, ref operands) => { @@ -809,7 +809,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { try!(self.assign_fields(dest, offsets, operands)); } else { assert_eq!(operands.len(), 0); - let offset = self.nonnull_offset(dest_ty, nndiscr, discrfield); + let offset = self.nonnull_offset(dest_ty, nndiscr, discrfield)?; let dest = dest.offset(offset.bytes() as isize); try!(self.memory.write_isize(dest, 0)); } @@ -834,8 +834,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { } } - _ => panic!("can't handle destination layout {:?} when assigning {:?}", - dest_layout, kind), + _ => return Err(EvalError::Unimplemented(format!("can't handle destination layout {:?} when assigning {:?}", dest_layout, kind))), } } @@ -904,7 +903,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { self.memory.write_usize(len_ptr, length as u64)?; } - _ => panic!("can't handle cast: {:?}", rvalue), + _ => return Err(EvalError::Unimplemented(format!("can't handle cast: {:?}", rvalue))), } } @@ -914,7 +913,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { self.memory.copy(src, dest, size)?; } - _ => panic!("can't handle cast: {:?}", rvalue), + _ => return Err(EvalError::Unimplemented(format!("can't handle cast: {:?}", rvalue))), } } @@ -925,7 +924,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { Ok(()) } - fn nonnull_offset(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> Size { + fn nonnull_offset(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> EvalResult { // Skip the constant 0 at the start meant for LLVM GEP. let mut path = discrfield.iter().skip(1).map(|&i| i as usize); @@ -946,49 +945,49 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { self.field_path_offset(inner_ty, path) } - fn field_path_offset>(&self, mut ty: Ty<'tcx>, path: I) -> Size { + fn field_path_offset>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult { let mut offset = Size::from_bytes(0); // Skip the initial 0 intended for LLVM GEP. for field_index in path { - let field_offset = self.get_field_offset(ty, field_index); - ty = self.get_field_ty(ty, field_index); + let field_offset = self.get_field_offset(ty, field_index)?; + ty = self.get_field_ty(ty, field_index)?; offset = offset.checked_add(field_offset, &self.tcx.data_layout).unwrap(); } - offset + Ok(offset) } - fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> Ty<'tcx> { + fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult> { match ty.sty { ty::TyStruct(adt_def, substs) => { - adt_def.struct_variant().fields[field_index].ty(self.tcx, substs) + Ok(adt_def.struct_variant().fields[field_index].ty(self.tcx, substs)) } ty::TyRef(_, ty::TypeAndMut { ty, .. }) | ty::TyRawPtr(ty::TypeAndMut { ty, .. }) | ty::TyBox(ty) => { assert_eq!(field_index, 0); - ty + Ok(ty) } - _ => panic!("can't handle type: {:?}", ty), + _ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}", ty))), } } - fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> Size { + fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult { let layout = self.type_layout(ty); use rustc::ty::layout::Layout::*; match *layout { Univariant { .. } => { assert_eq!(field_index, 0); - Size::from_bytes(0) + Ok(Size::from_bytes(0)) } FatPointer { .. } => { let bytes = layout::FAT_PTR_ADDR * self.memory.pointer_size; - Size::from_bytes(bytes as u64) + Ok(Size::from_bytes(bytes as u64)) } - _ => panic!("can't handle type: {:?}, with layout: {:?}", ty, layout), + _ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}, with layout: {:?}", ty, layout))), } } @@ -1223,7 +1222,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { Err(e) => return Err(e), } } else { - panic!("unimplemented: primitive read of fat pointer type: {:?}", ty); + return Err(EvalError::Unimplemented(format!("unimplemented: primitive read of fat pointer type: {:?}", ty))); } } diff --git a/src/memory.rs b/src/memory.rs index a42fd54669..d69e07ae2a 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -80,7 +80,7 @@ impl Memory { pub fn reallocate(&mut self, ptr: Pointer, new_size: usize) -> EvalResult<()> { if ptr.offset != 0 { // TODO(solson): Report error about non-__rust_allocate'd pointer. - panic!() + return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset))); } let alloc = self.get_mut(ptr.alloc_id)?; @@ -90,7 +90,7 @@ impl Memory { alloc.bytes.extend(iter::repeat(0).take(amount)); alloc.undef_mask.grow(amount, false); } else if size > new_size { - unimplemented!() + return Err(EvalError::Unimplemented(format!("unimplemented allocation relocation"))); // alloc.bytes.truncate(new_size); // alloc.undef_mask.len = new_size; // TODO: potentially remove relocations @@ -103,7 +103,7 @@ impl Memory { pub fn deallocate(&mut self, ptr: Pointer) -> EvalResult<()> { if ptr.offset != 0 { // TODO(solson): Report error about non-__rust_allocate'd pointer. - panic!() + return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset))); } if self.alloc_map.remove(&ptr.alloc_id).is_none() { diff --git a/src/primval.rs b/src/primval.rs index 19faadc962..0b1658739d 100644 --- a/src/primval.rs +++ b/src/primval.rs @@ -74,8 +74,7 @@ pub fn binary_op(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> EvalResul BitOr => l | r, BitXor => l ^ r, BitAnd => l & r, - Add | Sub | Mul | Div | Rem | Shl | Shr => - panic!("invalid binary operation on booleans: {:?}", bin_op), + Add | Sub | Mul | Div | Rem | Shl | Shr => return Err(EvalError::InvalidBoolOp(bin_op)), }) } @@ -99,33 +98,33 @@ pub fn binary_op(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> EvalResul Le => Bool(l <= r), Gt => Bool(l > r), Ge => Bool(l >= r), - _ => unimplemented!(), + _ => return Err(EvalError::Unimplemented(format!("unimplemented ptr op: {:?}", bin_op))), } } - _ => unimplemented!(), + (l, r) => return Err(EvalError::Unimplemented(format!("unimplemented binary op: {:?}, {:?}, {:?}", l, r, bin_op))), }; Ok(val) } -pub fn unary_op(un_op: mir::UnOp, val: PrimVal) -> PrimVal { +pub fn unary_op(un_op: mir::UnOp, val: PrimVal) -> EvalResult { use rustc::mir::repr::UnOp::*; use self::PrimVal::*; match (un_op, val) { - (Not, Bool(b)) => Bool(!b), - (Not, I8(n)) => I8(!n), - (Neg, I8(n)) => I8(-n), - (Not, I16(n)) => I16(!n), - (Neg, I16(n)) => I16(-n), - (Not, I32(n)) => I32(!n), - (Neg, I32(n)) => I32(-n), - (Not, I64(n)) => I64(!n), - (Neg, I64(n)) => I64(-n), - (Not, U8(n)) => U8(!n), - (Not, U16(n)) => U16(!n), - (Not, U32(n)) => U32(!n), - (Not, U64(n)) => U64(!n), - _ => unimplemented!(), + (Not, Bool(b)) => Ok(Bool(!b)), + (Not, I8(n)) => Ok(I8(!n)), + (Neg, I8(n)) => Ok(I8(-n)), + (Not, I16(n)) => Ok(I16(!n)), + (Neg, I16(n)) => Ok(I16(-n)), + (Not, I32(n)) => Ok(I32(!n)), + (Neg, I32(n)) => Ok(I32(-n)), + (Not, I64(n)) => Ok(I64(!n)), + (Neg, I64(n)) => Ok(I64(-n)), + (Not, U8(n)) => Ok(U8(!n)), + (Not, U16(n)) => Ok(U16(!n)), + (Not, U32(n)) => Ok(U32(!n)), + (Not, U64(n)) => Ok(U64(!n)), + _ => Err(EvalError::Unimplemented(format!("unimplemented unary op: {:?}, {:?}", un_op, val))), } } From 12c2e5fab27daaff5dada1fbc18d0b193a488ecd Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 31 May 2016 12:05:25 +0200 Subject: [PATCH 3/5] 4byte pointers --- src/error.rs | 13 ++++++++--- src/interpreter.rs | 42 ++++++++++++++++++++---------------- src/memory.rs | 19 ++++++++++------ tests/compile-fail/errors.rs | 6 ++++-- tests/compiletest.rs | 25 +++++++++++++-------- tests/run-pass/strings.rs | 5 +++++ 6 files changed, 71 insertions(+), 39 deletions(-) diff --git a/src/error.rs b/src/error.rs index ec75ab4452..c82b7fa1ca 100644 --- a/src/error.rs +++ b/src/error.rs @@ -7,7 +7,11 @@ pub enum EvalError { DanglingPointerDeref, InvalidBool, InvalidDiscriminant, - PointerOutOfBounds, + PointerOutOfBounds { + offset: usize, + size: usize, + len: usize, + }, ReadPointerAsBytes, ReadBytesAsPointer, InvalidPointerMath, @@ -27,7 +31,7 @@ impl Error for EvalError { "invalid boolean value read", EvalError::InvalidDiscriminant => "invalid enum discriminant value read", - EvalError::PointerOutOfBounds => + EvalError::PointerOutOfBounds { .. } => "pointer offset outside bounds of allocation", EvalError::ReadPointerAsBytes => "a raw memory access tried to access part of a pointer value as raw bytes", @@ -48,6 +52,9 @@ impl Error for EvalError { impl fmt::Display for EvalError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.description()) + match *self { + EvalError::PointerOutOfBounds { offset, size, len } => write!(f, "pointer offset ({} + {}) outside bounds ({}) of allocation", offset, size, len), + _ => write!(f, "{}", self.description()), + } } } diff --git a/src/interpreter.rs b/src/interpreter.rs index 8734427f07..bd8a5012b2 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -128,7 +128,11 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> { tcx: tcx, mir_map: mir_map, mir_cache: RefCell::new(DefIdMap()), - memory: Memory::new(), + memory: Memory::new(tcx.sess + .target + .uint_type + .bit_width() + .expect("Session::target::uint_type was usize")/8), substs_stack: Vec::new(), name_stack: Vec::new(), } @@ -1196,23 +1200,25 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> { pub fn read_primval(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult { use syntax::ast::{IntTy, UintTy}; - let val = match ty.sty { - ty::TyBool => PrimVal::Bool(self.memory.read_bool(ptr)?), - ty::TyInt(IntTy::I8) => PrimVal::I8(self.memory.read_int(ptr, 1)? as i8), - ty::TyInt(IntTy::I16) => PrimVal::I16(self.memory.read_int(ptr, 2)? as i16), - ty::TyInt(IntTy::I32) => PrimVal::I32(self.memory.read_int(ptr, 4)? as i32), - ty::TyInt(IntTy::I64) => PrimVal::I64(self.memory.read_int(ptr, 8)? as i64), - ty::TyUint(UintTy::U8) => PrimVal::U8(self.memory.read_uint(ptr, 1)? as u8), - ty::TyUint(UintTy::U16) => PrimVal::U16(self.memory.read_uint(ptr, 2)? as u16), - ty::TyUint(UintTy::U32) => PrimVal::U32(self.memory.read_uint(ptr, 4)? as u32), - ty::TyUint(UintTy::U64) => PrimVal::U64(self.memory.read_uint(ptr, 8)? as u64), - - // TODO(solson): Pick the PrimVal dynamically. - ty::TyInt(IntTy::Is) => PrimVal::I64(self.memory.read_isize(ptr)?), - ty::TyUint(UintTy::Us) => PrimVal::U64(self.memory.read_usize(ptr)?), - - ty::TyRef(_, ty::TypeAndMut { ty, .. }) | - ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => { + let val = match (self.memory.pointer_size, &ty.sty) { + (_, &ty::TyBool) => PrimVal::Bool(self.memory.read_bool(ptr)?), + (_, &ty::TyInt(IntTy::I8)) => PrimVal::I8(self.memory.read_int(ptr, 1)? as i8), + (2, &ty::TyInt(IntTy::Is)) | + (_, &ty::TyInt(IntTy::I16)) => PrimVal::I16(self.memory.read_int(ptr, 2)? as i16), + (4, &ty::TyInt(IntTy::Is)) | + (_, &ty::TyInt(IntTy::I32)) => PrimVal::I32(self.memory.read_int(ptr, 4)? as i32), + (8, &ty::TyInt(IntTy::Is)) | + (_, &ty::TyInt(IntTy::I64)) => PrimVal::I64(self.memory.read_int(ptr, 8)? as i64), + (_, &ty::TyUint(UintTy::U8)) => PrimVal::U8(self.memory.read_uint(ptr, 1)? as u8), + (2, &ty::TyUint(UintTy::Us)) | + (_, &ty::TyUint(UintTy::U16)) => PrimVal::U16(self.memory.read_uint(ptr, 2)? as u16), + (4, &ty::TyUint(UintTy::Us)) | + (_, &ty::TyUint(UintTy::U32)) => PrimVal::U32(self.memory.read_uint(ptr, 4)? as u32), + (8, &ty::TyUint(UintTy::Us)) | + (_, &ty::TyUint(UintTy::U64)) => PrimVal::U64(self.memory.read_uint(ptr, 8)? as u64), + + (_, &ty::TyRef(_, ty::TypeAndMut { ty, .. })) | + (_, &ty::TyRawPtr(ty::TypeAndMut { ty, .. })) => { if self.type_is_sized(ty) { match self.memory.read_ptr(ptr) { Ok(p) => PrimVal::AbstractPtr(p), diff --git a/src/memory.rs b/src/memory.rs index d69e07ae2a..7cc6a9a8e9 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -49,14 +49,11 @@ pub struct Memory { } impl Memory { - pub fn new() -> Self { + pub fn new(pointer_size: usize) -> Self { Memory { alloc_map: HashMap::new(), next_id: AllocId(0), - - // FIXME(solson): This should work for both 4 and 8, but it currently breaks some things - // when set to 4. - pointer_size: 8, + pointer_size: pointer_size, } } @@ -183,7 +180,11 @@ impl Memory { fn get_bytes_unchecked(&self, ptr: Pointer, size: usize) -> EvalResult<&[u8]> { let alloc = self.get(ptr.alloc_id)?; if ptr.offset + size > alloc.bytes.len() { - return Err(EvalError::PointerOutOfBounds); + return Err(EvalError::PointerOutOfBounds { + offset: ptr.offset, + size: size, + len: alloc.bytes.len(), + }); } Ok(&alloc.bytes[ptr.offset..ptr.offset + size]) } @@ -191,7 +192,11 @@ impl Memory { fn get_bytes_unchecked_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<&mut [u8]> { let alloc = self.get_mut(ptr.alloc_id)?; if ptr.offset + size > alloc.bytes.len() { - return Err(EvalError::PointerOutOfBounds); + return Err(EvalError::PointerOutOfBounds { + offset: ptr.offset, + size: size, + len: alloc.bytes.len(), + }); } Ok(&mut alloc.bytes[ptr.offset..ptr.offset + size]) } diff --git a/tests/compile-fail/errors.rs b/tests/compile-fail/errors.rs index 6ef9800a1a..1f7e3ce88c 100644 --- a/tests/compile-fail/errors.rs +++ b/tests/compile-fail/errors.rs @@ -6,7 +6,9 @@ fn overwriting_part_of_relocation_makes_the_rest_undefined() -> i32 { let mut p = &42; unsafe { let ptr: *mut _ = &mut p; - *(ptr as *mut u32) = 123; + *(ptr as *mut u8) = 123; // if we ever support 8 bit pointers, this is gonna cause + // "attempted to interpret some raw bytes as a pointer address" instead of + // "attempted to read undefined bytes" } *p //~ ERROR: attempted to read undefined bytes } @@ -34,7 +36,7 @@ fn undefined_byte_read() -> u8 { #[miri_run] fn out_of_bounds_read() -> u8 { let v: Vec = vec![1, 2]; - unsafe { *v.get_unchecked(5) } //~ ERROR: pointer offset outside bounds of allocation + unsafe { *v.get_unchecked(5) } //~ ERROR: pointer offset (5 + 1) outside bounds (2) of allocation } #[miri_run] diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 51634fd15b..184e282413 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -3,17 +3,24 @@ extern crate compiletest_rs as compiletest; use std::path::PathBuf; fn run_mode(mode: &'static str) { - let mut config = compiletest::default_config(); - config.rustc_path = "target/debug/miri".into(); - let path = std::env::var("RUST_SYSROOT").expect("env variable `RUST_SYSROOT` not set"); - config.target_rustcflags = Some(format!("--sysroot {}", path)); - config.host_rustcflags = Some(format!("--sysroot {}", path)); - let cfg_mode = mode.parse().ok().expect("Invalid mode"); + // FIXME: read directories in sysroot/lib/rustlib and generate the test targets from that + let targets = &["x86_64-unknown-linux-gnu", "i686-unknown-linux-gnu"]; - config.mode = cfg_mode; - config.src_base = PathBuf::from(format!("tests/{}", mode)); + for &target in targets { + let mut config = compiletest::default_config(); + config.rustc_path = "target/debug/miri".into(); + let path = std::env::var("RUST_SYSROOT").expect("env variable `RUST_SYSROOT` not set"); + config.run_lib_path = format!("{}/lib/rustlib/{}/lib", path, target); + let path = format!("--sysroot {}", path); + config.target_rustcflags = Some(path.clone()); + config.host_rustcflags = Some(path); + let cfg_mode = mode.parse().ok().expect("Invalid mode"); - compiletest::run_tests(&config); + config.mode = cfg_mode; + config.src_base = PathBuf::from(format!("tests/{}", mode)); + config.target = target.to_owned(); + compiletest::run_tests(&config); + } } #[test] diff --git a/tests/run-pass/strings.rs b/tests/run-pass/strings.rs index 3d71fa4e09..8092335116 100644 --- a/tests/run-pass/strings.rs +++ b/tests/run-pass/strings.rs @@ -21,4 +21,9 @@ fn hello_bytes_fat() -> &'static [u8] { b"Hello, world!" } +#[miri_run] +fn fat_pointer_on_32_bit() { + Some(5).expect("foo"); +} + fn main() {} From 29516c3129dbea594ea9b68f9bdf665dda909f44 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 1 Jun 2016 11:22:37 +0200 Subject: [PATCH 4/5] improve out of bounds error message --- src/error.rs | 10 +++++++--- src/memory.rs | 8 ++++---- tests/compile-fail/errors.rs | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/error.rs b/src/error.rs index c82b7fa1ca..7d252658ba 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,7 @@ use std::error::Error; use std::fmt; use rustc::mir::repr as mir; +use memory::Pointer; #[derive(Clone, Debug)] pub enum EvalError { @@ -8,9 +9,9 @@ pub enum EvalError { InvalidBool, InvalidDiscriminant, PointerOutOfBounds { - offset: usize, + ptr: Pointer, size: usize, - len: usize, + allocation_size: usize, }, ReadPointerAsBytes, ReadBytesAsPointer, @@ -53,7 +54,10 @@ impl Error for EvalError { impl fmt::Display for EvalError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - EvalError::PointerOutOfBounds { offset, size, len } => write!(f, "pointer offset ({} + {}) outside bounds ({}) of allocation", offset, size, len), + EvalError::PointerOutOfBounds { ptr, size, allocation_size } => { + write!(f, "memory access of {}..{} outside bounds of allocation {} which has size {}", + ptr.offset, ptr.offset + size, ptr.alloc_id, allocation_size) + }, _ => write!(f, "{}", self.description()), } } diff --git a/src/memory.rs b/src/memory.rs index 7cc6a9a8e9..6cae30d394 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -181,9 +181,9 @@ impl Memory { let alloc = self.get(ptr.alloc_id)?; if ptr.offset + size > alloc.bytes.len() { return Err(EvalError::PointerOutOfBounds { - offset: ptr.offset, + ptr: ptr, size: size, - len: alloc.bytes.len(), + allocation_size: alloc.bytes.len(), }); } Ok(&alloc.bytes[ptr.offset..ptr.offset + size]) @@ -193,9 +193,9 @@ impl Memory { let alloc = self.get_mut(ptr.alloc_id)?; if ptr.offset + size > alloc.bytes.len() { return Err(EvalError::PointerOutOfBounds { - offset: ptr.offset, + ptr: ptr, size: size, - len: alloc.bytes.len(), + allocation_size: alloc.bytes.len(), }); } Ok(&mut alloc.bytes[ptr.offset..ptr.offset + size]) diff --git a/tests/compile-fail/errors.rs b/tests/compile-fail/errors.rs index 1f7e3ce88c..0cadd76ccc 100644 --- a/tests/compile-fail/errors.rs +++ b/tests/compile-fail/errors.rs @@ -36,7 +36,7 @@ fn undefined_byte_read() -> u8 { #[miri_run] fn out_of_bounds_read() -> u8 { let v: Vec = vec![1, 2]; - unsafe { *v.get_unchecked(5) } //~ ERROR: pointer offset (5 + 1) outside bounds (2) of allocation + unsafe { *v.get_unchecked(5) } //~ ERROR: memory access of 5..6 outside bounds of allocation 11 which has size 2 } #[miri_run] From f910019da169a000d8b7bb0d031b4de2a0e420a9 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 1 Jun 2016 11:24:23 +0200 Subject: [PATCH 5/5] add a note to Memory::new mentioning tcx.data_layout --- src/memory.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/memory.rs b/src/memory.rs index 6cae30d394..728d5310f8 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -49,6 +49,7 @@ pub struct Memory { } impl Memory { + // FIXME: pass tcx.data_layout (This would also allow it to use primitive type alignments to diagnose unaligned memory accesses.) pub fn new(pointer_size: usize) -> Self { Memory { alloc_map: HashMap::new(),