From c36dcff0056a4a48651b778ed272aba80f6edd93 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 14 Jun 2016 10:34:54 +0200 Subject: [PATCH] forbid calling functions through pointers of a different type --- src/error.rs | 14 +++-- src/interpreter/mod.rs | 49 +++++++++--------- src/interpreter/stepper.rs | 6 +-- src/memory.rs | 86 ++++++++++++++++++------------- src/primval.rs | 6 +-- tests/compile-fail/cast_fn_ptr.rs | 9 ++++ 6 files changed, 100 insertions(+), 70 deletions(-) create mode 100644 tests/compile-fail/cast_fn_ptr.rs diff --git a/src/error.rs b/src/error.rs index 49fd8564be6..35a978f2d2e 100644 --- a/src/error.rs +++ b/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 = Result; +pub type EvalResult<'tcx, T> = Result>; -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 @@ fn description(&self) -> &str { 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()), } } diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 1b0b416e0e1..4acefb91130 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -18,14 +18,14 @@ 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 { +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 @@ pub fn stack(&self) -> &[Frame] { } // TODO(solson): Try making const_to_primval instead. - fn const_to_ptr(&mut self, const_val: &const_val::ConstVal) -> EvalResult { + 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 @@ fn pop_stack_frame(&mut self) { } 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 @@ fn eval_terminator(&mut self, terminator: &mir::Terminator<'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 @@ pub fn eval_fn_call( return_ptr: Option, args: &[mir::Operand<'tcx>], span: Span, - ) -> EvalResult<()> { + ) -> EvalResult<'tcx, ()> { use syntax::abi::Abi; match fn_ty.abi { Abi::RustIntrinsic => { @@ -559,7 +562,7 @@ pub fn eval_fn_call( } } - 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 @@ fn drop(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<()> { Ok(()) } - fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult { + 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 @@ fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalRes Ok(discr_val) } - fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u64) -> EvalResult { + 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 @@ fn call_intrinsic( args: &[mir::Operand<'tcx>], dest: Pointer, dest_size: usize - ) -> EvalResult<()> { + ) -> EvalResult<'tcx, ()> { let args_res: EvalResult> = args.iter() .map(|arg| self.eval_operand(arg)) .collect(); @@ -792,7 +795,7 @@ fn call_c_abi( 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 @@ fn assign_fields>( 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 @@ fn assign_fields>( } 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 @@ fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<' } 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 @@ fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<' Ok(()) } - fn nonnull_offset(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> EvalResult { + 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 @@ fn nonnull_offset(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> Eval self.field_path_offset(inner_ty, path) } - fn field_path_offset>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult { + fn field_path_offset>(&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 @@ fn field_path_offset>(&self, mut ty: Ty<'tcx>, path: I Ok(offset) } - fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult> { + 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 @@ fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult> } } - fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult { + 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 @@ fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult } } - fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult { + 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 @@ fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult { } } - fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult { + 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 @@ fn operand_ty(&self, operand: &mir::Operand<'tcx>) -> Ty<'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 @@ fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<()> Ok(()) } - pub fn read_primval(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult { + 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)?), diff --git a/src/interpreter/stepper.rs b/src/interpreter/stepper.rs index 8603054d124..36711943841 100644 --- a/src/interpreter/stepper.rs +++ b/src/interpreter/stepper.rs @@ -23,7 +23,7 @@ pub(super) fn new(ecx: &'ecx mut EvalContext<'a, 'tcx>) -> Self { } } - 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 @@ fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<()> { 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 @@ fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<()> { } // returns true as long as there are more things to do - pub(super) fn step(&mut self) -> EvalResult { + pub(super) fn step(&mut self) -> EvalResult<'tcx, bool> { if self.ecx.stack.is_empty() { return Ok(false); } diff --git a/src/memory.rs b/src/memory.rs index 35ee99eab97..e20d92207db 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -4,6 +4,7 @@ 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 @@ pub fn offset(self, i: isize) -> Self { } } +#[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, /// Function "allocations". They exist solely so pointers have something to point to, and /// we can figure out what they point to. - functions: HashMap)>, + functions: HashMap>, next_id: AllocId, pub pointer_size: usize, } @@ -68,11 +76,15 @@ pub fn new(pointer_size: usize) -> Self { // 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 @@ pub fn allocate(&mut self, size: usize) -> Pointer { // 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 @@ pub fn reallocate(&mut self, ptr: Pointer, new_size: usize) -> EvalResult<()> { } // 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 @@ pub fn deallocate(&mut self, ptr: Pointer) -> EvalResult<()> { // 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 @@ pub fn get(&self, id: AllocId) -> EvalResult<&Allocation> { } } - 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 @@ pub fn get_mut(&mut self, id: AllocId) -> EvalResult<&mut Allocation> { } } - 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 @@ pub fn dump(&self, id: AllocId) { // 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 @@ fn get_bytes_unchecked(&self, ptr: Pointer, size: usize) -> EvalResult<&[u8]> { 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 @@ fn get_bytes_unchecked_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<& 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 @@ fn get_bytes(&self, ptr: Pointer, size: usize) -> EvalResult<&[u8]> { 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 @@ fn get_bytes_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<&mut [u8]> // 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 @@ pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<( 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 { + 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 @@ pub fn read_ptr(&self, ptr: Pointer) -> EvalResult { } } - 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 @@ pub fn write_ptr(&mut self, dest: Pointer, ptr: Pointer) -> EvalResult<()> { 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 @@ pub fn write_primval(&mut self, ptr: Pointer, val: PrimVal) -> EvalResult<()> { } } - pub fn read_bool(&self, ptr: Pointer) -> EvalResult { + 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 @@ pub fn read_bool(&self, ptr: Pointer) -> EvalResult { } } - 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 { + pub fn read_int(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, i64> { self.get_bytes(ptr, size).map(|mut b| b.read_int::(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::(n, size).unwrap()) } - pub fn read_uint(&self, ptr: Pointer, size: usize) -> EvalResult { + pub fn read_uint(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, u64> { self.get_bytes(ptr, size).map(|mut b| b.read_uint::(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::(n, size).unwrap()) } - pub fn read_isize(&self, ptr: Pointer) -> EvalResult { + 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 { + 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 @@ pub fn write_usize(&mut self, ptr: Pointer, n: u64) -> EvalResult<()> { //////////////////////////////////////////////////////////////////////////////// fn relocations(&self, ptr: Pointer, size: usize) - -> EvalResult> + -> EvalResult<'tcx, btree_map::Range> { 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 @@ fn clear_relocations(&mut self, ptr: Pointer, size: usize) -> EvalResult<()> { 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 @@ fn check_relocation_edges(&self, ptr: Pointer, size: usize) -> EvalResult<()> { 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 @@ fn copy_relocations(&mut self, src: Pointer, dest: Pointer, size: usize) -> Eval //////////////////////////////////////////////////////////////////////////////// // 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 @@ fn copy_undef_mask(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalR 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 @@ fn check_defined(&self, ptr: Pointer, size: usize) -> EvalResult<()> { } 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); diff --git a/src/primval.rs b/src/primval.rs index 0b1658739d9..5e1cdac45a1 100644 --- a/src/primval.rs +++ b/src/primval.rs @@ -13,7 +13,7 @@ pub enum PrimVal { IntegerPtr(u64), } -pub fn binary_op(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> EvalResult { +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 @@ macro_rules! int_binops { }) } - fn unrelated_ptr_ops(bin_op: mir::BinOp) -> EvalResult { + 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 @@ fn unrelated_ptr_ops(bin_op: mir::BinOp) -> EvalResult { Ok(val) } -pub fn unary_op(un_op: mir::UnOp, val: PrimVal) -> EvalResult { +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) { diff --git a/tests/compile-fail/cast_fn_ptr.rs b/tests/compile-fail/cast_fn_ptr.rs new file mode 100644 index 00000000000..db87e9e422b --- /dev/null +++ b/tests/compile-fail/cast_fn_ptr.rs @@ -0,0 +1,9 @@ +fn main() { //~ ERROR tried to call a function of type + fn f() {} + + let g = unsafe { + std::mem::transmute::(f) + }; + + g(42) +} -- 2.44.0