X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Foperator.rs;h=cf92aed9ccb2c5edcf98e451e042f56b142198e3;hb=20e31dbdad67080eb83aa3b5330dfe2f116f9900;hp=2a90d3e12f4c0f41c51c0f4a837051aed579333e;hpb=4ddc37df7a27d442e72db07f02108a71f6ab3f6e;p=rust.git diff --git a/src/operator.rs b/src/operator.rs index 2a90d3e12f4..cf92aed9ccb 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,7 +1,6 @@ -use std::convert::TryFrom; +use log::trace; -use rustc::ty::{Ty, layout::{Size, LayoutOf}}; -use rustc::mir; +use rustc_middle::{mir, ty::Ty}; use crate::*; @@ -9,44 +8,36 @@ pub trait EvalContextExt<'tcx> { fn binary_ptr_op( &self, bin_op: mir::BinOp, - left: ImmTy<'tcx, Tag>, - right: ImmTy<'tcx, Tag>, + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; - fn ptr_eq( - &self, - left: Scalar, - right: Scalar, - ) -> InterpResult<'tcx, bool>; - - fn pointer_offset_inbounds( - &self, - ptr: Scalar, - pointee_ty: Ty<'tcx>, - offset: i64, - ) -> InterpResult<'tcx, Scalar>; + fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool>; } impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { fn binary_ptr_op( &self, bin_op: mir::BinOp, - left: ImmTy<'tcx, Tag>, - right: ImmTy<'tcx, Tag>, + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { - use rustc::mir::BinOp::*; + use rustc_middle::mir::BinOp::*; trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); Ok(match bin_op { Eq | Ne => { // This supports fat pointers. - let eq = match (*left, *right) { - (Immediate::Scalar(left), Immediate::Scalar(right)) => - self.ptr_eq(left.not_undef()?, right.not_undef()?)?, - (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) => - self.ptr_eq(left1.not_undef()?, right1.not_undef()?)? && - self.ptr_eq(left2.not_undef()?, right2.not_undef()?)?, + #[rustfmt::skip] + let eq = match (**left, **right) { + (Immediate::Scalar(left), Immediate::Scalar(right)) => { + self.ptr_eq(left.check_init()?, right.check_init()?)? + } + (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) => { + self.ptr_eq(left1.check_init()?, right1.check_init()?)? + && self.ptr_eq(left2.check_init()?, right2.check_init()?)? + } _ => bug!("Type system should not allow comparing Scalar with ScalarPair"), }; (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false, self.tcx.types.bool) @@ -68,27 +59,21 @@ fn binary_ptr_op( } Offset => { - let pointee_ty = left.layout.ty - .builtin_deref(true) - .expect("Offset called on non-ptr type") - .ty; - let ptr = self.pointer_offset_inbounds( + let pointee_ty = + left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty; + let ptr = self.ptr_offset_inbounds( left.to_scalar()?, pointee_ty, - right.to_scalar()?.to_isize(self)?, + right.to_scalar()?.to_machine_isize(self)?, )?; (ptr, false, left.layout.ty) } - _ => bug!("Invalid operator on pointers: {:?}", bin_op) + _ => bug!("Invalid operator on pointers: {:?}", bin_op), }) } - fn ptr_eq( - &self, - left: Scalar, - right: Scalar, - ) -> InterpResult<'tcx, bool> { + fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool> { let size = self.pointer_size(); // Just compare the integers. // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers? @@ -96,38 +81,4 @@ fn ptr_eq( let right = self.force_bits(right, size)?; Ok(left == right) } - - /// Raises an error if the offset moves the pointer outside of its allocation. - /// For integers, we consider each of them their own tiny allocation of size 0, - /// so offset-by-0 is okay for them -- except for NULL, which we rule out entirely. - fn pointer_offset_inbounds( - &self, - ptr: Scalar, - pointee_ty: Ty<'tcx>, - offset: i64, - ) -> InterpResult<'tcx, Scalar> { - let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); - let offset = offset - .checked_mul(pointee_size) - .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; - // We do this first, to rule out overflows. - let offset_ptr = ptr.ptr_signed_offset(offset, self)?; - // What we need to check is that starting at `min(ptr, offset_ptr)`, - // we could do an access of size `abs(offset)`. Alignment does not matter. - let (min_ptr, abs_offset) = if offset >= 0 { - (ptr, u64::try_from(offset).unwrap()) - } else { - // Negative offset. - // If the negation overflows, the result will be negative so the try_from will fail. - (offset_ptr, u64::try_from(-offset).unwrap()) - }; - self.memory.check_ptr_access_align( - min_ptr, - Size::from_bytes(abs_offset), - None, - CheckInAllocMsg::InboundsTest, - )?; - // That's it! - Ok(offset_ptr) - } }