Skip to content

Commit

Permalink
Merge pull request #34 from oli-obk/alignment
Browse files Browse the repository at this point in the history
use ty::layout::Size and ty::layout::TargetDataLayout
  • Loading branch information
solson authored Jun 23, 2016
2 parents 0c720f6 + 4c7aae7 commit ba23b87
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 55 deletions.
26 changes: 11 additions & 15 deletions src/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub struct EvalContext<'a, 'tcx: 'a> {
mir_cache: RefCell<DefIdMap<Rc<mir::Mir<'tcx>>>>,

/// The virtual memory system.
memory: Memory<'tcx>,
memory: Memory<'a, 'tcx>,

/// Precomputed statics, constants and promoteds.
statics: HashMap<ConstantId<'tcx>, Pointer>,
Expand Down Expand Up @@ -138,11 +138,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
tcx: tcx,
mir_map: mir_map,
mir_cache: RefCell::new(DefIdMap()),
memory: Memory::new(tcx.sess
.target
.uint_type
.bit_width()
.expect("Session::target::uint_type was usize")/8),
memory: Memory::new(&tcx.data_layout),
statics: HashMap::new(),
stack: Vec::new(),
}
Expand All @@ -162,7 +158,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
&self.memory
}

pub fn memory_mut(&mut self) -> &mut Memory<'tcx> {
pub fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx> {
&mut self.memory
}

Expand All @@ -182,7 +178,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Ok(ptr)
}
Str(ref s) => {
let psize = self.memory.pointer_size;
let psize = self.memory.pointer_size();
let static_ptr = self.memory.allocate(s.len());
let ptr = self.memory.allocate(psize * 2);
self.memory.write_bytes(static_ptr, s.as_bytes())?;
Expand All @@ -191,7 +187,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Ok(ptr)
}
ByteStr(ref bs) => {
let psize = self.memory.pointer_size;
let psize = self.memory.pointer_size();
let static_ptr = self.memory.allocate(bs.len());
let ptr = self.memory.allocate(psize);
self.memory.write_bytes(static_ptr, bs)?;
Expand Down Expand Up @@ -515,7 +511,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
match lv.extra {
LvalueExtra::None => {},
LvalueExtra::Length(len) => {
let len_ptr = dest.offset(self.memory.pointer_size as isize);
let len_ptr = dest.offset(self.memory.pointer_size() as isize);
self.memory.write_usize(len_ptr, len)?;
}
LvalueExtra::DowncastVariant(..) =>
Expand All @@ -541,7 +537,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {

match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
(&ty::TyArray(_, length), &ty::TySlice(_)) => {
let len_ptr = dest.offset(self.memory.pointer_size as isize);
let len_ptr = dest.offset(self.memory.pointer_size() as isize);
self.memory.write_usize(len_ptr, length as u64)?;
}

Expand Down Expand Up @@ -655,7 +651,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Ok(Size::from_bytes(0))
}
FatPointer { .. } => {
let bytes = layout::FAT_PTR_ADDR * self.memory.pointer_size;
let bytes = layout::FAT_PTR_ADDR * self.memory.pointer_size();
Ok(Size::from_bytes(bytes as u64))
}
_ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}, with layout: {:?}", ty, layout))),
Expand Down Expand Up @@ -766,7 +762,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let ptr = self.memory.read_ptr(base.ptr)?;
let extra = match pointee_ty.sty {
ty::TySlice(_) | ty::TyStr => {
let len_ptr = base.ptr.offset(self.memory.pointer_size as isize);
let len_ptr = base.ptr.offset(self.memory.pointer_size() as isize);
let len = self.memory.read_usize(len_ptr)?;
LvalueExtra::Length(len)
}
Expand Down Expand Up @@ -815,7 +811,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {

pub fn read_primval(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
use syntax::ast::{IntTy, UintTy};
let val = match (self.memory.pointer_size, &ty.sty) {
let val = match (self.memory.pointer_size(), &ty.sty) {
(_, &ty::TyBool) => PrimVal::Bool(self.memory.read_bool(ptr)?),
(_, &ty::TyChar) => {
let c = self.memory.read_uint(ptr, 4)? as u32;
Expand Down Expand Up @@ -923,7 +919,7 @@ pub fn eval_main<'a, 'tcx: 'a>(

if mir.arg_decls.len() == 2 {
// start function
let ptr_size = ecx.memory().pointer_size;
let ptr_size = ecx.memory().pointer_size();
let nargs = ecx.memory_mut().allocate(ptr_size);
ecx.memory_mut().write_usize(nargs, 0).unwrap();
let args = ecx.memory_mut().allocate(ptr_size);
Expand Down
6 changes: 3 additions & 3 deletions src/interpreter/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
.collect();
let args_ptrs = args_res?;

let pointer_size = self.memory.pointer_size;
let pointer_size = self.memory.pointer_size();

match name {
"add_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Add, &args[0], &args[1], dest, dest_layout)?,
Expand Down Expand Up @@ -368,7 +368,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
ty::TySlice(_) | ty::TyStr => {
let elem_ty = ty.sequence_element_type(self.tcx);
let elem_size = self.type_size(elem_ty) as u64;
let ptr_size = self.memory.pointer_size as isize;
let ptr_size = self.memory.pointer_size() as isize;
let n = self.memory.read_usize(args_ptrs[0].offset(ptr_size))?;
self.memory.write_uint(dest, n * elem_size, pointer_size)?;
}
Expand Down Expand Up @@ -557,7 +557,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
self.memory.deallocate(contents_ptr)?;
}
Err(EvalError::ReadBytesAsPointer) => {
let size = self.memory.pointer_size;
let size = self.memory.pointer_size();
let possible_drop_fill = self.memory.read_bytes(ptr, size)?;
if possible_drop_fill.iter().all(|&b| b == mem::POST_DROP_U8) {
return Ok(());
Expand Down
71 changes: 35 additions & 36 deletions src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::{fmt, iter, mem, ptr};
use rustc::hir::def_id::DefId;
use rustc::ty::BareFnTy;
use rustc::ty::subst::Substs;
use rustc::ty::layout::TargetDataLayout;

use error::{EvalError, EvalResult};
use primval::PrimVal;
Expand Down Expand Up @@ -53,7 +54,7 @@ pub struct FunctionDefinition<'tcx> {
// Top-level interpreter memory
////////////////////////////////////////////////////////////////////////////////

pub struct Memory<'tcx> {
pub struct Memory<'a, 'tcx> {
/// Actual memory allocations (arbitrary bytes, may contain pointers into other allocations)
alloc_map: HashMap<AllocId, Allocation>,
/// Function "allocations". They exist solely so pointers have something to point to, and
Expand All @@ -62,18 +63,17 @@ pub struct Memory<'tcx> {
/// Inverse map of `functions` so we don't allocate a new pointer every time we need one
function_alloc_cache: HashMap<FunctionDefinition<'tcx>, AllocId>,
next_id: AllocId,
pub pointer_size: usize,
pub layout: &'a TargetDataLayout,
}

impl<'tcx> Memory<'tcx> {
// 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 {
impl<'a, 'tcx> Memory<'a, 'tcx> {
pub fn new(layout: &'a TargetDataLayout) -> Self {
Memory {
alloc_map: HashMap::new(),
functions: HashMap::new(),
function_alloc_cache: HashMap::new(),
next_id: AllocId(0),
pointer_size: pointer_size,
layout: layout,
}
}

Expand Down Expand Up @@ -156,10 +156,13 @@ impl<'tcx> Memory<'tcx> {
Ok(())
}

////////////////////////////////////////////////////////////////////////////////
// Allocation accessors
////////////////////////////////////////////////////////////////////////////////
pub fn pointer_size(&self) -> usize {
self.layout.pointer_size.bytes() as usize
}
}

/// Allocation accessors
impl<'a, 'tcx> Memory<'a, 'tcx> {
pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
match self.alloc_map.get(&id) {
Some(alloc) => Ok(alloc),
Expand Down Expand Up @@ -235,21 +238,20 @@ impl<'tcx> Memory<'tcx> {
if !relocations.is_empty() {
print!("{:1$}", "", prefix.len()); // Print spaces.
let mut pos = 0;
let relocation_width = (self.pointer_size - 1) * 3;
let relocation_width = (self.pointer_size() - 1) * 3;
for (i, target_id) in relocations {
print!("{:1$}", "", (i - pos) * 3);
print!("└{0:─^1$}┘ ", format!("({})", target_id), relocation_width);
pos = i + self.pointer_size;
pos = i + self.pointer_size();
}
println!("");
}
}
}
}

////////////////////////////////////////////////////////////////////////////////
// Byte accessors
////////////////////////////////////////////////////////////////////////////////

/// Byte accessors
impl<'a, 'tcx> Memory<'a, 'tcx> {
fn get_bytes_unchecked(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &[u8]> {
let alloc = self.get(ptr.alloc_id)?;
if ptr.offset + size > alloc.bytes.len() {
Expand Down Expand Up @@ -287,11 +289,10 @@ impl<'tcx> Memory<'tcx> {
self.mark_definedness(ptr, size, true)?;
self.get_bytes_unchecked_mut(ptr, size)
}
}

////////////////////////////////////////////////////////////////////////////////
// Reading and writing
////////////////////////////////////////////////////////////////////////////////

/// Reading and writing
impl<'a, 'tcx> Memory<'a, 'tcx> {
pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<'tcx, ()> {
self.check_relocation_edges(src, size)?;

Expand Down Expand Up @@ -336,7 +337,7 @@ impl<'tcx> Memory<'tcx> {
}

pub fn read_ptr(&self, ptr: Pointer) -> EvalResult<'tcx, Pointer> {
let size = self.pointer_size;
let size = self.pointer_size();
self.check_defined(ptr, size)?;
let offset = self.get_bytes_unchecked(ptr, size)?
.read_uint::<NativeEndian>(size).unwrap() as usize;
Expand All @@ -349,7 +350,7 @@ impl<'tcx> Memory<'tcx> {

pub fn write_ptr(&mut self, dest: Pointer, ptr: Pointer) -> EvalResult<'tcx, ()> {
{
let size = self.pointer_size;
let size = self.pointer_size();
let mut bytes = self.get_bytes_mut(dest, size)?;
bytes.write_uint::<NativeEndian>(ptr.offset as u64, size).unwrap();
}
Expand All @@ -358,7 +359,7 @@ impl<'tcx> Memory<'tcx> {
}

pub fn write_primval(&mut self, ptr: Pointer, val: PrimVal) -> EvalResult<'tcx, ()> {
let pointer_size = self.pointer_size;
let pointer_size = self.pointer_size();
match val {
PrimVal::Bool(b) => self.write_bool(ptr, b),
PrimVal::I8(n) => self.write_int(ptr, n as i64, 1),
Expand Down Expand Up @@ -406,31 +407,30 @@ impl<'tcx> Memory<'tcx> {
}

pub fn read_isize(&self, ptr: Pointer) -> EvalResult<'tcx, i64> {
self.read_int(ptr, self.pointer_size)
self.read_int(ptr, self.pointer_size())
}

pub fn write_isize(&mut self, ptr: Pointer, n: i64) -> EvalResult<'tcx, ()> {
let size = self.pointer_size;
let size = self.pointer_size();
self.write_int(ptr, n, size)
}

pub fn read_usize(&self, ptr: Pointer) -> EvalResult<'tcx, u64> {
self.read_uint(ptr, self.pointer_size)
self.read_uint(ptr, self.pointer_size())
}

pub fn write_usize(&mut self, ptr: Pointer, n: u64) -> EvalResult<'tcx, ()> {
let size = self.pointer_size;
let size = self.pointer_size();
self.write_uint(ptr, n, size)
}
}

////////////////////////////////////////////////////////////////////////////////
// Relocations
////////////////////////////////////////////////////////////////////////////////

/// Relocations
impl<'a, 'tcx> Memory<'a, 'tcx> {
fn relocations(&self, ptr: Pointer, size: usize)
-> EvalResult<'tcx, btree_map::Range<usize, AllocId>>
{
let start = ptr.offset.saturating_sub(self.pointer_size - 1);
let start = ptr.offset.saturating_sub(self.pointer_size() - 1);
let end = ptr.offset + size;
Ok(self.get(ptr.alloc_id)?.relocations.range(Included(&start), Excluded(&end)))
}
Expand All @@ -444,7 +444,7 @@ impl<'tcx> Memory<'tcx> {
let start = ptr.offset;
let end = start + size;
let first = *keys.first().unwrap();
let last = *keys.last().unwrap() + self.pointer_size;
let last = *keys.last().unwrap() + self.pointer_size();

let alloc = self.get_mut(ptr.alloc_id)?;

Expand Down Expand Up @@ -478,11 +478,10 @@ impl<'tcx> Memory<'tcx> {
self.get_mut(dest.alloc_id)?.relocations.extend(relocations);
Ok(())
}
}

////////////////////////////////////////////////////////////////////////////////
// Undefined bytes
////////////////////////////////////////////////////////////////////////////////

/// Undefined bytes
impl<'a, 'tcx> Memory<'a, 'tcx> {
// FIXME(solson): This is a very naive, slow version.
fn copy_undef_mask(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<'tcx, ()> {
// The bits have to be saved locally before writing to dest in case src and dest overlap.
Expand Down
14 changes: 14 additions & 0 deletions tests/compile-fail/invalid_enum_discriminant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#[repr(C)]
pub enum Foo {
A, B, C, D
}

fn main() {
let f = unsafe { std::mem::transmute::<i32, Foo>(42) };
match f {
Foo::A => {}, //~ ERROR invalid enum discriminant value read
Foo::B => {},
Foo::C => {},
Foo::D => {},
}
}
8 changes: 8 additions & 0 deletions tests/compile-fail/match_char.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
fn main() {
assert!(std::char::from_u32(-1_i32 as u32).is_none());
match unsafe { std::mem::transmute::<i32, char>(-1) } {
'a' => {}, //~ERROR tried to interpret an invalid 32-bit value as a char: 4294967295
'b' => {},
_ => {},
}
}
2 changes: 1 addition & 1 deletion tests/compiletest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ fn compile_test() {
match cmd.output() {
Ok(ref output) if output.status.success() => writeln!(stderr.lock(), "ok").unwrap(),
Ok(output) => {
writeln!(stderr.lock(), "FAILED with exit code {}", output.status.code().unwrap_or(0)).unwrap();
writeln!(stderr.lock(), "FAILED with exit code {:?}", output.status.code()).unwrap();
writeln!(stderr.lock(), "stdout: \n {}", std::str::from_utf8(&output.stdout).unwrap()).unwrap();
writeln!(stderr.lock(), "stderr: \n {}", std::str::from_utf8(&output.stderr).unwrap()).unwrap();
panic!("some tests failed");
Expand Down

0 comments on commit ba23b87

Please sign in to comment.