提交 4d38f8df 编写于 作者: R Ralf Jung

move pointer truncation to a common method in memory.rs

上级 40950b2c
......@@ -4,7 +4,7 @@
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 @@ fn cast_from_int(&self, v: u128, ty: ty::Ty<'tcx>, negative: bool) -> EvalResult
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 @@ pub(super) fn write_pair_to_ptr(
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 syntax::ast::Mutability;
use error::{EvalError, EvalResult};
use value::{PrimVal, self, Pointer};
use value::{PrimVal, Pointer};
use eval_context::EvalContext;
////////////////////////////////////////////////////////////////////////////////
......@@ -73,26 +73,26 @@ pub fn new(alloc_id: AllocId, offset: u64) -> Self {
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 @@ fn get_bytes_unchecked(&self, ptr: MemoryPointer, size: u64, align: u64) -> Eval
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 @@ fn call_c_abi(
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 @@ pub fn get_vtable(&mut self, ty: Ty<'tcx>, trait_ref: ty::PolyTraitRef<'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)?;
}
}
......
#![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 @@ pub fn into_inner_primval(self) -> PrimVal {
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 @@ pub fn to_bool(self) -> EvalResult<'tcx, bool> {
}
}
// 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::*;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册