use std::hash::Hash;
use super::{
- GlobalAlloc, InterpResult, InterpError,
- OpTy, Machine, InterpCx, ValueVisitor, MPlaceTy, UnsupportedInfo::*,
+ GlobalAlloc, InterpResult,
+ Scalar, OpTy, Machine, InterpCx, ValueVisitor, MPlaceTy,
};
-macro_rules! validation_failure {
+macro_rules! throw_validation_failure {
($what:expr, $where:expr, $details:expr) => {{
let where_ = path_format(&$where);
let where_ = if where_.is_empty() {
} else {
format!(" at {}", where_)
};
- err!(ValidationFailure(format!(
+ throw_unsup!(ValidationFailure(format!(
"encountered {}{}, but expected {}",
$what, where_, $details,
)))
} else {
format!(" at {}", where_)
};
- err!(ValidationFailure(format!(
+ throw_unsup!(ValidationFailure(format!(
"encountered {}{}",
$what, where_,
)))
($e:expr, $what:expr, $where:expr, $details:expr) => {{
match $e {
Ok(x) => x,
- Err(_) => return validation_failure!($what, $where, $details),
+ Err(_) => throw_validation_failure!($what, $where, $details),
}
}};
($e:expr, $what:expr, $where:expr) => {{
match $e {
Ok(x) => x,
- Err(_) => return validation_failure!($what, $where),
+ Err(_) => throw_validation_failure!($what, $where),
}
}}
}
self.path.truncate(path_len);
Ok(())
}
+
+ fn check_wide_ptr_meta(
+ &mut self,
+ meta: Option<Scalar<M::PointerTag>>,
+ pointee: TyLayout<'tcx>,
+ ) -> InterpResult<'tcx> {
+ let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env);
+ match tail.sty {
+ ty::Dynamic(..) => {
+ let vtable = meta.unwrap();
+ try_validation!(
+ self.ecx.memory.check_ptr_access(
+ vtable,
+ 3*self.ecx.tcx.data_layout.pointer_size, // drop, size, align
+ self.ecx.tcx.data_layout.pointer_align.abi,
+ ),
+ "dangling or unaligned vtable pointer in wide pointer or too small vtable",
+ self.path
+ );
+ try_validation!(self.ecx.read_drop_type_from_vtable(vtable),
+ "invalid drop fn in vtable", self.path);
+ try_validation!(self.ecx.read_size_and_align_from_vtable(vtable),
+ "invalid size or align in vtable", self.path);
+ // FIXME: More checks for the vtable.
+ }
+ ty::Slice(..) | ty::Str => {
+ try_validation!(meta.unwrap().to_usize(self.ecx),
+ "non-integer slice length in wide pointer", self.path);
+ }
+ ty::Foreign(..) => {
+ // Unsized, but not wide.
+ }
+ _ =>
+ bug!("Unexpected unsized type tail: {:?}", tail),
+ }
+
+ Ok(())
+ }
}
impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
match self.walk_value(op) {
Ok(()) => Ok(()),
Err(err) => match err.kind {
- InterpError::Unsupported(InvalidDiscriminant(val)) =>
- validation_failure!(
+ err_unsup!(InvalidDiscriminant(val)) =>
+ throw_validation_failure!(
val, self.path, "a valid enum discriminant"
),
- InterpError::Unsupported(ReadPointerAsBytes) =>
- validation_failure!(
+ err_unsup!(ReadPointerAsBytes) =>
+ throw_validation_failure!(
"a pointer", self.path, "plain (non-pointer) bytes"
),
_ => Err(err),
}
}
_ if ty.is_box() || ty.is_region_ptr() => {
- // Handle fat pointers.
+ // Handle wide pointers.
// Check metadata early, for better diagnostics
let ptr = try_validation!(value.to_scalar_ptr(),
"undefined address in pointer", self.path);
let meta = try_validation!(value.to_meta(),
- "uninitialized data in fat pointer metadata", self.path);
+ "uninitialized data in wide pointer metadata", self.path);
let layout = self.ecx.layout_of(value.layout.ty.builtin_deref(true).unwrap().ty)?;
if layout.is_unsized() {
- let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(layout.ty,
- self.ecx.param_env);
- match tail.sty {
- ty::Dynamic(..) => {
- let vtable = meta.unwrap();
- try_validation!(
- self.ecx.memory.check_ptr_access(
- vtable,
- 3*self.ecx.tcx.data_layout.pointer_size, // drop, size, align
- self.ecx.tcx.data_layout.pointer_align.abi,
- ),
- "dangling or unaligned vtable pointer or too small vtable",
- self.path
- );
- try_validation!(self.ecx.read_drop_type_from_vtable(vtable),
- "invalid drop fn in vtable", self.path);
- try_validation!(self.ecx.read_size_and_align_from_vtable(vtable),
- "invalid size or align in vtable", self.path);
- // FIXME: More checks for the vtable.
- }
- ty::Slice(..) | ty::Str => {
- try_validation!(meta.unwrap().to_usize(self.ecx),
- "non-integer slice length in fat pointer", self.path);
- }
- ty::Foreign(..) => {
- // Unsized, but not fat.
- }
- _ =>
- bug!("Unexpected unsized type tail: {:?}", tail),
- }
+ self.check_wide_ptr_meta(meta, layout)?;
}
// Make sure this is dereferencable and all.
let (size, align) = self.ecx.size_and_align_of(meta, layout)?
// alignment and size determined by the layout (size will be 0,
// alignment should take attributes into account).
.unwrap_or_else(|| (layout.size, layout.align.abi));
- let ptr: Option<_> = match self.ecx.memory.check_ptr_access(ptr, size, align) {
+ let ptr: Option<_> = match
+ self.ecx.memory.check_ptr_access_align(ptr, size, Some(align))
+ {
Ok(ptr) => ptr,
Err(err) => {
info!(
ptr, size, align
);
match err.kind {
- InterpError::Unsupported(InvalidNullPointerUsage) =>
- return validation_failure!("NULL reference", self.path),
- InterpError::Unsupported(AlignmentCheckFailed { required, has }) =>
- return validation_failure!(format!("unaligned reference \
+ err_unsup!(InvalidNullPointerUsage) =>
+ throw_validation_failure!("NULL reference", self.path),
+ err_unsup!(AlignmentCheckFailed { required, has }) =>
+ throw_validation_failure!(format!("unaligned reference \
(required {} byte alignment but found {})",
required.bytes(), has.bytes()), self.path),
- InterpError::Unsupported(ReadBytesAsPointer) =>
- return validation_failure!(
+ err_unsup!(ReadBytesAsPointer) =>
+ throw_validation_failure!(
"dangling reference (created from integer)",
self.path
),
_ =>
- return validation_failure!(
+ throw_validation_failure!(
"dangling reference (not entirely in bounds)",
self.path
),
fn visit_uninhabited(&mut self) -> InterpResult<'tcx>
{
- validation_failure!("a value of an uninhabited type", self.path)
+ throw_validation_failure!("a value of an uninhabited type", self.path)
}
fn visit_scalar(
if lo == 1 && hi == max_hi {
// Only NULL is the niche. So make sure the ptr is NOT NULL.
if self.ecx.memory.ptr_may_be_null(ptr) {
- return validation_failure!(
+ throw_validation_failure!(
"a potentially NULL pointer",
self.path,
format!(
"something that cannot possibly fail to be {}",
wrapping_range_format(&layout.valid_range, max_hi)
)
- );
+ )
}
return Ok(());
} else {
// Conservatively, we reject, because the pointer *could* have a bad
// value.
- return validation_failure!(
+ throw_validation_failure!(
"a pointer",
self.path,
format!(
"something that cannot possibly fail to be {}",
wrapping_range_format(&layout.valid_range, max_hi)
)
- );
+ )
}
}
Ok(data) =>
if wrapping_range_contains(&layout.valid_range, bits) {
Ok(())
} else {
- validation_failure!(
+ throw_validation_failure!(
bits,
self.path,
format!("something {}", wrapping_range_format(&layout.valid_range, max_hi))
Err(err) => {
// For some errors we might be able to provide extra information
match err.kind {
- InterpError::Unsupported(ReadUndefBytes(offset)) => {
+ err_unsup!(ReadUndefBytes(offset)) => {
// Some byte was undefined, determine which
// element that byte belongs to so we can
// provide an index.
let i = (offset.bytes() / ty_size.bytes()) as usize;
self.path.push(PathElem::ArrayElem(i));
- return validation_failure!(
- "undefined bytes", self.path
- )
+ throw_validation_failure!("undefined bytes", self.path)
},
// Other errors shouldn't be possible
_ => return Err(err),