Skip to content

Commit c815170

Browse files
committed
Merge pull request rust-lang#15 from oli-obk/step_by_step
4 byte pointers + tests
2 parents f3923ee + f910019 commit c815170

File tree

8 files changed

+132
-87
lines changed

8 files changed

+132
-87
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ version = "0.1.0"
99
[[bin]]
1010
doc = false
1111
name = "miri"
12+
test = false
13+
14+
[lib]
15+
test = false
1216

1317
[dependencies]
1418
byteorder = "0.4.2"

src/error.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
use std::error::Error;
22
use std::fmt;
3+
use rustc::mir::repr as mir;
4+
use memory::Pointer;
35

46
#[derive(Clone, Debug)]
57
pub enum EvalError {
68
DanglingPointerDeref,
79
InvalidBool,
810
InvalidDiscriminant,
9-
PointerOutOfBounds,
11+
PointerOutOfBounds {
12+
ptr: Pointer,
13+
size: usize,
14+
allocation_size: usize,
15+
},
1016
ReadPointerAsBytes,
1117
ReadBytesAsPointer,
1218
InvalidPointerMath,
1319
ReadUndefBytes,
20+
InvalidBoolOp(mir::BinOp),
21+
Unimplemented(String),
1422
}
1523

1624
pub type EvalResult<T> = Result<T, EvalError>;
@@ -24,7 +32,7 @@ impl Error for EvalError {
2432
"invalid boolean value read",
2533
EvalError::InvalidDiscriminant =>
2634
"invalid enum discriminant value read",
27-
EvalError::PointerOutOfBounds =>
35+
EvalError::PointerOutOfBounds { .. } =>
2836
"pointer offset outside bounds of allocation",
2937
EvalError::ReadPointerAsBytes =>
3038
"a raw memory access tried to access part of a pointer value as raw bytes",
@@ -34,6 +42,9 @@ impl Error for EvalError {
3442
"attempted to do math or a comparison on pointers into different allocations",
3543
EvalError::ReadUndefBytes =>
3644
"attempted to read undefined bytes",
45+
EvalError::InvalidBoolOp(_) =>
46+
"invalid boolean operation",
47+
EvalError::Unimplemented(ref msg) => msg,
3748
}
3849
}
3950

@@ -42,6 +53,12 @@ impl Error for EvalError {
4253

4354
impl fmt::Display for EvalError {
4455
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45-
write!(f, "{}", self.description())
56+
match *self {
57+
EvalError::PointerOutOfBounds { ptr, size, allocation_size } => {
58+
write!(f, "memory access of {}..{} outside bounds of allocation {} which has size {}",
59+
ptr.offset, ptr.offset + size, ptr.alloc_id, allocation_size)
60+
},
61+
_ => write!(f, "{}", self.description()),
62+
}
4663
}
4764
}

src/interpreter.rs

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,11 @@ impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> {
128128
tcx: tcx,
129129
mir_map: mir_map,
130130
mir_cache: RefCell::new(DefIdMap()),
131-
memory: Memory::new(),
131+
memory: Memory::new(tcx.sess
132+
.target
133+
.uint_type
134+
.bit_width()
135+
.expect("Session::target::uint_type was usize")/8),
132136
substs_stack: Vec::new(),
133137
name_stack: Vec::new(),
134138
}
@@ -392,11 +396,11 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
392396
TerminatorTarget::Call
393397
}
394398

395-
abi => panic!("can't handle function with {:?} ABI", abi),
399+
abi => return Err(EvalError::Unimplemented(format!("can't handle function with {:?} ABI", abi))),
396400
}
397401
}
398402

399-
_ => panic!("can't handle callee of type {:?}", func_ty),
403+
_ => return Err(EvalError::Unimplemented(format!("can't handle callee of type {:?}", func_ty))),
400404
}
401405
}
402406

@@ -470,7 +474,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
470474
}
471475

472476
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
473-
let offset = self.nonnull_offset(adt_ty, nndiscr, discrfield);
477+
let offset = self.nonnull_offset(adt_ty, nndiscr, discrfield)?;
474478
let nonnull = adt_ptr.offset(offset.bytes() as isize);
475479
self.read_nonnull_discriminant_value(nonnull, nndiscr)?
476480
}
@@ -620,7 +624,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
620624
self.memory.write_uint(dest, n * elem_size, dest_size)?;
621625
}
622626

623-
_ => panic!("unimplemented: size_of_val::<{:?}>", ty),
627+
_ => return Err(EvalError::Unimplemented(format!("unimplemented: size_of_val::<{:?}>", ty))),
624628
}
625629
}
626630
}
@@ -631,7 +635,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
631635
}
632636
"uninit" => self.memory.mark_definedness(dest, dest_size, false)?,
633637

634-
name => panic!("can't handle intrinsic: {}", name),
638+
name => return Err(EvalError::Unimplemented(format!("unimplemented intrinsic: {}", name))),
635639
}
636640

637641
// Since we pushed no stack frame, the main loop will act
@@ -693,7 +697,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
693697
self.memory.write_int(dest, result, dest_size)?;
694698
}
695699

696-
_ => panic!("can't call C ABI function: {}", link_name),
700+
_ => return Err(EvalError::Unimplemented(format!("can't call C ABI function: {}", link_name))),
697701
}
698702

699703
// Since we pushed no stack frame, the main loop will act
@@ -748,7 +752,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
748752
let ptr = self.eval_operand(operand)?;
749753
let ty = self.operand_ty(operand);
750754
let val = self.read_primval(ptr, ty)?;
751-
self.memory.write_primval(dest, primval::unary_op(un_op, val))?;
755+
self.memory.write_primval(dest, primval::unary_op(un_op, val)?)?;
752756
}
753757

754758
Aggregate(ref kind, ref operands) => {
@@ -809,7 +813,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
809813
try!(self.assign_fields(dest, offsets, operands));
810814
} else {
811815
assert_eq!(operands.len(), 0);
812-
let offset = self.nonnull_offset(dest_ty, nndiscr, discrfield);
816+
let offset = self.nonnull_offset(dest_ty, nndiscr, discrfield)?;
813817
let dest = dest.offset(offset.bytes() as isize);
814818
try!(self.memory.write_isize(dest, 0));
815819
}
@@ -834,8 +838,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
834838
}
835839
}
836840

837-
_ => panic!("can't handle destination layout {:?} when assigning {:?}",
838-
dest_layout, kind),
841+
_ => return Err(EvalError::Unimplemented(format!("can't handle destination layout {:?} when assigning {:?}", dest_layout, kind))),
839842
}
840843
}
841844

@@ -904,7 +907,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
904907
self.memory.write_usize(len_ptr, length as u64)?;
905908
}
906909

907-
_ => panic!("can't handle cast: {:?}", rvalue),
910+
_ => return Err(EvalError::Unimplemented(format!("can't handle cast: {:?}", rvalue))),
908911
}
909912
}
910913

@@ -914,7 +917,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
914917
self.memory.copy(src, dest, size)?;
915918
}
916919

917-
_ => panic!("can't handle cast: {:?}", rvalue),
920+
_ => return Err(EvalError::Unimplemented(format!("can't handle cast: {:?}", rvalue))),
918921
}
919922
}
920923

@@ -925,7 +928,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
925928
Ok(())
926929
}
927930

928-
fn nonnull_offset(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> Size {
931+
fn nonnull_offset(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> EvalResult<Size> {
929932
// Skip the constant 0 at the start meant for LLVM GEP.
930933
let mut path = discrfield.iter().skip(1).map(|&i| i as usize);
931934

@@ -946,49 +949,49 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
946949
self.field_path_offset(inner_ty, path)
947950
}
948951

949-
fn field_path_offset<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> Size {
952+
fn field_path_offset<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<Size> {
950953
let mut offset = Size::from_bytes(0);
951954

952955
// Skip the initial 0 intended for LLVM GEP.
953956
for field_index in path {
954-
let field_offset = self.get_field_offset(ty, field_index);
955-
ty = self.get_field_ty(ty, field_index);
957+
let field_offset = self.get_field_offset(ty, field_index)?;
958+
ty = self.get_field_ty(ty, field_index)?;
956959
offset = offset.checked_add(field_offset, &self.tcx.data_layout).unwrap();
957960
}
958961

959-
offset
962+
Ok(offset)
960963
}
961964

962-
fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> Ty<'tcx> {
965+
fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<Ty<'tcx>> {
963966
match ty.sty {
964967
ty::TyStruct(adt_def, substs) => {
965-
adt_def.struct_variant().fields[field_index].ty(self.tcx, substs)
968+
Ok(adt_def.struct_variant().fields[field_index].ty(self.tcx, substs))
966969
}
967970

968971
ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
969972
ty::TyRawPtr(ty::TypeAndMut { ty, .. }) |
970973
ty::TyBox(ty) => {
971974
assert_eq!(field_index, 0);
972-
ty
975+
Ok(ty)
973976
}
974-
_ => panic!("can't handle type: {:?}", ty),
977+
_ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}", ty))),
975978
}
976979
}
977980

978-
fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> Size {
981+
fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<Size> {
979982
let layout = self.type_layout(ty);
980983

981984
use rustc::ty::layout::Layout::*;
982985
match *layout {
983986
Univariant { .. } => {
984987
assert_eq!(field_index, 0);
985-
Size::from_bytes(0)
988+
Ok(Size::from_bytes(0))
986989
}
987990
FatPointer { .. } => {
988991
let bytes = layout::FAT_PTR_ADDR * self.memory.pointer_size;
989-
Size::from_bytes(bytes as u64)
992+
Ok(Size::from_bytes(bytes as u64))
990993
}
991-
_ => panic!("can't handle type: {:?}, with layout: {:?}", ty, layout),
994+
_ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}, with layout: {:?}", ty, layout))),
992995
}
993996
}
994997

@@ -1197,23 +1200,25 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
11971200

11981201
pub fn read_primval(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<PrimVal> {
11991202
use syntax::ast::{IntTy, UintTy};
1200-
let val = match ty.sty {
1201-
ty::TyBool => PrimVal::Bool(self.memory.read_bool(ptr)?),
1202-
ty::TyInt(IntTy::I8) => PrimVal::I8(self.memory.read_int(ptr, 1)? as i8),
1203-
ty::TyInt(IntTy::I16) => PrimVal::I16(self.memory.read_int(ptr, 2)? as i16),
1204-
ty::TyInt(IntTy::I32) => PrimVal::I32(self.memory.read_int(ptr, 4)? as i32),
1205-
ty::TyInt(IntTy::I64) => PrimVal::I64(self.memory.read_int(ptr, 8)? as i64),
1206-
ty::TyUint(UintTy::U8) => PrimVal::U8(self.memory.read_uint(ptr, 1)? as u8),
1207-
ty::TyUint(UintTy::U16) => PrimVal::U16(self.memory.read_uint(ptr, 2)? as u16),
1208-
ty::TyUint(UintTy::U32) => PrimVal::U32(self.memory.read_uint(ptr, 4)? as u32),
1209-
ty::TyUint(UintTy::U64) => PrimVal::U64(self.memory.read_uint(ptr, 8)? as u64),
1210-
1211-
// TODO(solson): Pick the PrimVal dynamically.
1212-
ty::TyInt(IntTy::Is) => PrimVal::I64(self.memory.read_isize(ptr)?),
1213-
ty::TyUint(UintTy::Us) => PrimVal::U64(self.memory.read_usize(ptr)?),
1214-
1215-
ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
1216-
ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => {
1203+
let val = match (self.memory.pointer_size, &ty.sty) {
1204+
(_, &ty::TyBool) => PrimVal::Bool(self.memory.read_bool(ptr)?),
1205+
(_, &ty::TyInt(IntTy::I8)) => PrimVal::I8(self.memory.read_int(ptr, 1)? as i8),
1206+
(2, &ty::TyInt(IntTy::Is)) |
1207+
(_, &ty::TyInt(IntTy::I16)) => PrimVal::I16(self.memory.read_int(ptr, 2)? as i16),
1208+
(4, &ty::TyInt(IntTy::Is)) |
1209+
(_, &ty::TyInt(IntTy::I32)) => PrimVal::I32(self.memory.read_int(ptr, 4)? as i32),
1210+
(8, &ty::TyInt(IntTy::Is)) |
1211+
(_, &ty::TyInt(IntTy::I64)) => PrimVal::I64(self.memory.read_int(ptr, 8)? as i64),
1212+
(_, &ty::TyUint(UintTy::U8)) => PrimVal::U8(self.memory.read_uint(ptr, 1)? as u8),
1213+
(2, &ty::TyUint(UintTy::Us)) |
1214+
(_, &ty::TyUint(UintTy::U16)) => PrimVal::U16(self.memory.read_uint(ptr, 2)? as u16),
1215+
(4, &ty::TyUint(UintTy::Us)) |
1216+
(_, &ty::TyUint(UintTy::U32)) => PrimVal::U32(self.memory.read_uint(ptr, 4)? as u32),
1217+
(8, &ty::TyUint(UintTy::Us)) |
1218+
(_, &ty::TyUint(UintTy::U64)) => PrimVal::U64(self.memory.read_uint(ptr, 8)? as u64),
1219+
1220+
(_, &ty::TyRef(_, ty::TypeAndMut { ty, .. })) |
1221+
(_, &ty::TyRawPtr(ty::TypeAndMut { ty, .. })) => {
12171222
if self.type_is_sized(ty) {
12181223
match self.memory.read_ptr(ptr) {
12191224
Ok(p) => PrimVal::AbstractPtr(p),
@@ -1223,7 +1228,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
12231228
Err(e) => return Err(e),
12241229
}
12251230
} else {
1226-
panic!("unimplemented: primitive read of fat pointer type: {:?}", ty);
1231+
return Err(EvalError::Unimplemented(format!("unimplemented: primitive read of fat pointer type: {:?}", ty)));
12271232
}
12281233
}
12291234

src/memory.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,12 @@ pub struct Memory {
4949
}
5050

5151
impl Memory {
52-
pub fn new() -> Self {
52+
// FIXME: pass tcx.data_layout (This would also allow it to use primitive type alignments to diagnose unaligned memory accesses.)
53+
pub fn new(pointer_size: usize) -> Self {
5354
Memory {
5455
alloc_map: HashMap::new(),
5556
next_id: AllocId(0),
56-
57-
// FIXME(solson): This should work for both 4 and 8, but it currently breaks some things
58-
// when set to 4.
59-
pointer_size: 8,
57+
pointer_size: pointer_size,
6058
}
6159
}
6260

@@ -80,7 +78,7 @@ impl Memory {
8078
pub fn reallocate(&mut self, ptr: Pointer, new_size: usize) -> EvalResult<()> {
8179
if ptr.offset != 0 {
8280
// TODO(solson): Report error about non-__rust_allocate'd pointer.
83-
panic!()
81+
return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset)));
8482
}
8583

8684
let alloc = self.get_mut(ptr.alloc_id)?;
@@ -90,7 +88,7 @@ impl Memory {
9088
alloc.bytes.extend(iter::repeat(0).take(amount));
9189
alloc.undef_mask.grow(amount, false);
9290
} else if size > new_size {
93-
unimplemented!()
91+
return Err(EvalError::Unimplemented(format!("unimplemented allocation relocation")));
9492
// alloc.bytes.truncate(new_size);
9593
// alloc.undef_mask.len = new_size;
9694
// TODO: potentially remove relocations
@@ -103,7 +101,7 @@ impl Memory {
103101
pub fn deallocate(&mut self, ptr: Pointer) -> EvalResult<()> {
104102
if ptr.offset != 0 {
105103
// TODO(solson): Report error about non-__rust_allocate'd pointer.
106-
panic!()
104+
return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset)));
107105
}
108106

109107
if self.alloc_map.remove(&ptr.alloc_id).is_none() {
@@ -183,15 +181,23 @@ impl Memory {
183181
fn get_bytes_unchecked(&self, ptr: Pointer, size: usize) -> EvalResult<&[u8]> {
184182
let alloc = self.get(ptr.alloc_id)?;
185183
if ptr.offset + size > alloc.bytes.len() {
186-
return Err(EvalError::PointerOutOfBounds);
184+
return Err(EvalError::PointerOutOfBounds {
185+
ptr: ptr,
186+
size: size,
187+
allocation_size: alloc.bytes.len(),
188+
});
187189
}
188190
Ok(&alloc.bytes[ptr.offset..ptr.offset + size])
189191
}
190192

191193
fn get_bytes_unchecked_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<&mut [u8]> {
192194
let alloc = self.get_mut(ptr.alloc_id)?;
193195
if ptr.offset + size > alloc.bytes.len() {
194-
return Err(EvalError::PointerOutOfBounds);
196+
return Err(EvalError::PointerOutOfBounds {
197+
ptr: ptr,
198+
size: size,
199+
allocation_size: alloc.bytes.len(),
200+
});
195201
}
196202
Ok(&mut alloc.bytes[ptr.offset..ptr.offset + size])
197203
}

0 commit comments

Comments
 (0)