forbid calling functions through pointers of a different type
This commit is contained in:
parent
55fd060cd8
commit
c36dcff005
6 changed files with 100 additions and 70 deletions
14
src/error.rs
14
src/error.rs
|
|
@ -1,10 +1,12 @@
|
|||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use rustc::mir::repr as mir;
|
||||
use rustc::ty::BareFnTy;
|
||||
use memory::Pointer;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum EvalError {
|
||||
pub enum EvalError<'tcx> {
|
||||
FunctionPointerTyMismatch(&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>),
|
||||
DanglingPointerDeref,
|
||||
InvalidFunctionPointer,
|
||||
InvalidBool,
|
||||
|
|
@ -24,11 +26,13 @@ pub enum EvalError {
|
|||
ExecuteMemory,
|
||||
}
|
||||
|
||||
pub type EvalResult<T> = Result<T, EvalError>;
|
||||
pub type EvalResult<'tcx, T> = Result<T, EvalError<'tcx>>;
|
||||
|
||||
impl Error for EvalError {
|
||||
impl<'tcx> Error for EvalError<'tcx> {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
EvalError::FunctionPointerTyMismatch(..) =>
|
||||
"tried to call a function through a function pointer of a different type",
|
||||
EvalError::DanglingPointerDeref =>
|
||||
"dangling pointer was dereferenced",
|
||||
EvalError::InvalidFunctionPointer =>
|
||||
|
|
@ -60,13 +64,15 @@ impl Error for EvalError {
|
|||
fn cause(&self) -> Option<&Error> { None }
|
||||
}
|
||||
|
||||
impl fmt::Display for EvalError {
|
||||
impl<'tcx> fmt::Display for EvalError<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
EvalError::PointerOutOfBounds { ptr, size, allocation_size } => {
|
||||
write!(f, "memory access of {}..{} outside bounds of allocation {} which has size {}",
|
||||
ptr.offset, ptr.offset + size, ptr.alloc_id, allocation_size)
|
||||
},
|
||||
EvalError::FunctionPointerTyMismatch(expected, got) =>
|
||||
write!(f, "tried to call a function of type {:?} through a function pointer of type {:?}", expected, got),
|
||||
_ => write!(f, "{}", self.description()),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,14 +18,14 @@ use syntax::attr;
|
|||
use syntax::codemap::{self, DUMMY_SP, Span};
|
||||
|
||||
use error::{EvalError, EvalResult};
|
||||
use memory::{Memory, Pointer};
|
||||
use memory::{Memory, Pointer, FunctionDefinition};
|
||||
use primval::{self, PrimVal};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
mod stepper;
|
||||
|
||||
pub fn step<'ecx, 'a: 'ecx, 'tcx: 'a>(ecx: &'ecx mut EvalContext<'a, 'tcx>) -> EvalResult<bool> {
|
||||
pub fn step<'ecx, 'a: 'ecx, 'tcx: 'a>(ecx: &'ecx mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, bool> {
|
||||
stepper::Stepper::new(ecx).step()
|
||||
}
|
||||
|
||||
|
|
@ -159,7 +159,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// TODO(solson): Try making const_to_primval instead.
|
||||
fn const_to_ptr(&mut self, const_val: &const_val::ConstVal) -> EvalResult<Pointer> {
|
||||
fn const_to_ptr(&mut self, const_val: &const_val::ConstVal) -> EvalResult<'tcx, Pointer> {
|
||||
use rustc::middle::const_val::ConstVal::*;
|
||||
match *const_val {
|
||||
Float(_f) => unimplemented!(),
|
||||
|
|
@ -368,7 +368,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>)
|
||||
-> EvalResult<()> {
|
||||
-> EvalResult<'tcx, ()> {
|
||||
use rustc::mir::repr::TerminatorKind::*;
|
||||
match terminator.kind {
|
||||
Return => self.pop_stack_frame(),
|
||||
|
|
@ -434,7 +434,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
let ptr = self.eval_operand(func)?;
|
||||
assert_eq!(ptr.offset, 0);
|
||||
let fn_ptr = self.memory.read_ptr(ptr)?;
|
||||
let (def_id, substs) = self.memory.get_fn(fn_ptr.alloc_id)?;
|
||||
let FunctionDefinition { def_id, substs, fn_ty } = self.memory.get_fn(fn_ptr.alloc_id)?;
|
||||
if fn_ty != bare_fn_ty {
|
||||
return Err(EvalError::FunctionPointerTyMismatch(fn_ty, bare_fn_ty));
|
||||
}
|
||||
self.eval_fn_call(def_id, substs, bare_fn_ty, return_ptr, args,
|
||||
terminator.source_info.span)?
|
||||
},
|
||||
|
|
@ -480,7 +483,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
return_ptr: Option<Pointer>,
|
||||
args: &[mir::Operand<'tcx>],
|
||||
span: Span,
|
||||
) -> EvalResult<()> {
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
use syntax::abi::Abi;
|
||||
match fn_ty.abi {
|
||||
Abi::RustIntrinsic => {
|
||||
|
|
@ -559,7 +562,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn drop(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
|
||||
fn drop(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, ()> {
|
||||
if !self.type_needs_drop(ty) {
|
||||
debug!("no need to drop {:?}", ty);
|
||||
return Ok(());
|
||||
|
|
@ -601,7 +604,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<u64> {
|
||||
fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u64> {
|
||||
use rustc::ty::layout::Layout::*;
|
||||
let adt_layout = self.type_layout(adt_ty);
|
||||
|
||||
|
|
@ -629,7 +632,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
Ok(discr_val)
|
||||
}
|
||||
|
||||
fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u64) -> EvalResult<u64> {
|
||||
fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u64) -> EvalResult<'tcx, u64> {
|
||||
let not_null = match self.memory.read_usize(ptr) {
|
||||
Ok(0) => false,
|
||||
Ok(_) | Err(EvalError::ReadPointerAsBytes) => true,
|
||||
|
|
@ -646,7 +649,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
args: &[mir::Operand<'tcx>],
|
||||
dest: Pointer,
|
||||
dest_size: usize
|
||||
) -> EvalResult<()> {
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
let args_res: EvalResult<Vec<Pointer>> = args.iter()
|
||||
.map(|arg| self.eval_operand(arg))
|
||||
.collect();
|
||||
|
|
@ -792,7 +795,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
args: &[mir::Operand<'tcx>],
|
||||
dest: Pointer,
|
||||
dest_size: usize,
|
||||
) -> EvalResult<()> {
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
let name = self.tcx.item_name(def_id);
|
||||
let attrs = self.tcx.get_attrs(def_id);
|
||||
let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") {
|
||||
|
|
@ -855,7 +858,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
dest: Pointer,
|
||||
offsets: I,
|
||||
operands: &[mir::Operand<'tcx>],
|
||||
) -> EvalResult<()> {
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
for (offset, operand) in offsets.into_iter().zip(operands) {
|
||||
let src = self.eval_operand(operand)?;
|
||||
let src_ty = self.operand_ty(operand);
|
||||
|
|
@ -866,7 +869,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<'tcx>)
|
||||
-> EvalResult<()>
|
||||
-> EvalResult<'tcx, ()>
|
||||
{
|
||||
let dest = self.eval_lvalue(lvalue)?.to_ptr();
|
||||
let dest_ty = self.lvalue_ty(lvalue);
|
||||
|
|
@ -1095,8 +1098,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
ReifyFnPointer => match self.operand_ty(operand).sty {
|
||||
ty::TyFnDef(def_id, substs, _) => {
|
||||
let fn_ptr = self.memory.create_fn_ptr(def_id, substs);
|
||||
ty::TyFnDef(def_id, substs, fn_ty) => {
|
||||
let fn_ptr = self.memory.create_fn_ptr(def_id, substs, fn_ty);
|
||||
self.memory.write_ptr(dest, fn_ptr)?;
|
||||
},
|
||||
ref other => panic!("reify fn pointer on {:?}", other),
|
||||
|
|
@ -1112,7 +1115,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn nonnull_offset(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> EvalResult<Size> {
|
||||
fn nonnull_offset(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> EvalResult<'tcx, Size> {
|
||||
// Skip the constant 0 at the start meant for LLVM GEP.
|
||||
let mut path = discrfield.iter().skip(1).map(|&i| i as usize);
|
||||
|
||||
|
|
@ -1133,7 +1136,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
self.field_path_offset(inner_ty, path)
|
||||
}
|
||||
|
||||
fn field_path_offset<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<Size> {
|
||||
fn field_path_offset<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<'tcx, Size> {
|
||||
let mut offset = Size::from_bytes(0);
|
||||
|
||||
// Skip the initial 0 intended for LLVM GEP.
|
||||
|
|
@ -1146,7 +1149,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
Ok(offset)
|
||||
}
|
||||
|
||||
fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<Ty<'tcx>> {
|
||||
fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> {
|
||||
match ty.sty {
|
||||
ty::TyStruct(adt_def, substs) => {
|
||||
Ok(adt_def.struct_variant().fields[field_index].ty(self.tcx, substs))
|
||||
|
|
@ -1162,7 +1165,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<Size> {
|
||||
fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Size> {
|
||||
let layout = self.type_layout(ty);
|
||||
|
||||
use rustc::ty::layout::Layout::*;
|
||||
|
|
@ -1179,7 +1182,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<Pointer> {
|
||||
fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, Pointer> {
|
||||
use rustc::mir::repr::Operand::*;
|
||||
match *op {
|
||||
Consume(ref lvalue) => Ok(self.eval_lvalue(lvalue)?.to_ptr()),
|
||||
|
|
@ -1213,7 +1216,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<Lvalue> {
|
||||
fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, Lvalue> {
|
||||
use rustc::mir::repr::Lvalue::*;
|
||||
let ptr = match *lvalue {
|
||||
ReturnPointer => self.frame().return_ptr
|
||||
|
|
@ -1321,7 +1324,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
self.monomorphize(self.mir().operand_ty(self.tcx, operand), self.substs())
|
||||
}
|
||||
|
||||
fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
|
||||
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)?;
|
||||
if self.type_needs_drop(ty) {
|
||||
|
|
@ -1330,7 +1333,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_primval(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<PrimVal> {
|
||||
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) {
|
||||
(_, &ty::TyBool) => PrimVal::Bool(self.memory.read_bool(ptr)?),
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ impl<'ecx, 'a, 'tcx> Stepper<'ecx, 'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<()> {
|
||||
fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx, ()> {
|
||||
trace!("{:?}", stmt);
|
||||
let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind;
|
||||
self.ecx.eval_assignment(lvalue, rvalue)?;
|
||||
|
|
@ -31,7 +31,7 @@ impl<'ecx, 'a, 'tcx> Stepper<'ecx, 'a, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<()> {
|
||||
fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx, ()> {
|
||||
// after a terminator we go to a new block
|
||||
self.ecx.frame_mut().stmt = 0;
|
||||
trace!("{:?}", terminator.kind);
|
||||
|
|
@ -43,7 +43,7 @@ impl<'ecx, 'a, 'tcx> Stepper<'ecx, 'a, 'tcx> {
|
|||
}
|
||||
|
||||
// returns true as long as there are more things to do
|
||||
pub(super) fn step(&mut self) -> EvalResult<bool> {
|
||||
pub(super) fn step(&mut self) -> EvalResult<'tcx, bool> {
|
||||
if self.ecx.stack.is_empty() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque};
|
|||
use std::{fmt, iter, mem, ptr};
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::ty::BareFnTy;
|
||||
use rustc::ty::subst::Substs;
|
||||
|
||||
use error::{EvalError, EvalResult};
|
||||
|
|
@ -41,6 +42,13 @@ impl Pointer {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct FunctionDefinition<'tcx> {
|
||||
pub def_id: DefId,
|
||||
pub substs: &'tcx Substs<'tcx>,
|
||||
pub fn_ty: &'tcx BareFnTy<'tcx>,
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Top-level interpreter memory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -50,7 +58,7 @@ pub struct Memory<'tcx> {
|
|||
alloc_map: HashMap<AllocId, Allocation>,
|
||||
/// Function "allocations". They exist solely so pointers have something to point to, and
|
||||
/// we can figure out what they point to.
|
||||
functions: HashMap<AllocId, (DefId, &'tcx Substs<'tcx>)>,
|
||||
functions: HashMap<AllocId, FunctionDefinition<'tcx>>,
|
||||
next_id: AllocId,
|
||||
pub pointer_size: usize,
|
||||
}
|
||||
|
|
@ -68,11 +76,15 @@ impl<'tcx> Memory<'tcx> {
|
|||
|
||||
// FIXME: never create two pointers to the same def_id + substs combination
|
||||
// maybe re-use the statics cache of the EvalContext?
|
||||
pub fn create_fn_ptr(&mut self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Pointer {
|
||||
pub fn create_fn_ptr(&mut self, def_id: DefId, substs: &'tcx Substs<'tcx>, fn_ty: &'tcx BareFnTy<'tcx>) -> Pointer {
|
||||
let id = self.next_id;
|
||||
debug!("creating fn ptr: {}", id);
|
||||
self.next_id.0 += 1;
|
||||
self.functions.insert(id, (def_id, substs));
|
||||
self.functions.insert(id, FunctionDefinition {
|
||||
def_id: def_id,
|
||||
substs: substs,
|
||||
fn_ty: fn_ty,
|
||||
});
|
||||
Pointer {
|
||||
alloc_id: id,
|
||||
offset: 0,
|
||||
|
|
@ -96,7 +108,7 @@ impl<'tcx> Memory<'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<()> {
|
||||
pub fn reallocate(&mut self, ptr: Pointer, new_size: usize) -> EvalResult<'tcx, ()> {
|
||||
if ptr.offset != 0 {
|
||||
// TODO(solson): Report error about non-__rust_allocate'd pointer.
|
||||
return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset)));
|
||||
|
|
@ -120,7 +132,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
}
|
||||
|
||||
// TODO(solson): See comment on `reallocate`.
|
||||
pub fn deallocate(&mut self, ptr: Pointer) -> EvalResult<()> {
|
||||
pub fn deallocate(&mut self, ptr: Pointer) -> EvalResult<'tcx, ()> {
|
||||
if ptr.offset != 0 {
|
||||
// TODO(solson): Report error about non-__rust_allocate'd pointer.
|
||||
return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset)));
|
||||
|
|
@ -139,7 +151,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
// Allocation accessors
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub fn get(&self, id: AllocId) -> EvalResult<&Allocation> {
|
||||
pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
|
||||
match self.alloc_map.get(&id) {
|
||||
Some(alloc) => Ok(alloc),
|
||||
None => match self.functions.get(&id) {
|
||||
|
|
@ -149,7 +161,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, id: AllocId) -> EvalResult<&mut Allocation> {
|
||||
pub fn get_mut(&mut self, id: AllocId) -> EvalResult<'tcx, &mut Allocation> {
|
||||
match self.alloc_map.get_mut(&id) {
|
||||
Some(alloc) => Ok(alloc),
|
||||
None => match self.functions.get(&id) {
|
||||
|
|
@ -159,7 +171,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_fn(&self, id: AllocId) -> EvalResult<(DefId, &'tcx Substs<'tcx>)> {
|
||||
pub fn get_fn(&self, id: AllocId) -> EvalResult<'tcx, FunctionDefinition<'tcx>> {
|
||||
debug!("reading fn ptr: {}", id);
|
||||
match self.functions.get(&id) {
|
||||
Some(&fn_id) => Ok(fn_id),
|
||||
|
|
@ -229,7 +241,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
// Byte accessors
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fn get_bytes_unchecked(&self, ptr: Pointer, size: usize) -> EvalResult<&[u8]> {
|
||||
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() {
|
||||
return Err(EvalError::PointerOutOfBounds {
|
||||
|
|
@ -241,7 +253,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
Ok(&alloc.bytes[ptr.offset..ptr.offset + size])
|
||||
}
|
||||
|
||||
fn get_bytes_unchecked_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<&mut [u8]> {
|
||||
fn get_bytes_unchecked_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &mut [u8]> {
|
||||
let alloc = self.get_mut(ptr.alloc_id)?;
|
||||
if ptr.offset + size > alloc.bytes.len() {
|
||||
return Err(EvalError::PointerOutOfBounds {
|
||||
|
|
@ -253,7 +265,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
Ok(&mut alloc.bytes[ptr.offset..ptr.offset + size])
|
||||
}
|
||||
|
||||
fn get_bytes(&self, ptr: Pointer, size: usize) -> EvalResult<&[u8]> {
|
||||
fn get_bytes(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &[u8]> {
|
||||
if self.relocations(ptr, size)?.count() != 0 {
|
||||
return Err(EvalError::ReadPointerAsBytes);
|
||||
}
|
||||
|
|
@ -261,7 +273,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
self.get_bytes_unchecked(ptr, size)
|
||||
}
|
||||
|
||||
fn get_bytes_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<&mut [u8]> {
|
||||
fn get_bytes_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &mut [u8]> {
|
||||
self.clear_relocations(ptr, size)?;
|
||||
self.mark_definedness(ptr, size, true)?;
|
||||
self.get_bytes_unchecked_mut(ptr, size)
|
||||
|
|
@ -271,7 +283,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
// Reading and writing
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<()> {
|
||||
pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<'tcx, ()> {
|
||||
self.check_relocation_edges(src, size)?;
|
||||
|
||||
let src_bytes = self.get_bytes_unchecked_mut(src, size)?.as_mut_ptr();
|
||||
|
|
@ -294,27 +306,27 @@ impl<'tcx> Memory<'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_bytes(&self, ptr: Pointer, size: usize) -> EvalResult<&[u8]> {
|
||||
pub fn read_bytes(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &[u8]> {
|
||||
self.get_bytes(ptr, size)
|
||||
}
|
||||
|
||||
pub fn write_bytes(&mut self, ptr: Pointer, src: &[u8]) -> EvalResult<()> {
|
||||
pub fn write_bytes(&mut self, ptr: Pointer, src: &[u8]) -> EvalResult<'tcx, ()> {
|
||||
let bytes = self.get_bytes_mut(ptr, src.len())?;
|
||||
bytes.clone_from_slice(src);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_repeat(&mut self, ptr: Pointer, val: u8, count: usize) -> EvalResult<()> {
|
||||
pub fn write_repeat(&mut self, ptr: Pointer, val: u8, count: usize) -> EvalResult<'tcx, ()> {
|
||||
let bytes = self.get_bytes_mut(ptr, count)?;
|
||||
for b in bytes { *b = val; }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn drop_fill(&mut self, ptr: Pointer, size: usize) -> EvalResult<()> {
|
||||
pub fn drop_fill(&mut self, ptr: Pointer, size: usize) -> EvalResult<'tcx, ()> {
|
||||
self.write_repeat(ptr, mem::POST_DROP_U8, size)
|
||||
}
|
||||
|
||||
pub fn read_ptr(&self, ptr: Pointer) -> EvalResult<Pointer> {
|
||||
pub fn read_ptr(&self, ptr: Pointer) -> EvalResult<'tcx, Pointer> {
|
||||
let size = self.pointer_size;
|
||||
self.check_defined(ptr, size)?;
|
||||
let offset = self.get_bytes_unchecked(ptr, size)?
|
||||
|
|
@ -326,7 +338,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn write_ptr(&mut self, dest: Pointer, ptr: Pointer) -> EvalResult<()> {
|
||||
pub fn write_ptr(&mut self, dest: Pointer, ptr: Pointer) -> EvalResult<'tcx, ()> {
|
||||
{
|
||||
let size = self.pointer_size;
|
||||
let mut bytes = self.get_bytes_mut(dest, size)?;
|
||||
|
|
@ -336,7 +348,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_primval(&mut self, ptr: Pointer, val: PrimVal) -> EvalResult<()> {
|
||||
pub fn write_primval(&mut self, ptr: Pointer, val: PrimVal) -> EvalResult<'tcx, ()> {
|
||||
let pointer_size = self.pointer_size;
|
||||
match val {
|
||||
PrimVal::Bool(b) => self.write_bool(ptr, b),
|
||||
|
|
@ -353,7 +365,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn read_bool(&self, ptr: Pointer) -> EvalResult<bool> {
|
||||
pub fn read_bool(&self, ptr: Pointer) -> EvalResult<'tcx, bool> {
|
||||
let bytes = self.get_bytes(ptr, 1)?;
|
||||
match bytes[0] {
|
||||
0 => Ok(false),
|
||||
|
|
@ -362,40 +374,40 @@ impl<'tcx> Memory<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn write_bool(&mut self, ptr: Pointer, b: bool) -> EvalResult<()> {
|
||||
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)
|
||||
}
|
||||
|
||||
pub fn read_int(&self, ptr: Pointer, size: usize) -> EvalResult<i64> {
|
||||
pub fn read_int(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, i64> {
|
||||
self.get_bytes(ptr, size).map(|mut b| b.read_int::<NativeEndian>(size).unwrap())
|
||||
}
|
||||
|
||||
pub fn write_int(&mut self, ptr: Pointer, n: i64, size: usize) -> EvalResult<()> {
|
||||
pub fn write_int(&mut self, ptr: Pointer, n: i64, size: usize) -> EvalResult<'tcx, ()> {
|
||||
self.get_bytes_mut(ptr, size).map(|mut b| b.write_int::<NativeEndian>(n, size).unwrap())
|
||||
}
|
||||
|
||||
pub fn read_uint(&self, ptr: Pointer, size: usize) -> EvalResult<u64> {
|
||||
pub fn read_uint(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, u64> {
|
||||
self.get_bytes(ptr, size).map(|mut b| b.read_uint::<NativeEndian>(size).unwrap())
|
||||
}
|
||||
|
||||
pub fn write_uint(&mut self, ptr: Pointer, n: u64, size: usize) -> EvalResult<()> {
|
||||
pub fn write_uint(&mut self, ptr: Pointer, n: u64, size: usize) -> EvalResult<'tcx, ()> {
|
||||
self.get_bytes_mut(ptr, size).map(|mut b| b.write_uint::<NativeEndian>(n, size).unwrap())
|
||||
}
|
||||
|
||||
pub fn read_isize(&self, ptr: Pointer) -> EvalResult<i64> {
|
||||
pub fn read_isize(&self, ptr: Pointer) -> EvalResult<'tcx, i64> {
|
||||
self.read_int(ptr, self.pointer_size)
|
||||
}
|
||||
|
||||
pub fn write_isize(&mut self, ptr: Pointer, n: i64) -> EvalResult<()> {
|
||||
pub fn write_isize(&mut self, ptr: Pointer, n: i64) -> EvalResult<'tcx, ()> {
|
||||
let size = self.pointer_size;
|
||||
self.write_int(ptr, n, size)
|
||||
}
|
||||
|
||||
pub fn read_usize(&self, ptr: Pointer) -> EvalResult<u64> {
|
||||
pub fn read_usize(&self, ptr: Pointer) -> EvalResult<'tcx, u64> {
|
||||
self.read_uint(ptr, self.pointer_size)
|
||||
}
|
||||
|
||||
pub fn write_usize(&mut self, ptr: Pointer, n: u64) -> EvalResult<()> {
|
||||
pub fn write_usize(&mut self, ptr: Pointer, n: u64) -> EvalResult<'tcx, ()> {
|
||||
let size = self.pointer_size;
|
||||
self.write_uint(ptr, n, size)
|
||||
}
|
||||
|
|
@ -405,14 +417,14 @@ impl<'tcx> Memory<'tcx> {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fn relocations(&self, ptr: Pointer, size: usize)
|
||||
-> EvalResult<btree_map::Range<usize, AllocId>>
|
||||
-> EvalResult<'tcx, btree_map::Range<usize, AllocId>>
|
||||
{
|
||||
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)))
|
||||
}
|
||||
|
||||
fn clear_relocations(&mut self, ptr: Pointer, size: usize) -> EvalResult<()> {
|
||||
fn clear_relocations(&mut self, ptr: Pointer, size: usize) -> EvalResult<'tcx, ()> {
|
||||
// Find all relocations overlapping the given range.
|
||||
let keys: Vec<_> = self.relocations(ptr, size)?.map(|(&k, _)| k).collect();
|
||||
if keys.is_empty() { return Ok(()); }
|
||||
|
|
@ -436,7 +448,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn check_relocation_edges(&self, ptr: Pointer, size: usize) -> EvalResult<()> {
|
||||
fn check_relocation_edges(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, ()> {
|
||||
let overlapping_start = self.relocations(ptr, 0)?.count();
|
||||
let overlapping_end = self.relocations(ptr.offset(size as isize), 0)?.count();
|
||||
if overlapping_start + overlapping_end != 0 {
|
||||
|
|
@ -445,7 +457,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn copy_relocations(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<()> {
|
||||
fn copy_relocations(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<'tcx, ()> {
|
||||
let relocations: Vec<_> = self.relocations(src, size)?
|
||||
.map(|(&offset, &alloc_id)| {
|
||||
// Update relocation offsets for the new positions in the destination allocation.
|
||||
|
|
@ -461,7 +473,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FIXME(solson): This is a very naive, slow version.
|
||||
fn copy_undef_mask(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<()> {
|
||||
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.
|
||||
let mut v = Vec::with_capacity(size);
|
||||
for i in 0..size {
|
||||
|
|
@ -474,7 +486,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn check_defined(&self, ptr: Pointer, size: usize) -> EvalResult<()> {
|
||||
fn check_defined(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, ()> {
|
||||
let alloc = self.get(ptr.alloc_id)?;
|
||||
if !alloc.undef_mask.is_range_defined(ptr.offset, ptr.offset + size) {
|
||||
return Err(EvalError::ReadUndefBytes);
|
||||
|
|
@ -483,7 +495,7 @@ impl<'tcx> Memory<'tcx> {
|
|||
}
|
||||
|
||||
pub fn mark_definedness(&mut self, ptr: Pointer, size: usize, new_state: bool)
|
||||
-> EvalResult<()>
|
||||
-> EvalResult<'tcx, ()>
|
||||
{
|
||||
let mut alloc = self.get_mut(ptr.alloc_id)?;
|
||||
alloc.undef_mask.set_range(ptr.offset, ptr.offset + size, new_state);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ pub enum PrimVal {
|
|||
IntegerPtr(u64),
|
||||
}
|
||||
|
||||
pub fn binary_op(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> EvalResult<PrimVal> {
|
||||
pub fn binary_op<'tcx>(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> EvalResult<'tcx, PrimVal> {
|
||||
use rustc::mir::repr::BinOp::*;
|
||||
use self::PrimVal::*;
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ pub fn binary_op(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> EvalResul
|
|||
})
|
||||
}
|
||||
|
||||
fn unrelated_ptr_ops(bin_op: mir::BinOp) -> EvalResult<PrimVal> {
|
||||
fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp) -> EvalResult<'tcx, PrimVal> {
|
||||
use rustc::mir::repr::BinOp::*;
|
||||
match bin_op {
|
||||
Eq => Ok(Bool(false)),
|
||||
|
|
@ -108,7 +108,7 @@ pub fn binary_op(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> EvalResul
|
|||
Ok(val)
|
||||
}
|
||||
|
||||
pub fn unary_op(un_op: mir::UnOp, val: PrimVal) -> EvalResult<PrimVal> {
|
||||
pub fn unary_op<'tcx>(un_op: mir::UnOp, val: PrimVal) -> EvalResult<'tcx, PrimVal> {
|
||||
use rustc::mir::repr::UnOp::*;
|
||||
use self::PrimVal::*;
|
||||
match (un_op, val) {
|
||||
|
|
|
|||
9
tests/compile-fail/cast_fn_ptr.rs
Normal file
9
tests/compile-fail/cast_fn_ptr.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
fn main() { //~ ERROR tried to call a function of type
|
||||
fn f() {}
|
||||
|
||||
let g = unsafe {
|
||||
std::mem::transmute::<fn(), fn(i32)>(f)
|
||||
};
|
||||
|
||||
g(42)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue