1
Fork 0

4byte pointers

This commit is contained in:
Oliver Schneider 2016-05-31 12:05:25 +02:00
parent b78ca5f7e1
commit 12c2e5fab2
No known key found for this signature in database
GPG key ID: 56D6EEA0FC67AC46
6 changed files with 70 additions and 38 deletions

View file

@ -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()),
}
}
}

View file

@ -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<PrimVal> {
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),
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),
// 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, .. }) => {
(_, &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),

View file

@ -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])
}

View file

@ -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<u8> = 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]

View file

@ -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]

View file

@ -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() {}