layout computation can fail, make it fail with a miri error

上级 26ccc1e4
use std::error::Error;
use std::fmt;
use rustc::mir;
use rustc::ty::{BareFnTy, Ty, FnSig};
use rustc::ty::{BareFnTy, Ty, FnSig, layout};
use syntax::abi::Abi;
use memory::Pointer;
use rustc_const_math::ConstMathErr;
use syntax::codemap::Span;
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug)]
pub enum EvalError<'tcx> {
FunctionPointerTyMismatch(Abi, &'tcx FnSig<'tcx>, &'tcx BareFnTy<'tcx>),
NoMirFor(String),
......@@ -50,6 +50,7 @@ pub enum EvalError<'tcx> {
TypeNotPrimitive(Ty<'tcx>),
ReallocatedFrozenMemory,
DeallocatedFrozenMemory,
Layout(layout::LayoutError<'tcx>),
}
pub type EvalResult<'tcx, T> = Result<T, EvalError<'tcx>>;
......@@ -116,6 +117,8 @@ fn description(&self) -> &str {
"tried to reallocate frozen memory",
EvalError::DeallocatedFrozenMemory =>
"tried to deallocate frozen memory",
EvalError::Layout(_) =>
"rustc layout computation failed",
}
}
......@@ -146,6 +149,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
has, required),
EvalError::TypeNotPrimitive(ref ty) =>
write!(f, "expected primitive type, got {}", ty),
EvalError::Layout(ref err) =>
write!(f, "rustc layout computation failed: {:?}", err),
_ => write!(f, "{}", self.description()),
}
}
......
......@@ -188,8 +188,8 @@ pub fn alloc_ptr_with_substs(
ty: Ty<'tcx>,
substs: &'tcx Substs<'tcx>
) -> EvalResult<'tcx, Pointer> {
let size = self.type_size_with_substs(ty, substs).expect("cannot alloc memory for unsized type");
let align = self.type_align_with_substs(ty, substs);
let size = self.type_size_with_substs(ty, substs)?.expect("cannot alloc memory for unsized type");
let align = self.type_align_with_substs(ty, substs)?;
self.memory.allocate(size, align)
}
......@@ -292,38 +292,38 @@ pub fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx>
self.tcx.normalize_associated_type(&substituted)
}
fn type_size(&self, ty: Ty<'tcx>) -> Option<usize> {
fn type_size(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<usize>> {
self.type_size_with_substs(ty, self.substs())
}
fn type_align(&self, ty: Ty<'tcx>) -> usize {
fn type_align(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, usize> {
self.type_align_with_substs(ty, self.substs())
}
fn type_size_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Option<usize> {
let layout = self.type_layout_with_substs(ty, substs);
fn type_size_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, Option<usize>> {
let layout = self.type_layout_with_substs(ty, substs)?;
if layout.is_unsized() {
None
Ok(None)
} else {
Some(layout.size(&self.tcx.data_layout).bytes() as usize)
Ok(Some(layout.size(&self.tcx.data_layout).bytes() as usize))
}
}
fn type_align_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> usize {
self.type_layout_with_substs(ty, substs).align(&self.tcx.data_layout).abi() as usize
fn type_align_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, usize> {
self.type_layout_with_substs(ty, substs).map(|layout| layout.align(&self.tcx.data_layout).abi() as usize)
}
fn type_layout(&self, ty: Ty<'tcx>) -> &'tcx Layout {
fn type_layout(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, &'tcx Layout> {
self.type_layout_with_substs(ty, self.substs())
}
fn type_layout_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> &'tcx Layout {
fn type_layout_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, &'tcx Layout> {
// TODO(solson): Is this inefficient? Needs investigation.
let ty = self.monomorphize(ty, substs);
self.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
// TODO(solson): Report this error properly.
ty.layout(&infcx).unwrap()
ty.layout(&infcx).map_err(EvalError::Layout)
})
}
......@@ -482,7 +482,7 @@ fn eval_rvalue_into_lvalue(
) -> EvalResult<'tcx, ()> {
let dest = self.eval_lvalue(lvalue)?;
let dest_ty = self.lvalue_ty(lvalue);
let dest_layout = self.type_layout(dest_ty);
let dest_layout = self.type_layout(dest_ty)?;
use rustc::mir::Rvalue::*;
match *rvalue {
......@@ -516,7 +516,7 @@ fn eval_rvalue_into_lvalue(
Array { .. } => {
let elem_size = match dest_ty.sty {
ty::TyArray(elem_ty, _) => self.type_size(elem_ty).expect("array elements are sized") as u64,
ty::TyArray(elem_ty, _) => self.type_size(elem_ty)?.expect("array elements are sized") as u64,
_ => bug!("tried to assign {:?} to non-array type {:?}", kind, dest_ty),
};
let offsets = (0..).map(|i| i * elem_size);
......@@ -556,9 +556,9 @@ fn eval_rvalue_into_lvalue(
if let Some(operand) = operands.get(0) {
assert_eq!(operands.len(), 1);
let operand_ty = self.operand_ty(operand);
assert_eq!(self.type_size(operand_ty), Some(0));
assert_eq!(self.type_size(operand_ty)?, Some(0));
}
let value_size = self.type_size(dest_ty).expect("pointer types are sized");
let value_size = self.type_size(dest_ty)?.expect("pointer types are sized");
let zero = PrimVal::from_int_with_size(0, value_size);
self.write_primval(dest, zero)?;
}
......@@ -575,7 +575,7 @@ fn eval_rvalue_into_lvalue(
} else {
for operand in operands {
let operand_ty = self.operand_ty(operand);
assert_eq!(self.type_size(operand_ty), Some(0));
assert_eq!(self.type_size(operand_ty)?, Some(0));
}
let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
......@@ -583,7 +583,7 @@ fn eval_rvalue_into_lvalue(
let dest = self.force_allocation(dest)?.to_ptr();
let dest = dest.offset(offset.bytes() as isize);
let dest_size = self.type_size(ty).expect("bad StructWrappedNullablePointer discrfield");
let dest_size = self.type_size(ty)?.expect("bad StructWrappedNullablePointer discrfield");
try!(self.memory.write_int(dest, 0, dest_size));
}
} else {
......@@ -625,8 +625,8 @@ fn eval_rvalue_into_lvalue(
ty::TyArray(elem_ty, n) => (elem_ty, n),
_ => bug!("tried to assign array-repeat to non-array type {:?}", dest_ty),
};
let elem_size = self.type_size(elem_ty).expect("repeat element type must be sized");
self.inc_step_counter_and_check_limit(length as u64)?;
let elem_size = self.type_size(elem_ty)?.expect("repeat element type must be sized");
let value = self.eval_operand(operand)?;
// FIXME(solson)
......@@ -797,7 +797,7 @@ fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<
}
fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Size> {
let layout = self.type_layout(ty);
let layout = self.type_layout(ty)?;
use rustc::ty::layout::Layout::*;
match *layout {
......@@ -816,7 +816,7 @@ fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx,
}
fn get_field_count(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, usize> {
let layout = self.type_layout(ty);
let layout = self.type_layout(ty)?;
use rustc::ty::layout::Layout::*;
match *layout {
......@@ -944,7 +944,7 @@ fn eval_lvalue_projection(
) -> EvalResult<'tcx, Lvalue<'tcx>> {
let base = self.eval_lvalue(&proj.base)?;
let base_ty = self.lvalue_ty(&proj.base);
let base_layout = self.type_layout(base_ty);
let base_layout = self.type_layout(base_ty)?;
use rustc::mir::ProjectionElem::*;
let (ptr, extra) = match proj.elem {
......@@ -1043,7 +1043,7 @@ fn eval_lvalue_projection(
let (base_ptr, _) = base.to_ptr_and_extra();
let (elem_ty, len) = base.elem_ty_and_len(base_ty);
let elem_size = self.type_size(elem_ty).expect("slice element must be sized");
let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized");
let n_ptr = self.eval_operand(operand)?;
let usize = self.tcx.types.usize;
let n = self.value_to_primval(n_ptr, usize)?
......@@ -1059,7 +1059,7 @@ fn eval_lvalue_projection(
let (base_ptr, _) = base.to_ptr_and_extra();
let (elem_ty, n) = base.elem_ty_and_len(base_ty);
let elem_size = self.type_size(elem_ty).expect("sequence element must be sized");
let elem_size = self.type_size(elem_ty)?.expect("sequence element must be sized");
assert!(n >= min_length as u64);
let index = if from_end {
......@@ -1078,7 +1078,7 @@ fn eval_lvalue_projection(
let (base_ptr, _) = base.to_ptr_and_extra();
let (elem_ty, n) = base.elem_ty_and_len(base_ty);
let elem_size = self.type_size(elem_ty).expect("slice element must be sized");
let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized");
assert!((from as u64) <= n - (to as u64));
let ptr = base_ptr.offset(from as isize * elem_size as isize);
let extra = LvalueExtra::Length(n - to as u64 - from as u64);
......@@ -1098,8 +1098,8 @@ fn operand_ty(&self, operand: &mir::Operand<'tcx>) -> Ty<'tcx> {
}
fn copy(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, ()> {
let size = self.type_size(ty).expect("cannot copy from an unsized type");
let align = self.type_align(ty);
let size = self.type_size(ty)?.expect("cannot copy from an unsized type");
let align = self.type_align(ty)?;
self.memory.copy(src, dest, size, align)?;
Ok(())
}
......@@ -1368,7 +1368,7 @@ fn ty_to_primval_kind(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimValKind> {
ty::TyAdt(..) => {
use rustc::ty::layout::Layout::*;
if let CEnum { discr, signed, .. } = *self.type_layout(ty) {
if let CEnum { discr, signed, .. } = *self.type_layout(ty)? {
let size = discr.size().bytes() as usize;
if signed {
PrimValKind::from_int_size(size)
......@@ -1464,7 +1464,7 @@ fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value>
ty::TyAdt(..) => {
use rustc::ty::layout::Layout::*;
if let CEnum { discr, signed, .. } = *self.type_layout(ty) {
if let CEnum { discr, signed, .. } = *self.type_layout(ty)? {
let size = discr.size().bytes() as usize;
if signed {
let n = self.memory.read_int(ptr, size)?;
......@@ -1564,7 +1564,7 @@ fn unsize_into(
for (i, (src_f, dst_f)) in iter {
let src_fty = monomorphize_field_ty(self.tcx, src_f, substs_a);
let dst_fty = monomorphize_field_ty(self.tcx, dst_f, substs_b);
if self.type_size(dst_fty) == Some(0) {
if self.type_size(dst_fty)? == Some(0) {
continue;
}
let src_field_offset = self.get_field_offset(src_ty, i)?.bytes() as isize;
......
......@@ -144,8 +144,8 @@ pub(super) fn call_intrinsic(
"copy_nonoverlapping" => {
// FIXME: check whether overlapping occurs
let elem_ty = substs.type_at(0);
let elem_size = self.type_size(elem_ty).expect("cannot copy unsized value");
let elem_align = self.type_align(elem_ty);
let elem_size = self.type_size(elem_ty)?.expect("cannot copy unsized value");
let elem_align = self.type_align(elem_ty)?;
let src = arg_vals[0].read_ptr(&self.memory)?;
let dest = arg_vals[1].read_ptr(&self.memory)?;
let count = self.value_to_primval(arg_vals[2], usize)?
......@@ -252,14 +252,14 @@ pub(super) fn call_intrinsic(
"min_align_of" => {
let elem_ty = substs.type_at(0);
let elem_align = self.type_align(elem_ty);
let elem_align = self.type_align(elem_ty)?;
let align_val = self.usize_primval(elem_align as u64);
self.write_primval(dest, align_val)?;
}
"pref_align_of" => {
let ty = substs.type_at(0);
let layout = self.type_layout(ty);
let layout = self.type_layout(ty)?;
let align = layout.align(&self.tcx.data_layout).pref();
let align_val = self.usize_primval(align);
self.write_primval(dest, align_val)?;
......@@ -280,7 +280,7 @@ pub(super) fn call_intrinsic(
"offset" => {
let pointee_ty = substs.type_at(0);
let pointee_size = self.type_size(pointee_ty).expect("cannot offset a pointer to an unsized type") as isize;
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as isize;
let offset = self.value_to_primval(arg_vals[1], isize)?
.expect_int("offset second arg not isize");
......@@ -335,7 +335,7 @@ pub(super) fn call_intrinsic(
// `size_of_val` intrinsic, then change this back to
// .expect("size_of intrinsic called on unsized value")
// see https://github.com/rust-lang/rust/pull/37708
let size = self.type_size(ty).unwrap_or(!0) as u64;
let size = self.type_size(ty)?.unwrap_or(!0) as u64;
let size_val = self.usize_primval(size);
self.write_primval(dest, size_val)?;
}
......@@ -414,8 +414,8 @@ fn size_and_align_of_dst(
value: Value,
) -> EvalResult<'tcx, (u64, u64)> {
let pointer_size = self.memory.pointer_size();
if let Some(size) = self.type_size(ty) {
Ok((size as u64, self.type_align(ty) as u64))
if let Some(size) = self.type_size(ty)? {
Ok((size as u64, self.type_align(ty)? as u64))
} else {
match ty.sty {
ty::TyAdt(def, substs) => {
......@@ -424,7 +424,7 @@ fn size_and_align_of_dst(
// and it also rounds up to alignment, which we want to avoid,
// as the unsized field's alignment could be smaller.
assert!(!ty.is_simd());
let layout = self.type_layout(ty);
let layout = self.type_layout(ty)?;
debug!("DST {} layout: {:?}", ty, layout);
let (sized_size, sized_align) = match *layout {
......@@ -489,9 +489,9 @@ fn size_and_align_of_dst(
ty::TySlice(_) | ty::TyStr => {
let elem_ty = ty.sequence_element_type(self.tcx);
let elem_size = self.type_size(elem_ty).expect("slice element must be sized") as u64;
let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized") as u64;
let (_, len) = value.expect_slice(&self.memory)?;
let align = self.type_align(elem_ty);
let align = self.type_align(elem_ty)?;
Ok((len * elem_size, align as u64))
}
......
......@@ -183,7 +183,7 @@ fn eval_fn_call(
match fn_ty.abi {
Abi::RustIntrinsic => {
let ty = fn_ty.sig.0.output;
let layout = self.type_layout(ty);
let layout = self.type_layout(ty)?;
let (ret, target) = destination.unwrap();
self.call_intrinsic(def_id, substs, arg_operands, ret, ty, layout, target)?;
Ok(())
......@@ -191,7 +191,7 @@ fn eval_fn_call(
Abi::C => {
let ty = fn_ty.sig.0.output;
let size = self.type_size(ty).expect("function return type cannot be unsized");
let size = self.type_size(ty)?.expect("function return type cannot be unsized");
let (ret, target) = destination.unwrap();
self.call_c_abi(def_id, arg_operands, ret, size)?;
self.goto_block(target);
......@@ -248,7 +248,7 @@ fn eval_fn_call(
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);
let adt_layout = self.type_layout(adt_ty)?;
trace!("read_discriminant_value {:?}", adt_layout);
let discr_val = match *adt_layout {
......@@ -273,7 +273,7 @@ fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalRes
let nonnull = adt_ptr.offset(offset.bytes() as isize);
trace!("struct wrapped nullable pointer type: {}", ty);
// only the pointer part of a fat pointer is used for this space optimization
let discr_size = self.type_size(ty).expect("bad StructWrappedNullablePointer discrfield");
let discr_size = self.type_size(ty)?.expect("bad StructWrappedNullablePointer discrfield");
self.read_nonnull_discriminant_value(nonnull, nndiscr, discr_size)?
}
......@@ -402,9 +402,9 @@ pub(super) fn fulfill_obligation(&self, trait_ref: ty::PolyTraitRef<'tcx>) -> tr
})
}
fn unpack_fn_args(&self, args: &mut Vec<(Value, Ty<'tcx>)>) {
fn unpack_fn_args(&self, args: &mut Vec<(Value, Ty<'tcx>)>) -> EvalResult<'tcx, ()> {
if let Some((last, last_ty)) = args.pop() {
let last_layout = self.type_layout(last_ty);
let last_layout = self.type_layout(last_ty)?;
match (&last_ty.sty, last_layout) {
(&ty::TyTuple(fields),
&Layout::Univariant { ref variant, .. }) => {
......@@ -421,6 +421,7 @@ fn unpack_fn_args(&self, args: &mut Vec<(Value, Ty<'tcx>)>) {
ty => bug!("expected tuple as last argument in function with 'rust-call' ABI, got {:?}", ty),
}
}
Ok(())
}
/// Trait method, which has to be resolved to an impl method.
......@@ -452,7 +453,7 @@ fn trait_method(
.expect("The substitutions should have no type parameters remaining after passing through fulfill_obligation");
let closure_kind = self.tcx.closure_kind(vtable_closure.closure_def_id);
trace!("closures {:?}, {:?}", closure_kind, trait_closure_kind);
self.unpack_fn_args(args);
self.unpack_fn_args(args)?;
match (closure_kind, trait_closure_kind) {
(ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
(ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
......@@ -487,7 +488,7 @@ fn trait_method(
traits::VtableFnPointer(vtable_fn_ptr) => {
if let ty::TyFnDef(did, ref substs, _) = vtable_fn_ptr.fn_ty.sty {
args.remove(0);
self.unpack_fn_args(args);
self.unpack_fn_args(args)?;
Ok((did, substs))
} else {
bug!("VtableFnPointer did not contain a concrete function: {:?}", vtable_fn_ptr)
......@@ -583,7 +584,7 @@ pub fn drop(
if let Some(drop_def_id) = adt_def.destructor() {
drop.push((drop_def_id, Value::ByVal(PrimVal::from_ptr(adt_ptr)), substs));
}
let layout = self.type_layout(ty);
let layout = self.type_layout(ty)?;
let fields = match *layout {
Layout::Univariant { ref variant, .. } => {
adt_def.struct_variant().fields.iter().zip(&variant.offsets)
......@@ -630,7 +631,7 @@ pub fn drop(
)?;
},
ty::TyTuple(fields) => {
let offsets = match *self.type_layout(ty) {
let offsets = match *self.type_layout(ty)? {
Layout::Univariant { ref variant, .. } => &variant.offsets,
_ => bug!("tuples must be univariant"),
};
......@@ -658,7 +659,7 @@ pub fn drop(
Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len) } => (ptr, len as isize),
_ => bug!("expected an lvalue with a length"),
};
let size = self.type_size(elem_ty).expect("slice element must be sized") as isize;
let size = self.type_size(elem_ty)?.expect("slice element must be sized") as isize;
// FIXME: this creates a lot of stack frames if the element type has
// a drop impl
for i in 0..len {
......@@ -671,7 +672,7 @@ pub fn drop(
Lvalue::Ptr { ptr, extra } => (ptr, extra),
_ => bug!("expected an lvalue with optional extra data"),
};
let size = self.type_size(elem_ty).expect("array element cannot be unsized") as isize;
let size = self.type_size(elem_ty)?.expect("array element cannot be unsized") as isize;
// FIXME: this creates a lot of stack frames if the element type has
// a drop impl
for i in 0..len {
......
......@@ -80,8 +80,8 @@ pub fn get_vtable(&mut self, trait_ref: ty::PolyTraitRef<'tcx>) -> EvalResult<'t
}
}).collect();
let size = self.type_size(trait_ref.self_ty()).expect("can't create a vtable for an unsized type");
let align = self.type_align(trait_ref.self_ty());
let size = self.type_size(trait_ref.self_ty())?.expect("can't create a vtable for an unsized type");
let align = self.type_align(trait_ref.self_ty())?;
let ptr_size = self.memory.pointer_size();
let vtable = self.memory.allocate(ptr_size * (3 + methods.len()), ptr_size)?;
......
......@@ -212,7 +212,7 @@ pub fn reallocate(&mut self, ptr: Pointer, new_size: usize, align: usize) -> Eva
if ptr.points_to_zst() {
return self.allocate(new_size, align);
}
if self.get(ptr.alloc_id).map(|alloc| alloc.immutable) == Ok(true) {
if self.get(ptr.alloc_id).map(|alloc| alloc.immutable).ok() == Some(true) {
return Err(EvalError::ReallocatedFrozenMemory);
}
......@@ -245,7 +245,7 @@ pub fn deallocate(&mut self, ptr: Pointer) -> EvalResult<'tcx, ()> {
// TODO(solson): Report error about non-__rust_allocate'd pointer.
return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset)));
}
if self.get(ptr.alloc_id).map(|alloc| alloc.immutable) == Ok(true) {
if self.get(ptr.alloc_id).map(|alloc| alloc.immutable).ok() == Some(true) {
return Err(EvalError::DeallocatedFrozenMemory);
}
......
fn main() {
let data: [u8; std::isize::MAX as usize] = [42; std::isize::MAX as usize];
//~^ ERROR: rustc layout computation failed: SizeOverflow([u8;
assert_eq!(data.len(), 1024);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册