]> git.lizzy.rs Git - rust.git/blobdiff - src/helpers.rs
rustup for big refactor; kill most of validation
[rust.git] / src / helpers.rs
index 8482c484608b741ad13dcc6fb538c99990b75940..606f1bb4ecb447e9cbcf0332b46bcfe30b1cbd23 100644 (file)
-use mir;
-use rustc::ty::Ty;
-use rustc::ty::layout::{LayoutOf, Size};
+use rustc::ty::layout::{Size, HasDataLayout};
 
-use super::{Scalar, ScalarExt, EvalResult, EvalContext, ValTy};
+use super::{Scalar, ScalarMaybeUndef, EvalResult};
 use rustc_mir::interpret::sign_extend;
 
-pub trait EvalContextExt<'tcx> {
-    fn wrapping_pointer_offset(
-        &self,
-        ptr: Scalar,
-        pointee_ty: Ty<'tcx>,
-        offset: i64,
-    ) -> EvalResult<'tcx, Scalar>;
-
-    fn pointer_offset(
-        &self,
-        ptr: Scalar,
-        pointee_ty: Ty<'tcx>,
-        offset: i64,
-    ) -> EvalResult<'tcx, Scalar>;
-
-    fn value_to_isize(
-        &self,
-        value: ValTy<'tcx>,
-    ) -> EvalResult<'tcx, i64>;
-
-    fn value_to_usize(
-        &self,
-        value: ValTy<'tcx>,
-    ) -> EvalResult<'tcx, u64>;
-
-    fn value_to_i32(
-        &self,
-        value: ValTy<'tcx>,
-    ) -> EvalResult<'tcx, i32>;
-
-    fn value_to_u8(
-        &self,
-        value: ValTy<'tcx>,
-    ) -> EvalResult<'tcx, u8>;
+pub trait ScalarExt {
+    fn null(size: Size) -> Self;
+    fn from_i32(i: i32) -> Self;
+    fn from_uint(i: impl Into<u128>, ptr_size: Size) -> Self;
+    fn from_int(i: impl Into<i128>, ptr_size: Size) -> Self;
+    fn from_f32(f: f32) -> Self;
+    fn from_f64(f: f64) -> Self;
+    fn is_null(self) -> bool;
 }
 
-impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
-    fn wrapping_pointer_offset(
-        &self,
-        ptr: Scalar,
-        pointee_ty: Ty<'tcx>,
-        offset: i64,
-    ) -> EvalResult<'tcx, Scalar> {
-        // 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;
-        Ok(ptr.ptr_wrapping_signed_offset(offset, self))
-    }
-
-    fn pointer_offset(
-        &self,
-        ptr: Scalar,
-        pointee_ty: Ty<'tcx>,
-        offset: i64,
-    ) -> EvalResult<'tcx, Scalar> {
-        // 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)
-            };
+pub trait FalibleScalarExt {
+    fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64>;
+    fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64>;
+    fn to_i32(self) -> EvalResult<'static, i32>;
+    fn to_u8(self) -> EvalResult<'static, u8>;
+
+    /// HACK: this function just extracts all bits if `defined != 0`
+    /// Mainly used for args of C-functions and we should totally correctly fetch the size
+    /// of their arguments
+    fn to_bytes(self) -> EvalResult<'static, u128>;
+}
+
+impl ScalarExt for Scalar {
+    fn null(size: Size) -> Self {
+        Scalar::Bits { bits: 0, size: size.bytes() as u8 }
+    }
+
+    fn from_i32(i: i32) -> Self {
+        Scalar::Bits { bits: i as u32 as u128, size: 4 }
+    }
+
+    fn from_uint(i: impl Into<u128>, size: Size) -> Self {
+        Scalar::Bits { bits: i.into(), size: size.bytes() as u8 }
+    }
+
+    fn from_int(i: impl Into<i128>, size: Size) -> Self {
+        Scalar::Bits { bits: i.into() as u128, size: size.bytes() as u8 }
+    }
+
+    fn from_f32(f: f32) -> Self {
+        Scalar::Bits { bits: f.to_bits() as u128, size: 4 }
+    }
+
+    fn from_f64(f: f64) -> Self {
+        Scalar::Bits { bits: f.to_bits() as u128, size: 8 }
+    }
+
+    fn is_null(self) -> bool {
+        match self {
+            Scalar::Bits { bits, .. } => bits == 0,
+            Scalar::Ptr(_) => false
         }
-        // FIXME: assuming here that type size is < i64::max_value()
-        let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64;
-         if let Some(offset) = offset.checked_mul(pointee_size) {
-            let ptr = ptr.ptr_signed_offset(offset, self)?;
-            // Do not do bounds-checking for integers; they can never alias a normal pointer anyway.
-            if let Scalar::Ptr(ptr) = ptr {
-                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!(Overflow(mir::BinOp::Mul))
+    }
+}
+
+impl FalibleScalarExt for Scalar {
+    fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> {
+        let b = self.to_bits(cx.data_layout().pointer_size)?;
+        assert_eq!(b as u64 as u128, b);
+        Ok(b as u64)
+    }
+
+    fn to_u8(self) -> EvalResult<'static, u8> {
+        let sz = Size::from_bits(8);
+        let b = self.to_bits(sz)?;
+        assert_eq!(b as u8 as u128, b);
+        Ok(b as u8)
+    }
+
+    fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> {
+        let b = self.to_bits(cx.data_layout().pointer_size)?;
+        let b = sign_extend(b, cx.data_layout().pointer_size) as i128;
+        assert_eq!(b as i64 as i128, b);
+        Ok(b as i64)
+    }
+
+    fn to_i32(self) -> EvalResult<'static, i32> {
+        let sz = Size::from_bits(32);
+        let b = self.to_bits(sz)?;
+        let b = sign_extend(b, sz) as i128;
+        assert_eq!(b as i32 as i128, b);
+        Ok(b as i32)
+    }
+
+    fn to_bytes(self) -> EvalResult<'static, u128> {
+        match self {
+            Scalar::Bits { bits, size } => {
+                assert_ne!(size, 0);
+                Ok(bits)
+            },
+            Scalar::Ptr(_) => err!(ReadPointerAsBytes),
         }
     }
+}
+
+impl FalibleScalarExt for ScalarMaybeUndef {
+    fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> {
+        self.not_undef()?.to_usize(cx)
+    }
+
+    fn to_u8(self) -> EvalResult<'static, u8> {
+        self.not_undef()?.to_u8()
+    }
+
+    fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> {
+        self.not_undef()?.to_isize(cx)
+    }
+
+    fn to_i32(self) -> EvalResult<'static, i32> {
+        self.not_undef()?.to_i32()
+    }
 
-    fn value_to_isize(
-        &self,
-        value: ValTy<'tcx>,
-    ) -> EvalResult<'tcx, i64> {
-        assert_eq!(value.ty, self.tcx.types.isize);
-        let raw = self.value_to_scalar(value)?.to_bits(self.memory.pointer_size())?;
-        let raw = sign_extend(raw, self.layout_of(self.tcx.types.isize).unwrap());
-        Ok(raw as i64)
-    }
-
-    fn value_to_usize(
-        &self,
-        value: ValTy<'tcx>,
-    ) -> EvalResult<'tcx, u64> {
-        assert_eq!(value.ty, self.tcx.types.usize);
-        self.value_to_scalar(value)?.to_bits(self.memory.pointer_size()).map(|v| v as u64)
-    }
-
-    fn value_to_i32(
-        &self,
-        value: ValTy<'tcx>,
-    ) -> EvalResult<'tcx, i32> {
-        assert_eq!(value.ty, self.tcx.types.i32);
-        let raw = self.value_to_scalar(value)?.to_bits(Size::from_bits(32))?;
-        let raw = sign_extend(raw, self.layout_of(self.tcx.types.i32).unwrap());
-        Ok(raw as i32)
-    }
-
-    fn value_to_u8(
-        &self,
-        value: ValTy<'tcx>,
-    ) -> EvalResult<'tcx, u8> {
-        assert_eq!(value.ty, self.tcx.types.u8);
-        self.value_to_scalar(value)?.to_bits(Size::from_bits(8)).map(|v| v as u8)
+    fn to_bytes(self) -> EvalResult<'static, u128> {
+        self.not_undef()?.to_bytes()
     }
 }