Skip to content
11 changes: 6 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ before_script:
- cargo install xargo
- export RUST_SYSROOT=$HOME/rust
script:
- |
# get ourselves a MIR-ful libstd
cd xargo &&
RUSTFLAGS='-Zalways-encode-mir' xargo build &&
cd ..
- |
# Test plain miri
cargo build &&
Expand All @@ -22,11 +27,7 @@ script:
cargo miri test &&
cd ..
- |
# get ourselves a MIR-ful libstd
cd xargo &&
RUSTFLAGS='-Zalways-encode-mir' xargo build &&
cd .. &&
# and run the tests with it
# and run all tests with full mir
MIRI_SYSROOT=~/.xargo/HOST cargo test
notifications:
email:
Expand Down
9 changes: 4 additions & 5 deletions src/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use syntax::ast::{FloatTy, IntTy, UintTy};

use error::{EvalResult, EvalError};
use eval_context::EvalContext;
use memory::Pointer;
use value::PrimVal;

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Expand All @@ -24,7 +23,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {

Bool | Char | U8 | U16 | U32 | U64 | U128 => self.cast_int(val.to_u128()?, dest_ty, false),

FnPtr | Ptr => self.cast_ptr(val.to_ptr()?, dest_ty),
FnPtr | Ptr => self.cast_ptr(val, dest_ty),
}
}

Expand Down Expand Up @@ -71,7 +70,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
TyChar => Err(EvalError::InvalidChar(v)),

TyRawPtr(_) => Ok(PrimVal::Ptr(Pointer::from_int(v as u64))),
TyRawPtr(_) => Ok(PrimVal::Bytes(v % (1 << self.memory.pointer_size()))),

_ => Err(EvalError::Unimplemented(format!("int to {:?} cast", ty))),
}
Expand All @@ -92,11 +91,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
}
}

fn cast_ptr(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
fn cast_ptr(&self, ptr: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*;
match ty.sty {
TyRef(..) | TyRawPtr(_) | TyFnPtr(_) | TyInt(_) | TyUint(_) =>
Ok(PrimVal::Ptr(ptr)),
Ok(ptr),
_ => Err(EvalError::Unimplemented(format!("ptr to {:?} cast", ty))),
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub enum EvalError<'tcx> {
allocation_size: u64,
},
ReadPointerAsBytes,
ReadBytesAsPointer,
InvalidPointerMath,
ReadUndefBytes,
DeadLocal,
Expand Down Expand Up @@ -81,6 +82,8 @@ impl<'tcx> Error for EvalError<'tcx> {
"pointer offset outside bounds of allocation",
EvalError::ReadPointerAsBytes =>
"a raw memory access tried to access part of a pointer value as raw bytes",
EvalError::ReadBytesAsPointer =>
"a memory access tried to interpret some bytes as a pointer",
EvalError::InvalidPointerMath =>
"attempted to do math or a comparison on pointers into different allocations",
EvalError::ReadUndefBytes =>
Expand Down
99 changes: 62 additions & 37 deletions src/eval_context.rs

Large diffs are not rendered by default.

46 changes: 33 additions & 13 deletions src/lvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ use value::{PrimVal, Value};
pub enum Lvalue<'tcx> {
/// An lvalue referring to a value allocated in the `Memory` system.
Ptr {
ptr: Pointer,
/// An lvalue may have an invalid (integral or undef) pointer,
/// since it might be turned back into a reference
/// before ever being dereferenced.
ptr: PrimVal,
extra: LvalueExtra,
},

Expand Down Expand Up @@ -61,22 +64,35 @@ pub struct Global<'tcx> {
}

impl<'tcx> Lvalue<'tcx> {
pub fn from_ptr(ptr: Pointer) -> Self {
/// Produces an Lvalue that will error if attempted to be read from
pub fn undef() -> Self {
Self::from_primval_ptr(PrimVal::Undef)
}

fn from_primval_ptr(ptr: PrimVal) -> Self {
Lvalue::Ptr { ptr, extra: LvalueExtra::None }
}

pub(super) fn to_ptr_and_extra(self) -> (Pointer, LvalueExtra) {
pub fn zst() -> Self {
Self::from_ptr(Pointer::zst_ptr())
}

pub fn from_ptr(ptr: Pointer) -> Self {
Self::from_primval_ptr(PrimVal::Ptr(ptr))
}

pub(super) fn to_ptr_and_extra(self) -> (PrimVal, LvalueExtra) {
match self {
Lvalue::Ptr { ptr, extra } => (ptr, extra),
_ => bug!("to_ptr_and_extra: expected Lvalue::Ptr, got {:?}", self),

}
}

pub(super) fn to_ptr(self) -> Pointer {
pub(super) fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
let (ptr, extra) = self.to_ptr_and_extra();
assert_eq!(extra, LvalueExtra::None);
ptr
ptr.to_ptr()
}

pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) {
Expand Down Expand Up @@ -127,7 +143,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
match lvalue {
Lvalue::Ptr { ptr, extra } => {
assert_eq!(extra, LvalueExtra::None);
Ok(Value::ByRef(ptr))
Ok(Value::ByRef(ptr.to_ptr()?))
}
Lvalue::Local { frame, local, field } => {
self.stack[frame].get_local(local, field.map(|(i, _)| i))
Expand Down Expand Up @@ -167,7 +183,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
field_ty: Ty<'tcx>,
) -> EvalResult<'tcx, Lvalue<'tcx>> {
let base_layout = self.type_layout(base_ty)?;

use rustc::ty::layout::Layout::*;
let (offset, packed) = match *base_layout {
Univariant { ref variant, .. } => {
Expand Down Expand Up @@ -229,19 +244,24 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Lvalue::Local { frame, local, field } => match self.stack[frame].get_local(local, field.map(|(i, _)| i))? {
Value::ByRef(ptr) => {
assert!(field.is_none(), "local can't be ByRef and have a field offset");
(ptr, LvalueExtra::None)
(PrimVal::Ptr(ptr), LvalueExtra::None)
},
Value::ByVal(PrimVal::Undef) => {
// FIXME: allocate in fewer cases
if self.ty_to_primval_kind(base_ty).is_ok() {
return Ok(base);
} else {
(self.force_allocation(base)?.to_ptr(), LvalueExtra::None)
(PrimVal::Ptr(self.force_allocation(base)?.to_ptr()?), LvalueExtra::None)
}
},
Value::ByVal(_) => {
assert_eq!(field_index, 0, "ByVal can only have 1 non zst field with offset 0");
return Ok(base);
if self.get_field_count(base_ty)? == 1 {
assert_eq!(field_index, 0, "ByVal can only have 1 non zst field with offset 0");
return Ok(base);
}
// this branch is taken when a union creates a large ByVal which is then
// accessed as a struct with multiple small fields
(PrimVal::Ptr(self.force_allocation(base)?.to_ptr()?), LvalueExtra::None)
},
Value::ByValPair(_, _) => {
let field_count = self.get_field_count(base_ty)?;
Expand All @@ -264,7 +284,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {

let offset = match base_extra {
LvalueExtra::Vtable(tab) => {
let (_, align) = self.size_and_align_of_dst(base_ty, Value::ByValPair(PrimVal::Ptr(base_ptr), PrimVal::Ptr(tab)))?;
let (_, align) = self.size_and_align_of_dst(base_ty, Value::ByValPair(base_ptr, PrimVal::Ptr(tab)))?;
offset.abi_align(Align::from_bytes(align, align).unwrap()).bytes()
}
_ => offset.bytes(),
Expand All @@ -276,7 +296,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {

if packed {
let size = self.type_size(field_ty)?.expect("packed struct must be sized");
self.memory.mark_packed(ptr, size);
self.memory.mark_packed(ptr.to_ptr()?, size);
}

let extra = if self.type_is_sized(field_ty) {
Expand Down
Loading