Skip to content

Commit 9322dec

Browse files
authored
Merge pull request rust-lang#81 from oli-obk/master
ensure that integers cast to pointers will never point at a valid alloc, not even the zst alloc
2 parents 2d4301e + fd68670 commit 9322dec

22 files changed

+559
-219
lines changed

src/error.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use std::error::Error;
22
use std::fmt;
33
use rustc::mir;
4-
use rustc::ty::{BareFnTy, Ty};
4+
use rustc::ty::{BareFnTy, Ty, FnSig};
5+
use syntax::abi::Abi;
56
use memory::Pointer;
67
use rustc_const_math::ConstMathErr;
78
use syntax::codemap::Span;
89

910
#[derive(Clone, Debug)]
1011
pub enum EvalError<'tcx> {
11-
FunctionPointerTyMismatch(&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>),
12+
FunctionPointerTyMismatch(Abi, &'tcx FnSig<'tcx>, &'tcx BareFnTy<'tcx>),
1213
NoMirFor(String),
1314
DanglingPointerDeref,
1415
InvalidMemoryAccess,
@@ -61,7 +62,7 @@ impl<'tcx> Error for EvalError<'tcx> {
6162
EvalError::DanglingPointerDeref =>
6263
"dangling pointer was dereferenced",
6364
EvalError::InvalidFunctionPointer =>
64-
"tried to use a pointer as a function pointer",
65+
"tried to use an integer pointer or a dangling pointer as a function pointer",
6566
EvalError::InvalidBool =>
6667
"invalid boolean value read",
6768
EvalError::InvalidDiscriminant =>
@@ -123,8 +124,8 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
123124
ptr.offset, ptr.offset + size, ptr.alloc_id, allocation_size)
124125
},
125126
EvalError::NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
126-
EvalError::FunctionPointerTyMismatch(expected, got) =>
127-
write!(f, "tried to call a function of type {:?} through a function pointer of type {:?}", expected, got),
127+
EvalError::FunctionPointerTyMismatch(abi, sig, got) =>
128+
write!(f, "tried to call a function with abi {:?} and sig {:?} through a function pointer of type {:?}", abi, sig, got),
128129
EvalError::ArrayIndexOutOfBounds(span, len, index) =>
129130
write!(f, "index out of bounds: the len is {} but the index is {} at {:?}", len, index, span),
130131
EvalError::Math(span, ref err) =>

src/interpreter/cast.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
2121

2222
Bool | Char | U8 | U16 | U32 | U64 => self.cast_int(val.bits, ty, false),
2323

24-
FnPtr | Ptr => {
25-
let ptr = val.expect_ptr("FnPtr- or Ptr-tagged PrimVal had no relocation");
26-
self.cast_ptr(ptr, ty)
27-
}
24+
FnPtr | Ptr => self.cast_ptr(val.to_ptr(), ty),
2825
}
2926
}
3027

src/interpreter/mod.rs

Lines changed: 70 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
182182
ty: Ty<'tcx>,
183183
substs: &'tcx Substs<'tcx>
184184
) -> EvalResult<'tcx, Pointer> {
185-
let size = self.type_size_with_substs(ty, substs);
185+
let size = self.type_size_with_substs(ty, substs).expect("cannot alloc memory for unsized type");
186186
let align = self.type_align_with_substs(ty, substs);
187187
self.memory.allocate(size, align)
188188
}
@@ -203,10 +203,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
203203
PrimVal::from_uint_with_size(n, self.memory.pointer_size())
204204
}
205205

206-
fn isize_primval(&self, n: i64) -> PrimVal {
207-
PrimVal::from_int_with_size(n, self.memory.pointer_size())
208-
}
209-
210206
fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
211207
// FIXME: cache these allocs
212208
let ptr = self.memory.allocate(s.len(), 1)?;
@@ -290,16 +286,21 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
290286
self.tcx.normalize_associated_type(&substituted)
291287
}
292288

293-
fn type_size(&self, ty: Ty<'tcx>) -> usize {
289+
fn type_size(&self, ty: Ty<'tcx>) -> Option<usize> {
294290
self.type_size_with_substs(ty, self.substs())
295291
}
296292

297293
fn type_align(&self, ty: Ty<'tcx>) -> usize {
298294
self.type_align_with_substs(ty, self.substs())
299295
}
300296

301-
fn type_size_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> usize {
302-
self.type_layout_with_substs(ty, substs).size(&self.tcx.data_layout).bytes() as usize
297+
fn type_size_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Option<usize> {
298+
let layout = self.type_layout_with_substs(ty, substs);
299+
if layout.is_unsized() {
300+
None
301+
} else {
302+
Some(layout.size(&self.tcx.data_layout).bytes() as usize)
303+
}
303304
}
304305

305306
fn type_align_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> usize {
@@ -480,7 +481,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
480481

481482
Array { .. } => {
482483
let elem_size = match dest_ty.sty {
483-
ty::TyArray(elem_ty, _) => self.type_size(elem_ty) as u64,
484+
ty::TyArray(elem_ty, _) => self.type_size(elem_ty).expect("array elements are sized") as u64,
484485
_ => bug!("tried to assign {:?} to non-array type {:?}", kind, dest_ty),
485486
};
486487
let offsets = (0..).map(|i| i * elem_size);
@@ -517,8 +518,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
517518
let value_ty = self.operand_ty(operand);
518519
self.write_value(value, dest, value_ty)?;
519520
} else {
520-
assert_eq!(operands.len(), 0);
521-
let zero = self.isize_primval(0);
521+
if let Some(operand) = operands.get(0) {
522+
assert_eq!(operands.len(), 1);
523+
let operand_ty = self.operand_ty(operand);
524+
assert_eq!(self.type_size(operand_ty), Some(0));
525+
}
526+
let value_size = self.type_size(dest_ty).expect("pointer types are sized");
527+
let zero = PrimVal::from_int_with_size(0, value_size);
522528
self.write_primval(dest, zero)?;
523529
}
524530
} else {
@@ -534,15 +540,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
534540
} else {
535541
for operand in operands {
536542
let operand_ty = self.operand_ty(operand);
537-
assert_eq!(self.type_size(operand_ty), 0);
543+
assert_eq!(self.type_size(operand_ty), Some(0));
538544
}
539-
let offset = self.nonnull_offset(dest_ty, nndiscr, discrfield)?;
545+
let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
540546

541547
// FIXME(solson)
542548
let dest = self.force_allocation(dest)?.to_ptr();
543549

544550
let dest = dest.offset(offset.bytes() as isize);
545-
try!(self.memory.write_isize(dest, 0));
551+
let dest_size = self.type_size(ty).expect("bad StructWrappedNullablePointer discrfield");
552+
try!(self.memory.write_int(dest, 0, dest_size));
546553
}
547554
} else {
548555
bug!("tried to assign {:?} to Layout::RawNullablePointer", kind);
@@ -567,6 +574,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
567574
}
568575
}
569576

577+
Vector { element, count } => {
578+
let elem_size = element.size(&self.tcx.data_layout).bytes();
579+
debug_assert_eq!(count, operands.len() as u64);
580+
let offsets = (0..).map(|i| i * elem_size);
581+
self.assign_fields(dest, offsets, operands)?;
582+
}
583+
570584
_ => return Err(EvalError::Unimplemented(format!("can't handle destination layout {:?} when assigning {:?}", dest_layout, kind))),
571585
}
572586
}
@@ -576,7 +590,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
576590
ty::TyArray(elem_ty, n) => (elem_ty, n),
577591
_ => bug!("tried to assign array-repeat to non-array type {:?}", dest_ty),
578592
};
579-
let elem_size = self.type_size(elem_ty);
593+
let elem_size = self.type_size(elem_ty).expect("repeat element type must be sized");
580594
let value = self.eval_operand(operand)?;
581595

582596
// FIXME(solson)
@@ -651,7 +665,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
651665

652666
ReifyFnPointer => match self.operand_ty(operand).sty {
653667
ty::TyFnDef(def_id, substs, fn_ty) => {
654-
let fn_ptr = self.memory.create_fn_ptr(def_id, substs, fn_ty);
668+
let fn_ty = self.tcx.erase_regions(&fn_ty);
669+
let fn_ptr = self.memory.create_fn_ptr(self.tcx,def_id, substs, fn_ty);
655670
self.write_value(Value::ByVal(PrimVal::from_fn_ptr(fn_ptr)), dest, dest_ty)?;
656671
},
657672
ref other => bug!("reify fn pointer on {:?}", other),
@@ -661,8 +676,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
661676
ty::TyFnPtr(unsafe_fn_ty) => {
662677
let src = self.eval_operand(operand)?;
663678
let ptr = src.read_ptr(&self.memory)?;
664-
let (def_id, substs, _) = self.memory.get_fn(ptr.alloc_id)?;
665-
let fn_ptr = self.memory.create_fn_ptr(def_id, substs, unsafe_fn_ty);
679+
let (def_id, substs, _, _) = self.memory.get_fn(ptr.alloc_id)?;
680+
let unsafe_fn_ty = self.tcx.erase_regions(&unsafe_fn_ty);
681+
let fn_ptr = self.memory.create_fn_ptr(self.tcx, def_id, substs, unsafe_fn_ty);
666682
self.write_value(Value::ByVal(PrimVal::from_fn_ptr(fn_ptr)), dest, dest_ty)?;
667683
},
668684
ref other => bug!("fn to unsafe fn cast on {:?}", other),
@@ -689,7 +705,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
689705
}
690706
}
691707

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

@@ -704,10 +720,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
704720
_ => bug!("non-enum for StructWrappedNullablePointer: {}", ty),
705721
};
706722

707-
self.field_path_offset(inner_ty, path)
723+
self.field_path_offset_and_ty(inner_ty, path)
708724
}
709725

710-
fn field_path_offset<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<'tcx, Size> {
726+
fn field_path_offset_and_ty<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
711727
let mut offset = Size::from_bytes(0);
712728

713729
// Skip the initial 0 intended for LLVM GEP.
@@ -717,7 +733,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
717733
offset = offset.checked_add(field_offset, &self.tcx.data_layout).unwrap();
718734
}
719735

720-
Ok(offset)
736+
Ok((offset, ty))
721737
}
722738

723739
fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> {
@@ -731,8 +747,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
731747
ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
732748
ty::TyRawPtr(ty::TypeAndMut { ty, .. }) |
733749
ty::TyBox(ty) => {
734-
assert_eq!(field_index, 0);
735-
Ok(ty)
750+
match (field_index, &self.tcx.struct_tail(ty).sty) {
751+
(1, &ty::TyStr) |
752+
(1, &ty::TySlice(_)) => Ok(self.tcx.types.usize),
753+
(1, &ty::TyTrait(_)) |
754+
(0, _) => Ok(self.tcx.mk_imm_ptr(self.tcx.types.u8)),
755+
_ => bug!("invalid fat pointee type: {}", ty),
756+
}
736757
}
737758
_ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}, {:?}", ty, ty.sty))),
738759
}
@@ -955,33 +976,27 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
955976
}
956977

957978
Deref => {
958-
use interpreter::value::Value::*;
979+
let val = self.eval_and_read_lvalue(&proj.base)?;
959980

960-
let val = match self.eval_and_read_lvalue(&proj.base)? {
961-
ByRef(ptr) => self.read_value(ptr, base_ty)?,
962-
v => v,
981+
let pointee_type = match base_ty.sty {
982+
ty::TyRawPtr(ty::TypeAndMut{ty, ..}) |
983+
ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
984+
ty::TyBox(ty) => ty,
985+
_ => bug!("can only deref pointer types"),
963986
};
964987

965-
match val {
966-
ByValPair(ptr, vtable)
967-
if ptr.try_as_ptr().is_some() && vtable.try_as_ptr().is_some()
968-
=> {
969-
let ptr = ptr.try_as_ptr().unwrap();
970-
let vtable = vtable.try_as_ptr().unwrap();
971-
(ptr, LvalueExtra::Vtable(vtable))
972-
}
973-
974-
ByValPair(ptr, n) if ptr.try_as_ptr().is_some() => {
975-
let ptr = ptr.try_as_ptr().unwrap();
976-
(ptr, LvalueExtra::Length(n.expect_uint("slice length")))
977-
}
988+
trace!("deref to {} on {:?}", pointee_type, val);
978989

979-
ByVal(ptr) if ptr.try_as_ptr().is_some() => {
980-
let ptr = ptr.try_as_ptr().unwrap();
981-
(ptr, LvalueExtra::None)
982-
}
983-
984-
_ => bug!("can't deref non pointer types"),
990+
match self.tcx.struct_tail(pointee_type).sty {
991+
ty::TyTrait(_) => {
992+
let (ptr, vtable) = val.expect_ptr_vtable_pair(&self.memory)?;
993+
(ptr, LvalueExtra::Vtable(vtable))
994+
},
995+
ty::TyStr | ty::TySlice(_) => {
996+
let (ptr, len) = val.expect_slice(&self.memory)?;
997+
(ptr, LvalueExtra::Length(len))
998+
},
999+
_ => (val.read_ptr(&self.memory)?, LvalueExtra::None),
9851000
}
9861001
}
9871002

@@ -991,7 +1006,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
9911006
let (base_ptr, _) = base.to_ptr_and_extra();
9921007

9931008
let (elem_ty, len) = base.elem_ty_and_len(base_ty);
994-
let elem_size = self.type_size(elem_ty);
1009+
let elem_size = self.type_size(elem_ty).expect("slice element must be sized");
9951010
let n_ptr = self.eval_operand(operand)?;
9961011
let usize = self.tcx.types.usize;
9971012
let n = self.value_to_primval(n_ptr, usize)?
@@ -1007,7 +1022,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
10071022
let (base_ptr, _) = base.to_ptr_and_extra();
10081023

10091024
let (elem_ty, n) = base.elem_ty_and_len(base_ty);
1010-
let elem_size = self.type_size(elem_ty);
1025+
let elem_size = self.type_size(elem_ty).expect("sequence element must be sized");
10111026
assert!(n >= min_length as u64);
10121027

10131028
let index = if from_end {
@@ -1026,7 +1041,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
10261041
let (base_ptr, _) = base.to_ptr_and_extra();
10271042

10281043
let (elem_ty, n) = base.elem_ty_and_len(base_ty);
1029-
let elem_size = self.type_size(elem_ty);
1044+
let elem_size = self.type_size(elem_ty).expect("slice element must be sized");
10301045
assert!((from as u64) <= n - (to as u64));
10311046
let ptr = base_ptr.offset(from as isize * elem_size as isize);
10321047
let extra = LvalueExtra::Length(n - to as u64 - from as u64);
@@ -1046,7 +1061,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
10461061
}
10471062

10481063
fn copy(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, ()> {
1049-
let size = self.type_size(ty);
1064+
let size = self.type_size(ty).expect("cannot copy from an unsized type");
10501065
let align = self.type_align(ty);
10511066
self.memory.copy(src, dest, size, align)?;
10521067
Ok(())
@@ -1388,7 +1403,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
13881403
ty::TyFloat(FloatTy::F64) => PrimVal::from_f64(self.memory.read_f64(ptr)?),
13891404

13901405
ty::TyFnDef(def_id, substs, fn_ty) => {
1391-
PrimVal::from_fn_ptr(self.memory.create_fn_ptr(def_id, substs, fn_ty))
1406+
PrimVal::from_fn_ptr(self.memory.create_fn_ptr(self.tcx, def_id, substs, fn_ty))
13921407
},
13931408
ty::TyFnPtr(_) => self.memory.read_ptr(ptr).map(PrimVal::from_fn_ptr)?,
13941409
ty::TyBox(ty) |
@@ -1398,7 +1413,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
13981413
if self.type_is_sized(ty) {
13991414
PrimVal::from_ptr(p)
14001415
} else {
1401-
// FIXME: extract the offset to the tail field for `Box<(i64, i32, [u8])>`
1416+
trace!("reading fat pointer extra of type {}", ty);
14021417
let extra = ptr.offset(self.memory.pointer_size() as isize);
14031418
let extra = match self.tcx.struct_tail(ty).sty {
14041419
ty::TyTrait(..) => PrimVal::from_ptr(self.memory.read_ptr(extra)?),
@@ -1505,14 +1520,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
15051520
//let dst = adt::MaybeSizedValue::sized(dst);
15061521
let src_ptr = match src {
15071522
Value::ByRef(ptr) => ptr,
1508-
_ => panic!("expected pointer, got {:?}", src),
1523+
_ => bug!("expected pointer, got {:?}", src),
15091524
};
15101525

15111526
let iter = src_fields.zip(dst_fields).enumerate();
15121527
for (i, (src_f, dst_f)) in iter {
15131528
let src_fty = monomorphize_field_ty(self.tcx, src_f, substs_a);
15141529
let dst_fty = monomorphize_field_ty(self.tcx, dst_f, substs_b);
1515-
if self.type_size(dst_fty) == 0 {
1530+
if self.type_size(dst_fty) == Some(0) {
15161531
continue;
15171532
}
15181533
let src_field_offset = self.get_field_offset(src_ty, i)?.bytes() as isize;

0 commit comments

Comments
 (0)