rust/miri/helpers.rs
2017-12-06 15:03:24 +01:00

71 lines
2.5 KiB
Rust

use rustc::mir::interpret::{Pointer, EvalResult, PrimVal, EvalContext};
use rustc::ty::Ty;
use rustc::ty::layout::LayoutOf;
pub trait EvalContextExt<'tcx> {
fn wrapping_pointer_offset(
&self,
ptr: Pointer,
pointee_ty: Ty<'tcx>,
offset: i64,
) -> EvalResult<'tcx, Pointer>;
fn pointer_offset(
&self,
ptr: Pointer,
pointee_ty: Ty<'tcx>,
offset: i64,
) -> EvalResult<'tcx, Pointer>;
}
impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> {
fn wrapping_pointer_offset(
&self,
ptr: Pointer,
pointee_ty: Ty<'tcx>,
offset: i64,
) -> EvalResult<'tcx, Pointer> {
// FIXME: assuming here that type size is < i64::max_value()
let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64;
let offset = offset.overflowing_mul(pointee_size).0;
ptr.wrapping_signed_offset(offset, self)
}
fn pointer_offset(
&self,
ptr: Pointer,
pointee_ty: Ty<'tcx>,
offset: i64,
) -> EvalResult<'tcx, Pointer> {
// This function raises an error if the offset moves the pointer outside of its allocation. We consider
// ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0).
// We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own
// allocation.
if ptr.is_null()? {
// NULL pointers must only be offset by 0
return if offset == 0 {
Ok(ptr)
} else {
err!(InvalidNullPointerUsage)
};
}
// FIXME: assuming here that type size is < i64::max_value()
let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64;
return if let Some(offset) = offset.checked_mul(pointee_size) {
let ptr = ptr.signed_offset(offset, self)?;
// Do not do bounds-checking for integers; they can never alias a normal pointer anyway.
if let PrimVal::Ptr(ptr) = ptr.into_inner_primval() {
self.memory.check_bounds(ptr, false)?;
} else if ptr.is_null()? {
// We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now.
return err!(InvalidNullPointerUsage);
}
Ok(ptr)
} else {
err!(OverflowingMath)
};
}
}