commit
90c2470e22
6 changed files with 143 additions and 57 deletions
|
@ -36,6 +36,10 @@ pub enum EvalError<'tcx> {
|
|||
},
|
||||
ExecutionTimeLimitReached,
|
||||
StackFrameLimitReached,
|
||||
AlignmentCheckFailed {
|
||||
required: usize,
|
||||
has: usize,
|
||||
},
|
||||
}
|
||||
|
||||
pub type EvalResult<'tcx, T> = Result<T, EvalError<'tcx>>;
|
||||
|
@ -82,6 +86,8 @@ impl<'tcx> Error for EvalError<'tcx> {
|
|||
"reached the configured maximum execution time",
|
||||
EvalError::StackFrameLimitReached =>
|
||||
"reached the configured maximum number of stack frames",
|
||||
EvalError::AlignmentCheckFailed{..} =>
|
||||
"tried to execute a misaligned read or write",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,6 +112,9 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
|
|||
EvalError::OutOfMemory { allocation_size, memory_size, memory_usage } =>
|
||||
write!(f, "tried to allocate {} more bytes, but only {} bytes are free of the {} byte memory",
|
||||
allocation_size, memory_size - memory_usage, memory_size),
|
||||
EvalError::AlignmentCheckFailed { required, has } =>
|
||||
write!(f, "tried to access memory with alignment {}, but alignment {} is required",
|
||||
has, required),
|
||||
_ => write!(f, "{}", self.description()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,7 +152,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
match output_ty {
|
||||
ty::FnConverging(ty) => {
|
||||
let size = self.type_size_with_substs(ty, substs);
|
||||
self.memory.allocate(size).map(Some)
|
||||
let align = self.type_align_with_substs(ty, substs);
|
||||
self.memory.allocate(size, align).map(Some)
|
||||
}
|
||||
ty::FnDiverging => Ok(None),
|
||||
}
|
||||
|
@ -176,19 +177,19 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize, ConstFloat};
|
||||
macro_rules! i2p {
|
||||
($i:ident, $n:expr) => {{
|
||||
let ptr = self.memory.allocate($n)?;
|
||||
let ptr = self.memory.allocate($n, $n)?;
|
||||
self.memory.write_int(ptr, $i as i64, $n)?;
|
||||
Ok(ptr)
|
||||
}}
|
||||
}
|
||||
match *const_val {
|
||||
Float(ConstFloat::F32(f)) => {
|
||||
let ptr = self.memory.allocate(4)?;
|
||||
let ptr = self.memory.allocate(4, 4)?;
|
||||
self.memory.write_f32(ptr, f)?;
|
||||
Ok(ptr)
|
||||
},
|
||||
Float(ConstFloat::F64(f)) => {
|
||||
let ptr = self.memory.allocate(8)?;
|
||||
let ptr = self.memory.allocate(8, 8)?;
|
||||
self.memory.write_f64(ptr, f)?;
|
||||
Ok(ptr)
|
||||
},
|
||||
|
@ -197,22 +198,22 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
Integral(ConstInt::InferSigned(_)) => unreachable!(),
|
||||
Integral(ConstInt::I8(i)) => i2p!(i, 1),
|
||||
Integral(ConstInt::U8(i)) => i2p!(i, 1),
|
||||
Integral(ConstInt::Isize(ConstIsize::Is16(i))) |
|
||||
Integral(ConstInt::I16(i)) => i2p!(i, 2),
|
||||
Integral(ConstInt::Usize(ConstUsize::Us16(i))) |
|
||||
Integral(ConstInt::U16(i)) => i2p!(i, 2),
|
||||
Integral(ConstInt::Isize(ConstIsize::Is32(i))) |
|
||||
Integral(ConstInt::I32(i)) => i2p!(i, 4),
|
||||
Integral(ConstInt::Usize(ConstUsize::Us32(i))) |
|
||||
Integral(ConstInt::U32(i)) => i2p!(i, 4),
|
||||
Integral(ConstInt::Isize(ConstIsize::Is64(i))) |
|
||||
Integral(ConstInt::I64(i)) => i2p!(i, 8),
|
||||
Integral(ConstInt::Usize(ConstUsize::Us64(i))) |
|
||||
Integral(ConstInt::U64(i)) => i2p!(i, 8),
|
||||
Integral(ConstInt::Isize(ConstIsize::Is16(i))) => i2p!(i, 2),
|
||||
Integral(ConstInt::Isize(ConstIsize::Is32(i))) => i2p!(i, 4),
|
||||
Integral(ConstInt::Isize(ConstIsize::Is64(i))) => i2p!(i, 8),
|
||||
Integral(ConstInt::Usize(ConstUsize::Us16(i))) => i2p!(i, 2),
|
||||
Integral(ConstInt::Usize(ConstUsize::Us32(i))) => i2p!(i, 4),
|
||||
Integral(ConstInt::Usize(ConstUsize::Us64(i))) => i2p!(i, 8),
|
||||
Str(ref s) => {
|
||||
let psize = self.memory.pointer_size();
|
||||
let static_ptr = self.memory.allocate(s.len())?;
|
||||
let ptr = self.memory.allocate(psize * 2)?;
|
||||
let static_ptr = self.memory.allocate(s.len(), 1)?;
|
||||
let ptr = self.memory.allocate(psize * 2, psize)?;
|
||||
self.memory.write_bytes(static_ptr, s.as_bytes())?;
|
||||
self.memory.write_ptr(ptr, static_ptr)?;
|
||||
self.memory.write_usize(ptr.offset(psize as isize), s.len() as u64)?;
|
||||
|
@ -220,19 +221,19 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
}
|
||||
ByteStr(ref bs) => {
|
||||
let psize = self.memory.pointer_size();
|
||||
let static_ptr = self.memory.allocate(bs.len())?;
|
||||
let ptr = self.memory.allocate(psize)?;
|
||||
let static_ptr = self.memory.allocate(bs.len(), 1)?;
|
||||
let ptr = self.memory.allocate(psize, psize)?;
|
||||
self.memory.write_bytes(static_ptr, bs)?;
|
||||
self.memory.write_ptr(ptr, static_ptr)?;
|
||||
Ok(ptr)
|
||||
}
|
||||
Bool(b) => {
|
||||
let ptr = self.memory.allocate(1)?;
|
||||
let ptr = self.memory.allocate(1, 1)?;
|
||||
self.memory.write_bool(ptr, b)?;
|
||||
Ok(ptr)
|
||||
}
|
||||
Char(c) => {
|
||||
let ptr = self.memory.allocate(4)?;
|
||||
let ptr = self.memory.allocate(4, 4)?;
|
||||
self.memory.write_uint(ptr, c as u64, 4)?;
|
||||
Ok(ptr)
|
||||
},
|
||||
|
@ -278,10 +279,18 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
self.type_size_with_substs(ty, self.substs())
|
||||
}
|
||||
|
||||
fn type_align(&self, ty: Ty<'tcx>) -> usize {
|
||||
self.type_align_with_substs(ty, self.substs())
|
||||
}
|
||||
|
||||
fn type_size_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> usize {
|
||||
self.type_layout_with_substs(ty, substs).size(&self.tcx.data_layout).bytes() as usize
|
||||
}
|
||||
|
||||
fn type_align_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> usize {
|
||||
self.type_layout_with_substs(ty, substs).align(&self.tcx.data_layout).abi() as usize
|
||||
}
|
||||
|
||||
fn type_layout(&self, ty: Ty<'tcx>) -> &'tcx Layout {
|
||||
self.type_layout_with_substs(ty, self.substs())
|
||||
}
|
||||
|
@ -315,7 +324,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
|
||||
let locals: EvalResult<'tcx, Vec<Pointer>> = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| {
|
||||
let size = self.type_size_with_substs(ty, substs);
|
||||
self.memory.allocate(size)
|
||||
let align = self.type_align_with_substs(ty, substs);
|
||||
self.memory.allocate(size, align)
|
||||
}).collect();
|
||||
|
||||
self.stack.push(Frame {
|
||||
|
@ -519,15 +529,15 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
Repeat(ref operand, _) => {
|
||||
let (elem_size, length) = match dest_ty.sty {
|
||||
ty::TyArray(elem_ty, n) => (self.type_size(elem_ty), n),
|
||||
let (elem_size, elem_align, length) = match dest_ty.sty {
|
||||
ty::TyArray(elem_ty, n) => (self.type_size(elem_ty), self.type_align(elem_ty), n),
|
||||
_ => panic!("tried to assign array-repeat to non-array type {:?}", dest_ty),
|
||||
};
|
||||
|
||||
let src = self.eval_operand(operand)?;
|
||||
for i in 0..length {
|
||||
let elem_dest = dest.offset((i * elem_size) as isize);
|
||||
self.memory.copy(src, elem_dest, elem_size)?;
|
||||
self.memory.copy(src, elem_dest, elem_size, elem_align)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -562,7 +572,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
|
||||
Box(ty) => {
|
||||
let size = self.type_size(ty);
|
||||
let ptr = self.memory.allocate(size)?;
|
||||
let align = self.type_align(ty);
|
||||
let ptr = self.memory.allocate(size, align)?;
|
||||
self.memory.write_ptr(dest, ptr)?;
|
||||
}
|
||||
|
||||
|
@ -593,13 +604,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
warn!("misc cast from {:?} to {:?}", src_ty, dest_ty);
|
||||
let dest_size = self.type_size(dest_ty);
|
||||
let src_size = self.type_size(src_ty);
|
||||
let dest_align = self.type_align(dest_ty);
|
||||
|
||||
// Hack to support fat pointer -> thin pointer casts to keep tests for
|
||||
// other things passing for now.
|
||||
let is_fat_ptr_cast = pointee_type(src_ty).map_or(false, |ty| !self.type_is_sized(ty));
|
||||
|
||||
if dest_size == src_size || is_fat_ptr_cast {
|
||||
self.memory.copy(src, dest, dest_size)?;
|
||||
self.memory.copy(src, dest, dest_size, dest_align)?;
|
||||
} else {
|
||||
return Err(EvalError::Unimplemented(format!("can't handle cast: {:?}", rvalue)));
|
||||
}
|
||||
|
@ -710,7 +722,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
Item { def_id, substs } => {
|
||||
if let ty::TyFnDef(..) = ty.sty {
|
||||
// function items are zero sized
|
||||
Ok(self.memory.allocate(0)?)
|
||||
Ok(self.memory.allocate(0, 0)?)
|
||||
} else {
|
||||
let cid = ConstantId {
|
||||
def_id: def_id,
|
||||
|
@ -843,7 +855,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
|
||||
fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, ()> {
|
||||
let size = self.type_size(ty);
|
||||
self.memory.copy(src, dest, size)?;
|
||||
let align = self.type_align(ty);
|
||||
self.memory.copy(src, dest, size, align)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -967,9 +980,9 @@ pub fn eval_main<'a, 'tcx: 'a>(
|
|||
if mir.arg_decls.len() == 2 {
|
||||
// start function
|
||||
let ptr_size = ecx.memory().pointer_size();
|
||||
let nargs = ecx.memory_mut().allocate(ptr_size).expect("can't allocate memory for nargs");
|
||||
let nargs = ecx.memory_mut().allocate(ptr_size, ptr_size).expect("can't allocate memory for nargs");
|
||||
ecx.memory_mut().write_usize(nargs, 0).unwrap();
|
||||
let args = ecx.memory_mut().allocate(ptr_size).expect("can't allocate memory for arg pointer");
|
||||
let args = ecx.memory_mut().allocate(ptr_size, ptr_size).expect("can't allocate memory for arg pointer");
|
||||
ecx.memory_mut().write_usize(args, 0).unwrap();
|
||||
ecx.frame_mut().locals[0] = nargs;
|
||||
ecx.frame_mut().locals[1] = args;
|
||||
|
|
|
@ -88,7 +88,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
match func_ty.sty {
|
||||
ty::TyFnPtr(bare_fn_ty) => {
|
||||
let ptr = self.eval_operand(func)?;
|
||||
assert_eq!(ptr.offset, 0);
|
||||
let fn_ptr = self.memory.read_ptr(ptr)?;
|
||||
let FunctionDefinition { def_id, substs, fn_ty } = self.memory.get_fn(fn_ptr.alloc_id)?;
|
||||
if fn_ty != bare_fn_ty {
|
||||
|
@ -290,10 +289,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
"copy_nonoverlapping" => {
|
||||
let elem_ty = *substs.types.get(subst::FnSpace, 0);
|
||||
let elem_size = self.type_size(elem_ty);
|
||||
let elem_align = self.type_align(elem_ty);
|
||||
let src = self.memory.read_ptr(args_ptrs[0])?;
|
||||
let dest = self.memory.read_ptr(args_ptrs[1])?;
|
||||
let count = self.memory.read_isize(args_ptrs[2])?;
|
||||
self.memory.copy(src, dest, count as usize * elem_size)?;
|
||||
self.memory.copy(src, dest, count as usize * elem_size, elem_align)?;
|
||||
}
|
||||
|
||||
"discriminant_value" => {
|
||||
|
@ -308,8 +308,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
"init" => self.memory.write_repeat(dest, 0, dest_layout.size(&self.tcx.data_layout).bytes() as usize)?,
|
||||
|
||||
"min_align_of" => {
|
||||
// FIXME: use correct value
|
||||
self.memory.write_int(dest, 1, pointer_size)?;
|
||||
let elem_ty = *substs.types.get(subst::FnSpace, 0);
|
||||
let elem_align = self.type_align(elem_ty);
|
||||
self.memory.write_uint(dest, elem_align as u64, pointer_size)?;
|
||||
}
|
||||
|
||||
"move_val_init" => {
|
||||
|
@ -416,14 +417,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
match &link_name[..] {
|
||||
"__rust_allocate" => {
|
||||
let size = self.memory.read_usize(args[0])?;
|
||||
let ptr = self.memory.allocate(size as usize)?;
|
||||
let align = self.memory.read_usize(args[1])?;
|
||||
let ptr = self.memory.allocate(size as usize, align as usize)?;
|
||||
self.memory.write_ptr(dest, ptr)?;
|
||||
}
|
||||
|
||||
"__rust_reallocate" => {
|
||||
let ptr = self.memory.read_ptr(args[0])?;
|
||||
let size = self.memory.read_usize(args[2])?;
|
||||
let new_ptr = self.memory.reallocate(ptr, size as usize)?;
|
||||
let align = self.memory.read_usize(args[3])?;
|
||||
let new_ptr = self.memory.reallocate(ptr, size as usize, align as usize)?;
|
||||
self.memory.write_ptr(dest, new_ptr)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ pub struct Allocation {
|
|||
pub bytes: Vec<u8>,
|
||||
pub relocations: BTreeMap<usize, AllocId>,
|
||||
pub undef_mask: UndefMask,
|
||||
pub align: usize,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
|
@ -98,15 +99,16 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
bytes: Vec::new(),
|
||||
relocations: BTreeMap::new(),
|
||||
undef_mask: UndefMask::new(0),
|
||||
align: 1,
|
||||
};
|
||||
mem.alloc_map.insert(ZST_ALLOC_ID, alloc);
|
||||
// check that additional zst allocs work
|
||||
debug_assert!(mem.allocate(0).unwrap().points_to_zst());
|
||||
debug_assert!(mem.allocate(0, 1).unwrap().points_to_zst());
|
||||
debug_assert!(mem.get(ZST_ALLOC_ID).is_ok());
|
||||
mem
|
||||
}
|
||||
|
||||
pub fn allocations<'b>(&'b self) -> ::std::collections::hash_map::Iter<'b, AllocId, Allocation> {
|
||||
pub fn allocations(&self) -> ::std::collections::hash_map::Iter<AllocId, Allocation> {
|
||||
self.alloc_map.iter()
|
||||
}
|
||||
|
||||
|
@ -133,7 +135,8 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn allocate(&mut self, size: usize) -> EvalResult<'tcx, Pointer> {
|
||||
pub fn allocate(&mut self, size: usize, align: usize) -> EvalResult<'tcx, Pointer> {
|
||||
assert!(align != 0);
|
||||
if size == 0 {
|
||||
return Ok(Pointer::zst_ptr());
|
||||
}
|
||||
|
@ -149,6 +152,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
bytes: vec![0; size],
|
||||
relocations: BTreeMap::new(),
|
||||
undef_mask: UndefMask::new(size),
|
||||
align: align,
|
||||
};
|
||||
let id = self.next_id;
|
||||
self.next_id.0 += 1;
|
||||
|
@ -161,16 +165,16 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
|
||||
// TODO(solson): Track which allocations were returned from __rust_allocate and report an error
|
||||
// when reallocating/deallocating any others.
|
||||
pub fn reallocate(&mut self, ptr: Pointer, new_size: usize) -> EvalResult<'tcx, Pointer> {
|
||||
pub fn reallocate(&mut self, ptr: Pointer, new_size: usize, align: usize) -> EvalResult<'tcx, Pointer> {
|
||||
// TODO(solson): Report error about non-__rust_allocate'd pointer.
|
||||
if ptr.offset != 0 {
|
||||
// TODO(solson): Report error about non-__rust_allocate'd pointer.
|
||||
return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset)));
|
||||
}
|
||||
if ptr.points_to_zst() {
|
||||
return self.allocate(new_size);
|
||||
return self.allocate(new_size, align);
|
||||
}
|
||||
|
||||
let size = self.get_mut(ptr.alloc_id)?.bytes.len();
|
||||
let size = self.get(ptr.alloc_id)?.bytes.len();
|
||||
|
||||
if new_size > size {
|
||||
let amount = new_size - size;
|
||||
|
@ -187,7 +191,10 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
alloc.undef_mask.truncate(new_size);
|
||||
}
|
||||
|
||||
Ok(ptr)
|
||||
Ok(Pointer {
|
||||
alloc_id: ptr.alloc_id,
|
||||
offset: 0,
|
||||
})
|
||||
}
|
||||
|
||||
// TODO(solson): See comment on `reallocate`.
|
||||
|
@ -220,6 +227,24 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
pub fn endianess(&self) -> layout::Endian {
|
||||
self.layout.endian
|
||||
}
|
||||
|
||||
pub fn check_align(&self, ptr: Pointer, align: usize) -> EvalResult<'tcx, ()> {
|
||||
let alloc = self.get(ptr.alloc_id)?;
|
||||
if alloc.align < align {
|
||||
return Err(EvalError::AlignmentCheckFailed {
|
||||
has: alloc.align,
|
||||
required: align,
|
||||
});
|
||||
}
|
||||
if ptr.offset % align == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(EvalError::AlignmentCheckFailed {
|
||||
has: ptr.offset % align,
|
||||
required: align,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocation accessors
|
||||
|
@ -337,7 +362,8 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
Ok(&mut alloc.bytes[ptr.offset..ptr.offset + size])
|
||||
}
|
||||
|
||||
fn get_bytes(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &[u8]> {
|
||||
fn get_bytes(&self, ptr: Pointer, size: usize, align: usize) -> EvalResult<'tcx, &[u8]> {
|
||||
self.check_align(ptr, align)?;
|
||||
if self.relocations(ptr, size)?.count() != 0 {
|
||||
return Err(EvalError::ReadPointerAsBytes);
|
||||
}
|
||||
|
@ -345,7 +371,8 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
self.get_bytes_unchecked(ptr, size)
|
||||
}
|
||||
|
||||
fn get_bytes_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &mut [u8]> {
|
||||
fn get_bytes_mut(&mut self, ptr: Pointer, size: usize, align: usize) -> EvalResult<'tcx, &mut [u8]> {
|
||||
self.check_align(ptr, align)?;
|
||||
self.clear_relocations(ptr, size)?;
|
||||
self.mark_definedness(ptr, size, true)?;
|
||||
self.get_bytes_unchecked_mut(ptr, size)
|
||||
|
@ -354,11 +381,11 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
|
||||
/// Reading and writing
|
||||
impl<'a, 'tcx> Memory<'a, 'tcx> {
|
||||
pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<'tcx, ()> {
|
||||
pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize, align: usize) -> EvalResult<'tcx, ()> {
|
||||
self.check_relocation_edges(src, size)?;
|
||||
|
||||
let src_bytes = self.get_bytes_unchecked_mut(src, size)?.as_mut_ptr();
|
||||
let dest_bytes = self.get_bytes_mut(dest, size)?.as_mut_ptr();
|
||||
let dest_bytes = self.get_bytes_mut(dest, size, align)?.as_mut_ptr();
|
||||
|
||||
// SAFE: The above indexing would have panicked if there weren't at least `size` bytes
|
||||
// behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and
|
||||
|
@ -378,17 +405,17 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn read_bytes(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &[u8]> {
|
||||
self.get_bytes(ptr, size)
|
||||
self.get_bytes(ptr, size, 1)
|
||||
}
|
||||
|
||||
pub fn write_bytes(&mut self, ptr: Pointer, src: &[u8]) -> EvalResult<'tcx, ()> {
|
||||
let bytes = self.get_bytes_mut(ptr, src.len())?;
|
||||
let bytes = self.get_bytes_mut(ptr, src.len(), 1)?;
|
||||
bytes.clone_from_slice(src);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_repeat(&mut self, ptr: Pointer, val: u8, count: usize) -> EvalResult<'tcx, ()> {
|
||||
let bytes = self.get_bytes_mut(ptr, count)?;
|
||||
let bytes = self.get_bytes_mut(ptr, count, 1)?;
|
||||
for b in bytes { *b = val; }
|
||||
Ok(())
|
||||
}
|
||||
|
@ -434,7 +461,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn read_bool(&self, ptr: Pointer) -> EvalResult<'tcx, bool> {
|
||||
let bytes = self.get_bytes(ptr, 1)?;
|
||||
let bytes = self.get_bytes(ptr, 1, self.layout.i1_align.abi() as usize)?;
|
||||
match bytes[0] {
|
||||
0 => Ok(false),
|
||||
1 => Ok(true),
|
||||
|
@ -443,27 +470,43 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn write_bool(&mut self, ptr: Pointer, b: bool) -> EvalResult<'tcx, ()> {
|
||||
self.get_bytes_mut(ptr, 1).map(|bytes| bytes[0] = b as u8)
|
||||
let align = self.layout.i1_align.abi() as usize;
|
||||
self.get_bytes_mut(ptr, 1, align)
|
||||
.map(|bytes| bytes[0] = b as u8)
|
||||
}
|
||||
|
||||
fn int_align(&self, size: usize) -> EvalResult<'tcx, usize> {
|
||||
match size {
|
||||
1 => Ok(self.layout.i8_align.abi() as usize),
|
||||
2 => Ok(self.layout.i16_align.abi() as usize),
|
||||
4 => Ok(self.layout.i32_align.abi() as usize),
|
||||
8 => Ok(self.layout.i64_align.abi() as usize),
|
||||
_ => panic!("bad integer size"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_int(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, i64> {
|
||||
self.get_bytes(ptr, size).map(|b| read_target_int(self.endianess(), b).unwrap())
|
||||
let align = self.int_align(size)?;
|
||||
self.get_bytes(ptr, size, align).map(|b| read_target_int(self.endianess(), b).unwrap())
|
||||
}
|
||||
|
||||
pub fn write_int(&mut self, ptr: Pointer, n: i64, size: usize) -> EvalResult<'tcx, ()> {
|
||||
let align = self.int_align(size)?;
|
||||
let endianess = self.endianess();
|
||||
let b = self.get_bytes_mut(ptr, size)?;
|
||||
let b = self.get_bytes_mut(ptr, size, align)?;
|
||||
write_target_int(endianess, b, n).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_uint(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, u64> {
|
||||
self.get_bytes(ptr, size).map(|b| read_target_uint(self.endianess(), b).unwrap())
|
||||
let align = self.int_align(size)?;
|
||||
self.get_bytes(ptr, size, align).map(|b| read_target_uint(self.endianess(), b).unwrap())
|
||||
}
|
||||
|
||||
pub fn write_uint(&mut self, ptr: Pointer, n: u64, size: usize) -> EvalResult<'tcx, ()> {
|
||||
let align = self.int_align(size)?;
|
||||
let endianess = self.endianess();
|
||||
let b = self.get_bytes_mut(ptr, size)?;
|
||||
let b = self.get_bytes_mut(ptr, size, align)?;
|
||||
write_target_uint(endianess, b, n).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
@ -488,24 +531,28 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
|
||||
pub fn write_f32(&mut self, ptr: Pointer, f: f32) -> EvalResult<'tcx, ()> {
|
||||
let endianess = self.endianess();
|
||||
let b = self.get_bytes_mut(ptr, 4)?;
|
||||
let align = self.layout.f32_align.abi() as usize;
|
||||
let b = self.get_bytes_mut(ptr, 4, align)?;
|
||||
write_target_f32(endianess, b, f).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_f64(&mut self, ptr: Pointer, f: f64) -> EvalResult<'tcx, ()> {
|
||||
let endianess = self.endianess();
|
||||
let b = self.get_bytes_mut(ptr, 8)?;
|
||||
let align = self.layout.f64_align.abi() as usize;
|
||||
let b = self.get_bytes_mut(ptr, 8, align)?;
|
||||
write_target_f64(endianess, b, f).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_f32(&self, ptr: Pointer) -> EvalResult<'tcx, f32> {
|
||||
self.get_bytes(ptr, 4).map(|b| read_target_f32(self.endianess(), b).unwrap())
|
||||
self.get_bytes(ptr, 4, self.layout.f32_align.abi() as usize)
|
||||
.map(|b| read_target_f32(self.endianess(), b).unwrap())
|
||||
}
|
||||
|
||||
pub fn read_f64(&self, ptr: Pointer) -> EvalResult<'tcx, f64> {
|
||||
self.get_bytes(ptr, 8).map(|b| read_target_f64(self.endianess(), b).unwrap())
|
||||
self.get_bytes(ptr, 8, self.layout.f64_align.abi() as usize)
|
||||
.map(|b| read_target_f64(self.endianess(), b).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#![allow(unknown_lints)]
|
||||
#![allow(float_cmp)]
|
||||
|
||||
use rustc::mir::repr as mir;
|
||||
|
||||
use error::{EvalError, EvalResult};
|
||||
|
|
11
tests/compile-fail/alignment.rs
Normal file
11
tests/compile-fail/alignment.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
fn main() {
|
||||
// miri always gives allocations the worst possible alignment, so a `u8` array is guaranteed
|
||||
// to be at the virtual location 1 (so one byte offset from the ultimate alignemnt location 0)
|
||||
let mut x = [0u8; 20];
|
||||
let x_ptr: *mut u8 = &mut x[0];
|
||||
let y_ptr = x_ptr as *mut u64;
|
||||
unsafe {
|
||||
*y_ptr = 42; //~ ERROR tried to access memory with alignment 1, but alignment
|
||||
}
|
||||
panic!("unreachable in miri");
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue