Skip to content

Commit c36dcff

Browse files
committed
forbid calling functions through pointers of a different type
1 parent 55fd060 commit c36dcff

File tree

6 files changed

+100
-70
lines changed

6 files changed

+100
-70
lines changed

src/error.rs

Lines changed: 10 additions & 4 deletions
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

Lines changed: 26 additions & 23 deletions
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

@@ -159,7 +159,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
159159
}
160160

161161
// TODO(solson): Try making const_to_primval instead.
162-
fn const_to_ptr(&mut self, const_val: &const_val::ConstVal) -> EvalResult<Pointer> {
162+
fn const_to_ptr(&mut self, const_val: &const_val::ConstVal) -> EvalResult<'tcx, Pointer> {
163163
use rustc::middle::const_val::ConstVal::*;
164164
match *const_val {
165165
Float(_f) => unimplemented!(),
@@ -368,7 +368,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
368368
}
369369

370370
fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>)
371-
-> EvalResult<()> {
371+
-> EvalResult<'tcx, ()> {
372372
use rustc::mir::repr::TerminatorKind::*;
373373
match terminator.kind {
374374
Return => self.pop_stack_frame(),
@@ -434,7 +434,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
434434
let ptr = self.eval_operand(func)?;
435435
assert_eq!(ptr.offset, 0);
436436
let fn_ptr = self.memory.read_ptr(ptr)?;
437-
let (def_id, substs) = self.memory.get_fn(fn_ptr.alloc_id)?;
437+
let FunctionDefinition { def_id, substs, fn_ty } = self.memory.get_fn(fn_ptr.alloc_id)?;
438+
if fn_ty != bare_fn_ty {
439+
return Err(EvalError::FunctionPointerTyMismatch(fn_ty, bare_fn_ty));
440+
}
438441
self.eval_fn_call(def_id, substs, bare_fn_ty, return_ptr, args,
439442
terminator.source_info.span)?
440443
},
@@ -480,7 +483,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
480483
return_ptr: Option<Pointer>,
481484
args: &[mir::Operand<'tcx>],
482485
span: Span,
483-
) -> EvalResult<()> {
486+
) -> EvalResult<'tcx, ()> {
484487
use syntax::abi::Abi;
485488
match fn_ty.abi {
486489
Abi::RustIntrinsic => {
@@ -559,7 +562,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
559562
}
560563
}
561564

562-
fn drop(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
565+
fn drop(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, ()> {
563566
if !self.type_needs_drop(ty) {
564567
debug!("no need to drop {:?}", ty);
565568
return Ok(());
@@ -601,7 +604,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
601604
Ok(())
602605
}
603606

604-
fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<u64> {
607+
fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u64> {
605608
use rustc::ty::layout::Layout::*;
606609
let adt_layout = self.type_layout(adt_ty);
607610

@@ -629,7 +632,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
629632
Ok(discr_val)
630633
}
631634

632-
fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u64) -> EvalResult<u64> {
635+
fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u64) -> EvalResult<'tcx, u64> {
633636
let not_null = match self.memory.read_usize(ptr) {
634637
Ok(0) => false,
635638
Ok(_) | Err(EvalError::ReadPointerAsBytes) => true,
@@ -646,7 +649,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
646649
args: &[mir::Operand<'tcx>],
647650
dest: Pointer,
648651
dest_size: usize
649-
) -> EvalResult<()> {
652+
) -> EvalResult<'tcx, ()> {
650653
let args_res: EvalResult<Vec<Pointer>> = args.iter()
651654
.map(|arg| self.eval_operand(arg))
652655
.collect();
@@ -792,7 +795,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
792795
args: &[mir::Operand<'tcx>],
793796
dest: Pointer,
794797
dest_size: usize,
795-
) -> EvalResult<()> {
798+
) -> EvalResult<'tcx, ()> {
796799
let name = self.tcx.item_name(def_id);
797800
let attrs = self.tcx.get_attrs(def_id);
798801
let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") {
@@ -855,7 +858,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
855858
dest: Pointer,
856859
offsets: I,
857860
operands: &[mir::Operand<'tcx>],
858-
) -> EvalResult<()> {
861+
) -> EvalResult<'tcx, ()> {
859862
for (offset, operand) in offsets.into_iter().zip(operands) {
860863
let src = self.eval_operand(operand)?;
861864
let src_ty = self.operand_ty(operand);
@@ -866,7 +869,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
866869
}
867870

868871
fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<'tcx>)
869-
-> EvalResult<()>
872+
-> EvalResult<'tcx, ()>
870873
{
871874
let dest = self.eval_lvalue(lvalue)?.to_ptr();
872875
let dest_ty = self.lvalue_ty(lvalue);
@@ -1095,8 +1098,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
10951098
}
10961099

10971100
ReifyFnPointer => match self.operand_ty(operand).sty {
1098-
ty::TyFnDef(def_id, substs, _) => {
1099-
let fn_ptr = self.memory.create_fn_ptr(def_id, substs);
1101+
ty::TyFnDef(def_id, substs, fn_ty) => {
1102+
let fn_ptr = self.memory.create_fn_ptr(def_id, substs, fn_ty);
11001103
self.memory.write_ptr(dest, fn_ptr)?;
11011104
},
11021105
ref other => panic!("reify fn pointer on {:?}", other),
@@ -1112,7 +1115,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11121115
Ok(())
11131116
}
11141117

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

@@ -1133,7 +1136,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11331136
self.field_path_offset(inner_ty, path)
11341137
}
11351138

1136-
fn field_path_offset<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<Size> {
1139+
fn field_path_offset<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<'tcx, Size> {
11371140
let mut offset = Size::from_bytes(0);
11381141

11391142
// Skip the initial 0 intended for LLVM GEP.
@@ -1146,7 +1149,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11461149
Ok(offset)
11471150
}
11481151

1149-
fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<Ty<'tcx>> {
1152+
fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> {
11501153
match ty.sty {
11511154
ty::TyStruct(adt_def, substs) => {
11521155
Ok(adt_def.struct_variant().fields[field_index].ty(self.tcx, substs))
@@ -1162,7 +1165,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11621165
}
11631166
}
11641167

1165-
fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<Size> {
1168+
fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Size> {
11661169
let layout = self.type_layout(ty);
11671170

11681171
use rustc::ty::layout::Layout::*;
@@ -1179,7 +1182,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11791182
}
11801183
}
11811184

1182-
fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<Pointer> {
1185+
fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, Pointer> {
11831186
use rustc::mir::repr::Operand::*;
11841187
match *op {
11851188
Consume(ref lvalue) => Ok(self.eval_lvalue(lvalue)?.to_ptr()),
@@ -1213,7 +1216,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
12131216
}
12141217
}
12151218

1216-
fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<Lvalue> {
1219+
fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, Lvalue> {
12171220
use rustc::mir::repr::Lvalue::*;
12181221
let ptr = match *lvalue {
12191222
ReturnPointer => self.frame().return_ptr
@@ -1321,7 +1324,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
13211324
self.monomorphize(self.mir().operand_ty(self.tcx, operand), self.substs())
13221325
}
13231326

1324-
fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
1327+
fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, ()> {
13251328
let size = self.type_size(ty);
13261329
self.memory.copy(src, dest, size)?;
13271330
if self.type_needs_drop(ty) {
@@ -1330,7 +1333,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
13301333
Ok(())
13311334
}
13321335

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

src/interpreter/stepper.rs

Lines changed: 3 additions & 3 deletions
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)