Skip to content

Commit b24edd6

Browse files
authored
Merge pull request rust-lang#24 from oli-obk/typesafe_fn_calls
Typesafe fn calls
2 parents 1146504 + c36dcff commit b24edd6

File tree

6 files changed

+100
-70
lines changed

6 files changed

+100
-70
lines changed

src/error.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
use std::error::Error;
22
use std::fmt;
33
use rustc::mir::repr as mir;
4+
use rustc::ty::BareFnTy;
45
use memory::Pointer;
56

67
#[derive(Clone, Debug)]
7-
pub enum EvalError {
8+
pub enum EvalError<'tcx> {
9+
FunctionPointerTyMismatch(&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>),
810
DanglingPointerDeref,
911
InvalidFunctionPointer,
1012
InvalidBool,
@@ -24,11 +26,13 @@ pub enum EvalError {
2426
ExecuteMemory,
2527
}
2628

27-
pub type EvalResult<T> = Result<T, EvalError>;
29+
pub type EvalResult<'tcx, T> = Result<T, EvalError<'tcx>>;
2830

29-
impl Error for EvalError {
31+
impl<'tcx> Error for EvalError<'tcx> {
3032
fn description(&self) -> &str {
3133
match *self {
34+
EvalError::FunctionPointerTyMismatch(..) =>
35+
"tried to call a function through a function pointer of a different type",
3236
EvalError::DanglingPointerDeref =>
3337
"dangling pointer was dereferenced",
3438
EvalError::InvalidFunctionPointer =>
@@ -60,13 +64,15 @@ impl Error for EvalError {
6064
fn cause(&self) -> Option<&Error> { None }
6165
}
6266

63-
impl fmt::Display for EvalError {
67+
impl<'tcx> fmt::Display for EvalError<'tcx> {
6468
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6569
match *self {
6670
EvalError::PointerOutOfBounds { ptr, size, allocation_size } => {
6771
write!(f, "memory access of {}..{} outside bounds of allocation {} which has size {}",
6872
ptr.offset, ptr.offset + size, ptr.alloc_id, allocation_size)
6973
},
74+
EvalError::FunctionPointerTyMismatch(expected, got) =>
75+
write!(f, "tried to call a function of type {:?} through a function pointer of type {:?}", expected, got),
7076
_ => write!(f, "{}", self.description()),
7177
}
7278
}

src/interpreter/mod.rs

+26-23
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ use syntax::attr;
1818
use syntax::codemap::{self, DUMMY_SP, Span};
1919

2020
use error::{EvalError, EvalResult};
21-
use memory::{Memory, Pointer};
21+
use memory::{Memory, Pointer, FunctionDefinition};
2222
use primval::{self, PrimVal};
2323

2424
use std::collections::HashMap;
2525

2626
mod stepper;
2727

28-
pub fn step<'ecx, 'a: 'ecx, 'tcx: 'a>(ecx: &'ecx mut EvalContext<'a, 'tcx>) -> EvalResult<bool> {
28+
pub fn step<'ecx, 'a: 'ecx, 'tcx: 'a>(ecx: &'ecx mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, bool> {
2929
stepper::Stepper::new(ecx).step()
3030
}
3131

@@ -163,7 +163,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
163163
}
164164

165165
// TODO(solson): Try making const_to_primval instead.
166-
fn const_to_ptr(&mut self, const_val: &const_val::ConstVal) -> EvalResult<Pointer> {
166+
fn const_to_ptr(&mut self, const_val: &const_val::ConstVal) -> EvalResult<'tcx, Pointer> {
167167
use rustc::middle::const_val::ConstVal::*;
168168
match *const_val {
169169
Float(_f) => unimplemented!(),
@@ -372,7 +372,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
372372
}
373373

374374
fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>)
375-
-> EvalResult<()> {
375+
-> EvalResult<'tcx, ()> {
376376
use rustc::mir::repr::TerminatorKind::*;
377377
match terminator.kind {
378378
Return => self.pop_stack_frame(),
@@ -438,7 +438,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
438438
let ptr = self.eval_operand(func)?;
439439
assert_eq!(ptr.offset, 0);
440440
let fn_ptr = self.memory.read_ptr(ptr)?;
441-
let (def_id, substs) = self.memory.get_fn(fn_ptr.alloc_id)?;
441+
let FunctionDefinition { def_id, substs, fn_ty } = self.memory.get_fn(fn_ptr.alloc_id)?;
442+
if fn_ty != bare_fn_ty {
443+
return Err(EvalError::FunctionPointerTyMismatch(fn_ty, bare_fn_ty));
444+
}
442445
self.eval_fn_call(def_id, substs, bare_fn_ty, return_ptr, args,
443446
terminator.source_info.span)?
444447
},
@@ -484,7 +487,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
484487
return_ptr: Option<Pointer>,
485488
args: &[mir::Operand<'tcx>],
486489
span: Span,
487-
) -> EvalResult<()> {
490+
) -> EvalResult<'tcx, ()> {
488491
use syntax::abi::Abi;
489492
match fn_ty.abi {
490493
Abi::RustIntrinsic => {
@@ -563,7 +566,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
563566
}
564567
}
565568

566-
fn drop(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
569+
fn drop(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, ()> {
567570
if !self.type_needs_drop(ty) {
568571
debug!("no need to drop {:?}", ty);
569572
return Ok(());
@@ -605,7 +608,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
605608
Ok(())
606609
}
607610

608-
fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<u64> {
611+
fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u64> {
609612
use rustc::ty::layout::Layout::*;
610613
let adt_layout = self.type_layout(adt_ty);
611614

@@ -633,7 +636,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
633636
Ok(discr_val)
634637
}
635638

636-
fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u64) -> EvalResult<u64> {
639+
fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u64) -> EvalResult<'tcx, u64> {
637640
let not_null = match self.memory.read_usize(ptr) {
638641
Ok(0) => false,
639642
Ok(_) | Err(EvalError::ReadPointerAsBytes) => true,
@@ -650,7 +653,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
650653
args: &[mir::Operand<'tcx>],
651654
dest: Pointer,
652655
dest_size: usize
653-
) -> EvalResult<()> {
656+
) -> EvalResult<'tcx, ()> {
654657
let args_res: EvalResult<Vec<Pointer>> = args.iter()
655658
.map(|arg| self.eval_operand(arg))
656659
.collect();
@@ -796,7 +799,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
796799
args: &[mir::Operand<'tcx>],
797800
dest: Pointer,
798801
dest_size: usize,
799-
) -> EvalResult<()> {
802+
) -> EvalResult<'tcx, ()> {
800803
let name = self.tcx.item_name(def_id);
801804
let attrs = self.tcx.get_attrs(def_id);
802805
let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") {
@@ -859,7 +862,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
859862
dest: Pointer,
860863
offsets: I,
861864
operands: &[mir::Operand<'tcx>],
862-
) -> EvalResult<()> {
865+
) -> EvalResult<'tcx, ()> {
863866
for (offset, operand) in offsets.into_iter().zip(operands) {
864867
let src = self.eval_operand(operand)?;
865868
let src_ty = self.operand_ty(operand);
@@ -870,7 +873,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
870873
}
871874

872875
fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<'tcx>)
873-
-> EvalResult<()>
876+
-> EvalResult<'tcx, ()>
874877
{
875878
let dest = self.eval_lvalue(lvalue)?.to_ptr();
876879
let dest_ty = self.lvalue_ty(lvalue);
@@ -1099,8 +1102,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
10991102
}
11001103

11011104
ReifyFnPointer => match self.operand_ty(operand).sty {
1102-
ty::TyFnDef(def_id, substs, _) => {
1103-
let fn_ptr = self.memory.create_fn_ptr(def_id, substs);
1105+
ty::TyFnDef(def_id, substs, fn_ty) => {
1106+
let fn_ptr = self.memory.create_fn_ptr(def_id, substs, fn_ty);
11041107
self.memory.write_ptr(dest, fn_ptr)?;
11051108
},
11061109
ref other => panic!("reify fn pointer on {:?}", other),
@@ -1116,7 +1119,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11161119
Ok(())
11171120
}
11181121

1119-
fn nonnull_offset(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> EvalResult<Size> {
1122+
fn nonnull_offset(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> EvalResult<'tcx, Size> {
11201123
// Skip the constant 0 at the start meant for LLVM GEP.
11211124
let mut path = discrfield.iter().skip(1).map(|&i| i as usize);
11221125

@@ -1137,7 +1140,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11371140
self.field_path_offset(inner_ty, path)
11381141
}
11391142

1140-
fn field_path_offset<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<Size> {
1143+
fn field_path_offset<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<'tcx, Size> {
11411144
let mut offset = Size::from_bytes(0);
11421145

11431146
// Skip the initial 0 intended for LLVM GEP.
@@ -1150,7 +1153,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11501153
Ok(offset)
11511154
}
11521155

1153-
fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<Ty<'tcx>> {
1156+
fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> {
11541157
match ty.sty {
11551158
ty::TyStruct(adt_def, substs) => {
11561159
Ok(adt_def.struct_variant().fields[field_index].ty(self.tcx, substs))
@@ -1166,7 +1169,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11661169
}
11671170
}
11681171

1169-
fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<Size> {
1172+
fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Size> {
11701173
let layout = self.type_layout(ty);
11711174

11721175
use rustc::ty::layout::Layout::*;
@@ -1183,7 +1186,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11831186
}
11841187
}
11851188

1186-
fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<Pointer> {
1189+
fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, Pointer> {
11871190
use rustc::mir::repr::Operand::*;
11881191
match *op {
11891192
Consume(ref lvalue) => Ok(self.eval_lvalue(lvalue)?.to_ptr()),
@@ -1217,7 +1220,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
12171220
}
12181221
}
12191222

1220-
fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<Lvalue> {
1223+
fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, Lvalue> {
12211224
use rustc::mir::repr::Lvalue::*;
12221225
let ptr = match *lvalue {
12231226
ReturnPointer => self.frame().return_ptr
@@ -1325,7 +1328,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
13251328
self.monomorphize(self.mir().operand_ty(self.tcx, operand), self.substs())
13261329
}
13271330

1328-
fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
1331+
fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, ()> {
13291332
let size = self.type_size(ty);
13301333
self.memory.copy(src, dest, size)?;
13311334
if self.type_needs_drop(ty) {
@@ -1334,7 +1337,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
13341337
Ok(())
13351338
}
13361339

1337-
pub fn read_primval(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<PrimVal> {
1340+
pub fn read_primval(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
13381341
use syntax::ast::{IntTy, UintTy};
13391342
let val = match (self.memory.pointer_size, &ty.sty) {
13401343
(_, &ty::TyBool) => PrimVal::Bool(self.memory.read_bool(ptr)?),

src/interpreter/stepper.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ impl<'ecx, 'a, 'tcx> Stepper<'ecx, 'a, 'tcx> {
2323
}
2424
}
2525

26-
fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<()> {
26+
fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx, ()> {
2727
trace!("{:?}", stmt);
2828
let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind;
2929
self.ecx.eval_assignment(lvalue, rvalue)?;
3030
self.ecx.frame_mut().stmt += 1;
3131
Ok(())
3232
}
3333

34-
fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<()> {
34+
fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx, ()> {
3535
// after a terminator we go to a new block
3636
self.ecx.frame_mut().stmt = 0;
3737
trace!("{:?}", terminator.kind);
@@ -43,7 +43,7 @@ impl<'ecx, 'a, 'tcx> Stepper<'ecx, 'a, 'tcx> {
4343
}
4444

4545
// returns true as long as there are more things to do
46-
pub(super) fn step(&mut self) -> EvalResult<bool> {
46+
pub(super) fn step(&mut self) -> EvalResult<'tcx, bool> {
4747
if self.ecx.stack.is_empty() {
4848
return Ok(false);
4949
}

0 commit comments

Comments
 (0)