about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2019-05-26 14:13:12 +0200
committerRalf Jung <post@ralfj.de>2019-05-26 14:13:12 +0200
commitaad13a176a0c9c96380fecf574f424e555fe880b (patch)
tree2decdde3adb5bc04e400eb43358aa624be0c2e65
parent3defb3f18fdd6d2bd74b3de7a2d932133c99303b (diff)
downloadrust-aad13a176a0c9c96380fecf574f424e555fe880b.tar.gz
rust-aad13a176a0c9c96380fecf574f424e555fe880b.zip
centralize Scalar size sanity checks and also do them in release builds
-rw-r--r--src/librustc/mir/interpret/allocation.rs16
-rw-r--r--src/librustc/mir/interpret/value.rs42
-rw-r--r--src/librustc_codegen_utils/symbol_names.rs2
-rw-r--r--src/librustc_mir/hair/constant.rs3
-rw-r--r--src/librustc_mir/interpret/cast.rs41
-rw-r--r--src/librustc_mir/interpret/memory.rs8
-rw-r--r--src/librustc_mir/interpret/operand.rs13
-rw-r--r--src/librustc_mir/interpret/validity.rs8
8 files changed, 54 insertions, 79 deletions
diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs
index 988bd530241..56173dfe304 100644
--- a/src/librustc/mir/interpret/allocation.rs
+++ b/src/librustc/mir/interpret/allocation.rs
@@ -2,7 +2,6 @@
 
 use super::{
     Pointer, EvalResult, AllocId, ScalarMaybeUndef, write_target_uint, read_target_uint, Scalar,
-    truncate,
 };
 
 use crate::ty::layout::{Size, Align};
@@ -382,18 +381,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
             ScalarMaybeUndef::Undef => return self.mark_definedness(ptr, type_size, false),
         };
 
-        let bytes = match val {
-            Scalar::Ptr(val) => {
-                assert_eq!(type_size, cx.data_layout().pointer_size);
-                val.offset.bytes() as u128
-            }
-
-            Scalar::Raw { data, size } => {
-                assert_eq!(size as u64, type_size.bytes());
-                debug_assert_eq!(truncate(data, Size::from_bytes(size.into())), data,
-                    "Unexpected value of size {} when writing to memory", size);
-                data
-            },
+        let bytes = match val.to_bits_or_ptr(type_size, cx) {
+            Err(val) => val.offset.bytes() as u128,
+            Ok(data) => data,
         };
 
         let endian = cx.data_layout().endian;
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index c6099adcc34..3aed90c70ad 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -232,7 +232,7 @@ impl<'tcx, Tag> Scalar<Tag> {
         }
     }
 
-    /// Returns this pointers offset from the allocation base, or from NULL (for
+    /// Returns this pointer's offset from the allocation base, or from NULL (for
     /// integer pointers).
     #[inline]
     pub fn get_ptr_offset(self, cx: &impl HasDataLayout) -> Size {
@@ -269,7 +269,7 @@ impl<'tcx, Tag> Scalar<Tag> {
     #[inline]
     pub fn from_uint(i: impl Into<u128>, size: Size) -> Self {
         let i = i.into();
-        debug_assert_eq!(truncate(i, size), i,
+        assert_eq!(truncate(i, size), i,
                          "Unsigned value {} does not fit in {} bits", i, size.bits());
         Scalar::Raw { data: i, size: size.bytes() as u8 }
     }
@@ -279,7 +279,7 @@ impl<'tcx, Tag> Scalar<Tag> {
         let i = i.into();
         // `into` performed sign extension, we have to truncate
         let truncated = truncate(i as u128, size);
-        debug_assert_eq!(sign_extend(truncated, size) as i128, i,
+        assert_eq!(sign_extend(truncated, size) as i128, i,
                          "Signed value {} does not fit in {} bits", i, size.bits());
         Scalar::Raw { data: truncated, size: size.bytes() as u8 }
     }
@@ -295,11 +295,34 @@ impl<'tcx, Tag> Scalar<Tag> {
     }
 
     #[inline]
+    pub fn to_bits_or_ptr(
+        self,
+        target_size: Size,
+        cx: &impl HasDataLayout,
+    ) -> Result<u128, Pointer<Tag>> {
+        match self {
+            Scalar::Raw { data, size } => {
+                assert_eq!(target_size.bytes(), size as u64);
+                assert_ne!(size, 0, "to_bits cannot be used with zsts");
+                assert_eq!(truncate(data, target_size), data,
+                            "Scalar value {:#x} exceeds size of {} bytes", data, size);
+                Ok(data)
+            }
+            Scalar::Ptr(ptr) => {
+                assert_eq!(target_size, cx.data_layout().pointer_size);
+                Err(ptr)
+            }
+        }
+    }
+
+    #[inline]
     pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
         match self {
             Scalar::Raw { data, size } => {
                 assert_eq!(target_size.bytes(), size as u64);
                 assert_ne!(size, 0, "to_bits cannot be used with zsts");
+                assert_eq!(truncate(data, target_size), data,
+                            "Scalar value {:#x} exceeds size of {} bytes", data, size);
                 Ok(data)
             }
             Scalar::Ptr(_) => err!(ReadPointerAsBytes),
@@ -350,27 +373,23 @@ impl<'tcx, Tag> Scalar<Tag> {
     pub 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)
     }
 
     pub fn to_u32(self) -> EvalResult<'static, u32> {
         let sz = Size::from_bits(32);
         let b = self.to_bits(sz)?;
-        assert_eq!(b as u32 as u128, b);
         Ok(b as u32)
     }
 
     pub fn to_u64(self) -> EvalResult<'static, u64> {
         let sz = Size::from_bits(64);
         let b = self.to_bits(sz)?;
-        assert_eq!(b as u64 as u128, b);
         Ok(b as u64)
     }
 
     pub 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)
     }
 
@@ -378,7 +397,6 @@ impl<'tcx, Tag> Scalar<Tag> {
         let sz = Size::from_bits(8);
         let b = self.to_bits(sz)?;
         let b = sign_extend(b, sz) as i128;
-        assert_eq!(b as i8 as i128, b);
         Ok(b as i8)
     }
 
@@ -386,7 +404,6 @@ impl<'tcx, Tag> Scalar<Tag> {
         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)
     }
 
@@ -394,14 +411,13 @@ impl<'tcx, Tag> Scalar<Tag> {
         let sz = Size::from_bits(64);
         let b = self.to_bits(sz)?;
         let b = sign_extend(b, sz) as i128;
-        assert_eq!(b as i64 as i128, b);
         Ok(b as i64)
     }
 
     pub 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);
+        let sz = cx.data_layout().pointer_size;
+        let b = self.to_bits(sz)?;
+        let b = sign_extend(b, sz) as i128;
         Ok(b as i64)
     }
 
diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs
index 86407162907..bf81b7f0da5 100644
--- a/src/librustc_codegen_utils/symbol_names.rs
+++ b/src/librustc_codegen_utils/symbol_names.rs
@@ -443,7 +443,7 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> {
         ct: &'tcx ty::Const<'tcx>,
     ) -> Result<Self::Const, Self::Error> {
         // only print integers
-        if let ConstValue::Scalar(Scalar::Bits { .. }) = ct.val {
+        if let ConstValue::Scalar(Scalar::Raw { .. }) = ct.val {
             if ct.ty.is_integral() {
                 return self.pretty_print_const(ct);
             }
diff --git a/src/librustc_mir/hair/constant.rs b/src/librustc_mir/hair/constant.rs
index 0f5c696f7f9..69df36348a6 100644
--- a/src/librustc_mir/hair/constant.rs
+++ b/src/librustc_mir/hair/constant.rs
@@ -101,6 +101,5 @@ fn parse_float<'tcx>(
         }
     };
 
-    // We trust that `data` is properly truncated.
-    Ok(ConstValue::Scalar(Scalar::Raw { data, size }))
+    Ok(ConstValue::Scalar(Scalar::from_uint(data, Size::from_bytes(size))))
 }
diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs
index e0667f17fd1..76b11ac2fe6 100644
--- a/src/librustc_mir/interpret/cast.rs
+++ b/src/librustc_mir/interpret/cast.rs
@@ -6,7 +6,7 @@ use syntax::symbol::sym;
 
 use rustc_apfloat::ieee::{Single, Double};
 use rustc::mir::interpret::{
-    Scalar, EvalResult, Pointer, PointerArithmetic, InterpError, truncate
+    Scalar, EvalResult, Pointer, PointerArithmetic, InterpError,
 };
 use rustc::mir::CastKind;
 use rustc_apfloat::Float;
@@ -135,29 +135,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
         use rustc::ty::TyKind::*;
         trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty);
 
-        match val {
-            Scalar::Ptr(ptr) => self.cast_from_ptr(ptr, dest_layout.ty),
-            Scalar::Raw { data, size } => {
-                debug_assert_eq!(size as u64, src_layout.size.bytes());
-                debug_assert_eq!(truncate(data, Size::from_bytes(size.into())), data,
-                    "Unexpected value of size {} before casting", size);
-
-                let res = match src_layout.ty.sty {
-                    Float(fty) => self.cast_from_float(data, fty, dest_layout.ty)?,
-                    _ => self.cast_from_int(data, src_layout, dest_layout)?,
-                };
-
-                // Sanity check
-                match res {
-                    Scalar::Ptr(_) => bug!("Fabricated a ptr value from an int...?"),
-                    Scalar::Raw { data, size } => {
-                        debug_assert_eq!(size as u64, dest_layout.size.bytes());
-                        debug_assert_eq!(truncate(data, Size::from_bytes(size.into())), data,
-                            "Unexpected value of size {} after casting", size);
-                    }
+        match val.to_bits_or_ptr(src_layout.size, self) {
+            Err(ptr) => self.cast_from_ptr(ptr, dest_layout.ty),
+            Ok(data) => {
+                match src_layout.ty.sty {
+                    Float(fty) => self.cast_from_float(data, fty, dest_layout.ty),
+                    _ => self.cast_from_int(data, src_layout, dest_layout),
                 }
-                // Done
-                Ok(res)
             }
         }
     }
@@ -177,7 +161,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
         trace!("cast_from_int: {}, {}, {}", v, src_layout.ty, dest_layout.ty);
         use rustc::ty::TyKind::*;
         match dest_layout.ty.sty {
-            Int(_) | Uint(_) => {
+            Int(_) | Uint(_) | RawPtr(_) => {
                 let v = self.truncate(v, dest_layout);
                 Ok(Scalar::from_uint(v, dest_layout.size))
             }
@@ -205,15 +189,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
                 Ok(Scalar::from_uint(v, Size::from_bytes(4)))
             },
 
-            // No alignment check needed for raw pointers.
-            // But we have to truncate to target ptr size.
-            RawPtr(_) => {
-                Ok(Scalar::from_uint(
-                    self.truncate_to_ptr(v).0,
-                    self.pointer_size(),
-                ))
-            },
-
             // Casts to bool are not permitted by rustc, no need to handle them here.
             _ => err!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))),
         }
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 7009649ae55..e3a843993ab 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -247,16 +247,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         required_align: Align
     ) -> EvalResult<'tcx> {
         // Check non-NULL/Undef, extract offset
-        let (offset, alloc_align) = match ptr {
-            Scalar::Ptr(ptr) => {
+        let (offset, alloc_align) = match ptr.to_bits_or_ptr(self.pointer_size(), self) {
+            Err(ptr) => {
                 // check this is not NULL -- which we can ensure only if this is in-bounds
                 // of some (potentially dead) allocation.
                 let align = self.check_bounds_ptr(ptr, InboundsCheck::MaybeDead)?;
                 (ptr.offset.bytes(), align)
             }
-            Scalar::Raw { data, size } => {
-                assert_eq!(size as u64, self.pointer_size().bytes());
-                assert!(data < (1u128 << self.pointer_size().bits()));
+            Ok(data) => {
                 // check this is not NULL
                 if data == 0 {
                     return err!(InvalidNullPointerUsage);
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index d4ccccfbfb8..3e3c9234409 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -639,18 +639,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
             } => {
                 let variants_start = niche_variants.start().as_u32() as u128;
                 let variants_end = niche_variants.end().as_u32() as u128;
-                match raw_discr {
-                    ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) => {
+                let raw_discr = raw_discr.not_undef()
+                    .map_err(|_| InterpError::InvalidDiscriminant(ScalarMaybeUndef::Undef))?;
+                match raw_discr.to_bits_or_ptr(discr_val.layout.size, self) {
+                    Err(ptr) => {
                         // The niche must be just 0 (which an inbounds pointer value never is)
                         let ptr_valid = niche_start == 0 && variants_start == variants_end &&
                             self.memory.check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok();
                         if !ptr_valid {
-                            return err!(InvalidDiscriminant(raw_discr.erase_tag()));
+                            return err!(InvalidDiscriminant(raw_discr.erase_tag().into()));
                         }
                         (dataful_variant.as_u32() as u128, dataful_variant)
                     },
-                    ScalarMaybeUndef::Scalar(Scalar::Raw { data: raw_discr, size }) => {
-                        assert_eq!(size as u64, discr_val.layout.size.bytes());
+                    Ok(raw_discr) => {
                         let adjusted_discr = raw_discr.wrapping_sub(niche_start)
                             .wrapping_add(variants_start);
                         if variants_start <= adjusted_discr && adjusted_discr <= variants_end {
@@ -665,8 +666,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
                             (dataful_variant.as_u32() as u128, dataful_variant)
                         }
                     },
-                    ScalarMaybeUndef::Undef =>
-                        return err!(InvalidDiscriminant(ScalarMaybeUndef::Undef)),
                 }
             }
         })
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index c2ecc38808b..d88d0af75fb 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -480,8 +480,8 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
                 wrapping_range_format(&layout.valid_range, max_hi),
             )
         );
-        let bits = match value {
-            Scalar::Ptr(ptr) => {
+        let bits = match value.to_bits_or_ptr(op.layout.size, self.ecx) {
+            Err(ptr) => {
                 if lo == 1 && hi == max_hi {
                     // only NULL is not allowed.
                     // We can call `check_align` to check non-NULL-ness, but have to also look
@@ -509,10 +509,8 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
                     );
                 }
             }
-            Scalar::Raw { data, size } => {
-                assert_eq!(size as u64, op.layout.size.bytes());
+            Ok(data) =>
                 data
-            }
         };
         // Now compare. This is slightly subtle because this is a special "wrap-around" range.
         if wrapping_range_contains(&layout.valid_range, bits) {