diff options
| author | Ralf Jung <post@ralfj.de> | 2019-05-26 14:13:12 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2019-05-26 14:13:12 +0200 |
| commit | aad13a176a0c9c96380fecf574f424e555fe880b (patch) | |
| tree | 2decdde3adb5bc04e400eb43358aa624be0c2e65 | |
| parent | 3defb3f18fdd6d2bd74b3de7a2d932133c99303b (diff) | |
| download | rust-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.rs | 16 | ||||
| -rw-r--r-- | src/librustc/mir/interpret/value.rs | 42 | ||||
| -rw-r--r-- | src/librustc_codegen_utils/symbol_names.rs | 2 | ||||
| -rw-r--r-- | src/librustc_mir/hair/constant.rs | 3 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/cast.rs | 41 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/memory.rs | 8 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/operand.rs | 13 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/validity.rs | 8 |
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) { |
