move pointer truncation to a common method in memory.rs
This commit is contained in:
parent
40950b2cd1
commit
4d38f8dffb
6 changed files with 113 additions and 70 deletions
|
|
@ -4,7 +4,7 @@ use syntax::ast::{FloatTy, IntTy, UintTy};
|
|||
use error::{EvalResult, EvalError};
|
||||
use eval_context::EvalContext;
|
||||
use value::PrimVal;
|
||||
use memory::MemoryPointer;
|
||||
use memory::{MemoryPointer, HasDataLayout};
|
||||
|
||||
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
pub(super) fn cast_primval(
|
||||
|
|
@ -78,7 +78,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
TyChar => Err(EvalError::InvalidChar(v)),
|
||||
|
||||
// No alignment check needed for raw pointers. But we have to truncate to target ptr size.
|
||||
TyRawPtr(_) => Ok(PrimVal::Bytes(v % (1u128 << self.memory.layout.pointer_size.bits()))),
|
||||
TyRawPtr(_) => Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128)),
|
||||
|
||||
_ => Err(EvalError::Unimplemented(format!("int to {:?} cast", ty))),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1226,8 +1226,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
let field_1_ty = self.get_field_ty(ty, 1)?;
|
||||
let field_0_size = self.type_size(field_0_ty)?.expect("pair element type must be sized");
|
||||
let field_1_size = self.type_size(field_1_ty)?.expect("pair element type must be sized");
|
||||
self.memory.write_primval(ptr.offset(field_0, self.memory.layout)?.into(), a, field_0_size)?;
|
||||
self.memory.write_primval(ptr.offset(field_1, self.memory.layout)?.into(), b, field_1_size)?;
|
||||
let layout = self.memory.layout;
|
||||
self.memory.write_primval(ptr.offset(field_0, layout)?.into(), a, field_0_size)?;
|
||||
self.memory.write_primval(ptr.offset(field_1, layout)?.into(), b, field_1_size)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc::ty::layout::{self, TargetDataLayout};
|
|||
use syntax::ast::Mutability;
|
||||
|
||||
use error::{EvalError, EvalResult};
|
||||
use value::{PrimVal, self, Pointer};
|
||||
use value::{PrimVal, Pointer};
|
||||
use eval_context::EvalContext;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -73,26 +73,26 @@ impl MemoryPointer {
|
|||
MemoryPointer { alloc_id, offset }
|
||||
}
|
||||
|
||||
pub fn wrapping_signed_offset<'tcx>(self, i: i64, layout: &TargetDataLayout) -> Self {
|
||||
MemoryPointer::new(self.alloc_id, value::wrapping_signed_offset(self.offset, i, layout))
|
||||
pub(crate) fn wrapping_signed_offset<'a, L: HasDataLayout<'a>>(self, i: i64, l: L) -> Self {
|
||||
MemoryPointer::new(self.alloc_id, l.wrapping_signed_offset(self.offset, i))
|
||||
}
|
||||
|
||||
pub fn overflowing_signed_offset<'tcx>(self, i: i128, layout: &TargetDataLayout) -> (Self, bool) {
|
||||
let (res, over) = value::overflowing_signed_offset(self.offset, i, layout);
|
||||
pub(crate) fn overflowing_signed_offset<'a, L: HasDataLayout<'a>>(self, i: i128, l: L) -> (Self, bool) {
|
||||
let (res, over) = l.overflowing_signed_offset(self.offset, i);
|
||||
(MemoryPointer::new(self.alloc_id, res), over)
|
||||
}
|
||||
|
||||
pub fn signed_offset<'tcx>(self, i: i64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
|
||||
Ok(MemoryPointer::new(self.alloc_id, value::signed_offset(self.offset, i, layout)?))
|
||||
pub(crate) fn signed_offset<'a, 'tcx, L: HasDataLayout<'a>>(self, i: i64, l: L) -> EvalResult<'tcx, Self> {
|
||||
Ok(MemoryPointer::new(self.alloc_id, l.signed_offset(self.offset, i)?))
|
||||
}
|
||||
|
||||
pub fn overflowing_offset<'tcx>(self, i: u64, layout: &TargetDataLayout) -> (Self, bool) {
|
||||
let (res, over) = value::overflowing_offset(self.offset, i, layout);
|
||||
pub(crate) fn overflowing_offset<'a, L: HasDataLayout<'a>>(self, i: u64, l: L) -> (Self, bool) {
|
||||
let (res, over) = l.overflowing_offset(self.offset, i);
|
||||
(MemoryPointer::new(self.alloc_id, res), over)
|
||||
}
|
||||
|
||||
pub fn offset<'tcx>(self, i: u64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
|
||||
Ok(MemoryPointer::new(self.alloc_id, value::offset(self.offset, i, layout)?))
|
||||
pub(crate) fn offset<'a, 'tcx, L: HasDataLayout<'a>>(self, i: u64, l: L) -> EvalResult<'tcx, Self> {
|
||||
Ok(MemoryPointer::new(self.alloc_id, l.offset(self.offset, i)?))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -540,7 +540,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||
if size == 0 {
|
||||
return Ok(&[]);
|
||||
}
|
||||
self.check_bounds(ptr.offset(size, self.layout)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
|
||||
self.check_bounds(ptr.offset(size, self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
|
||||
let alloc = self.get(ptr.alloc_id)?;
|
||||
assert_eq!(ptr.offset as usize as u64, ptr.offset);
|
||||
assert_eq!(size as usize as u64, size);
|
||||
|
|
@ -1131,6 +1131,7 @@ fn bit_index(bits: u64) -> (usize, usize) {
|
|||
|
||||
pub(crate) trait HasMemory<'a, 'tcx> {
|
||||
fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx>;
|
||||
fn memory(&self) -> &Memory<'a, 'tcx>;
|
||||
|
||||
// These are not supposed to be overriden.
|
||||
fn read_maybe_aligned<F, T>(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T>
|
||||
|
|
@ -1159,6 +1160,11 @@ impl<'a, 'tcx> HasMemory<'a, 'tcx> for Memory<'a, 'tcx> {
|
|||
fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx> {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn memory(&self) -> &Memory<'a, 'tcx> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> HasMemory<'a, 'tcx> for EvalContext<'a, 'tcx> {
|
||||
|
|
@ -1166,4 +1172,81 @@ impl<'a, 'tcx> HasMemory<'a, 'tcx> for EvalContext<'a, 'tcx> {
|
|||
fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx> {
|
||||
&mut self.memory
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn memory(&self) -> &Memory<'a, 'tcx> {
|
||||
&self.memory
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Pointer arithmetic
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub(crate) trait HasDataLayout<'a> : Copy {
|
||||
fn data_layout(self) -> &'a TargetDataLayout;
|
||||
|
||||
// These are not supposed to be overriden.
|
||||
|
||||
//// Trunace the given value to the pointer size; also return whether there was an overflow
|
||||
fn truncate_to_ptr(self, val: u128) -> (u64, bool) {
|
||||
let max_ptr_plus_1 = 1u128 << self.data_layout().pointer_size.bits();
|
||||
((val % max_ptr_plus_1) as u64, val >= max_ptr_plus_1)
|
||||
}
|
||||
|
||||
// Overflow checking only works properly on the range from -u64 to +u64.
|
||||
fn overflowing_signed_offset(self, val: u64, i: i128) -> (u64, bool) {
|
||||
// FIXME: is it possible to over/underflow here?
|
||||
if i < 0 {
|
||||
// trickery to ensure that i64::min_value() works fine
|
||||
// this formula only works for true negative values, it panics for zero!
|
||||
let n = u64::max_value() - (i as u64) + 1;
|
||||
val.overflowing_sub(n)
|
||||
} else {
|
||||
self.overflowing_offset(val, i as u64)
|
||||
}
|
||||
}
|
||||
|
||||
fn overflowing_offset(self, val: u64, i: u64) -> (u64, bool) {
|
||||
let (res, over1) = val.overflowing_add(i);
|
||||
let (res, over2) = self.truncate_to_ptr(res as u128);
|
||||
(res, over1 || over2)
|
||||
}
|
||||
|
||||
fn signed_offset<'tcx>(self, val: u64, i: i64) -> EvalResult<'tcx, u64> {
|
||||
let (res, over) = self.overflowing_signed_offset(val, i as i128);
|
||||
if over {
|
||||
Err(EvalError::OverflowingMath)
|
||||
} else {
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
fn offset<'tcx>(self, val: u64, i: u64) -> EvalResult<'tcx, u64> {
|
||||
let (res, over) = self.overflowing_offset(val, i);
|
||||
if over {
|
||||
Err(EvalError::OverflowingMath)
|
||||
} else {
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
fn wrapping_signed_offset(self, val: u64, i: i64) -> u64 {
|
||||
self.overflowing_signed_offset(val, i as i128).0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> HasDataLayout<'a> for &'a TargetDataLayout {
|
||||
#[inline]
|
||||
fn data_layout(self) -> &'a TargetDataLayout {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'tcx, T> HasDataLayout<'a> for &'b T
|
||||
where T: HasMemory<'a, 'tcx> {
|
||||
#[inline]
|
||||
fn data_layout(self) -> &'a TargetDataLayout {
|
||||
self.memory().layout
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -814,8 +814,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
if let Some((name, value)) = new {
|
||||
// +1 for the null terminator
|
||||
let value_copy = self.memory.allocate((value.len() + 1) as u64, 1, Kind::Env)?;
|
||||
let layout = self.memory.layout;
|
||||
self.memory.write_bytes(value_copy.into(), &value)?;
|
||||
self.memory.write_bytes(value_copy.offset(value.len() as u64, self.memory.layout)?.into(), &[0])?;
|
||||
self.memory.write_bytes(value_copy.offset(value.len() as u64, layout)?.into(), &[0])?;
|
||||
if let Some(var) = self.env_vars.insert(name.to_owned(), value_copy) {
|
||||
self.memory.deallocate(var, None, Kind::Env)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,14 +57,15 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
let drop = self.memory.create_fn_alloc(drop);
|
||||
self.memory.write_ptr(vtable, drop)?;
|
||||
|
||||
self.memory.write_usize(vtable.offset(ptr_size, self.memory.layout)?, size)?;
|
||||
self.memory.write_usize(vtable.offset(ptr_size * 2, self.memory.layout)?, align)?;
|
||||
let layout = self.memory.layout;
|
||||
self.memory.write_usize(vtable.offset(ptr_size, layout)?, size)?;
|
||||
self.memory.write_usize(vtable.offset(ptr_size * 2, layout)?, align)?;
|
||||
|
||||
for (i, method) in ::rustc::traits::get_vtable_methods(self.tcx, trait_ref).enumerate() {
|
||||
if let Some((def_id, substs)) = method {
|
||||
let instance = eval_context::resolve(self.tcx, def_id, substs);
|
||||
let fn_ptr = self.memory.create_fn_alloc(instance);
|
||||
self.memory.write_ptr(vtable.offset(ptr_size * (3 + i as u64), self.memory.layout)?, fn_ptr)?;
|
||||
self.memory.write_ptr(vtable.offset(ptr_size * (3 + i as u64), layout)?, fn_ptr)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
#![allow(unknown_lints)]
|
||||
#![allow(float_cmp)]
|
||||
|
||||
use rustc::ty::layout::TargetDataLayout;
|
||||
|
||||
use error::{EvalError, EvalResult};
|
||||
use memory::{Memory, MemoryPointer, HasMemory};
|
||||
use memory::{Memory, MemoryPointer, HasMemory, HasDataLayout};
|
||||
|
||||
pub(super) fn bytes_to_f32(bytes: u128) -> f32 {
|
||||
f32::from_bits(bytes as u32)
|
||||
|
|
@ -61,33 +59,33 @@ impl<'tcx> Pointer {
|
|||
self.primval
|
||||
}
|
||||
|
||||
pub(crate) fn signed_offset(self, i: i64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
|
||||
pub(crate) fn signed_offset<'a, L: HasDataLayout<'a>>(self, i: i64, layout: L) -> EvalResult<'tcx, Self> {
|
||||
match self.primval {
|
||||
PrimVal::Bytes(b) => {
|
||||
assert_eq!(b as u64 as u128, b);
|
||||
Ok(Pointer::from(PrimVal::Bytes(signed_offset(b as u64, i, layout)? as u128)))
|
||||
Ok(Pointer::from(PrimVal::Bytes(layout.signed_offset(b as u64, i)? as u128)))
|
||||
},
|
||||
PrimVal::Ptr(ptr) => ptr.signed_offset(i, layout).map(Pointer::from),
|
||||
PrimVal::Undef => Err(EvalError::ReadUndefBytes),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn offset(self, i: u64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
|
||||
pub(crate) fn offset<'a, L: HasDataLayout<'a>>(self, i: u64, layout: L) -> EvalResult<'tcx, Self> {
|
||||
match self.primval {
|
||||
PrimVal::Bytes(b) => {
|
||||
assert_eq!(b as u64 as u128, b);
|
||||
Ok(Pointer::from(PrimVal::Bytes(offset(b as u64, i, layout)? as u128)))
|
||||
Ok(Pointer::from(PrimVal::Bytes(layout.offset(b as u64, i)? as u128)))
|
||||
},
|
||||
PrimVal::Ptr(ptr) => ptr.offset(i, layout).map(Pointer::from),
|
||||
PrimVal::Undef => Err(EvalError::ReadUndefBytes),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn wrapping_signed_offset(self, i: i64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
|
||||
pub(crate) fn wrapping_signed_offset<'a, L: HasDataLayout<'a>>(self, i: i64, layout: L) -> EvalResult<'tcx, Self> {
|
||||
match self.primval {
|
||||
PrimVal::Bytes(b) => {
|
||||
assert_eq!(b as u64 as u128, b);
|
||||
Ok(Pointer::from(PrimVal::Bytes(wrapping_signed_offset(b as u64, i, layout) as u128)))
|
||||
Ok(Pointer::from(PrimVal::Bytes(layout.wrapping_signed_offset(b as u64, i) as u128)))
|
||||
},
|
||||
PrimVal::Ptr(ptr) => Ok(Pointer::from(ptr.wrapping_signed_offset(i, layout))),
|
||||
PrimVal::Undef => Err(EvalError::ReadUndefBytes),
|
||||
|
|
@ -323,47 +321,6 @@ impl<'tcx> PrimVal {
|
|||
}
|
||||
}
|
||||
|
||||
// Overflow checking only works properly on the range from -u64 to +u64.
|
||||
pub fn overflowing_signed_offset<'tcx>(val: u64, i: i128, layout: &TargetDataLayout) -> (u64, bool) {
|
||||
// FIXME: is it possible to over/underflow here?
|
||||
if i < 0 {
|
||||
// trickery to ensure that i64::min_value() works fine
|
||||
// this formula only works for true negative values, it panics for zero!
|
||||
let n = u64::max_value() - (i as u64) + 1;
|
||||
val.overflowing_sub(n)
|
||||
} else {
|
||||
overflowing_offset(val, i as u64, layout)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overflowing_offset<'tcx>(val: u64, i: u64, layout: &TargetDataLayout) -> (u64, bool) {
|
||||
let (res, over) = val.overflowing_add(i);
|
||||
((res as u128 % (1u128 << layout.pointer_size.bits())) as u64,
|
||||
over || res as u128 >= (1u128 << layout.pointer_size.bits()))
|
||||
}
|
||||
|
||||
pub fn signed_offset<'tcx>(val: u64, i: i64, layout: &TargetDataLayout) -> EvalResult<'tcx, u64> {
|
||||
let (res, over) = overflowing_signed_offset(val, i as i128, layout);
|
||||
if over {
|
||||
Err(EvalError::OverflowingMath)
|
||||
} else {
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn offset<'tcx>(val: u64, i: u64, layout: &TargetDataLayout) -> EvalResult<'tcx, u64> {
|
||||
let (res, over) = overflowing_offset(val, i, layout);
|
||||
if over {
|
||||
Err(EvalError::OverflowingMath)
|
||||
} else {
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wrapping_signed_offset<'tcx>(val: u64, i: i64, layout: &TargetDataLayout) -> u64 {
|
||||
overflowing_signed_offset(val, i as i128, layout).0
|
||||
}
|
||||
|
||||
impl PrimValKind {
|
||||
pub fn is_int(self) -> bool {
|
||||
use self::PrimValKind::*;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue