4byte pointers
This commit is contained in:
parent
b78ca5f7e1
commit
12c2e5fab2
6 changed files with 70 additions and 38 deletions
13
src/error.rs
13
src/error.rs
|
@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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])
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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() {}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue