centralize Scalar size sanity checks and also do them in release builds
This commit is contained in:
parent
3defb3f18f
commit
aad13a176a
|
@ -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;
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
|
@ -294,12 +294,35 @@ impl<'tcx, Tag> Scalar<Tag> {
|
|||
Scalar::Raw { data: f.to_bits() as u128, size: 8 }
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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))))
|
||||
}
|
||||
|
|
|
@ -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))),
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue