Skip to content

Commit

Permalink
Merge pull request rust-lang#267 from RalfJung/cast
Browse files Browse the repository at this point in the history
Fix ptr-int-casts
  • Loading branch information
oli-obk authored Jul 24, 2017
2 parents 6e10752 + 4a34a1b commit 03ca15e
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 129 deletions.
69 changes: 33 additions & 36 deletions src/librustc_mir/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use syntax::ast::{FloatTy, IntTy, UintTy};
use error::{EvalResult, EvalError};
use eval_context::EvalContext;
use value::PrimVal;
use memory::{MemoryPointer, PointerArithmetic};

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
pub(super) fn cast_primval(
Expand All @@ -12,38 +13,34 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
src_ty: Ty<'tcx>,
dest_ty: Ty<'tcx>
) -> EvalResult<'tcx, PrimVal> {
let kind = self.ty_to_primval_kind(src_ty)?;

use value::PrimValKind::*;
match kind {
F32 => self.cast_float(val.to_f32()? as f64, dest_ty),
F64 => self.cast_float(val.to_f64()?, dest_ty),

I8 | I16 | I32 | I64 | I128 => {
if val.is_ptr() {
self.cast_ptr(val, dest_ty)
} else {
self.cast_signed_int(val.to_i128()?, dest_ty)
let src_kind = self.ty_to_primval_kind(src_ty)?;

match val {
PrimVal::Undef => Ok(PrimVal::Undef),
PrimVal::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty),
val @ PrimVal::Bytes(_) => {
use value::PrimValKind::*;
match src_kind {
F32 => self.cast_from_float(val.to_f32()? as f64, dest_ty),
F64 => self.cast_from_float(val.to_f64()?, dest_ty),

I8 | I16 | I32 | I64 | I128 => {
self.cast_from_signed_int(val.to_i128()?, dest_ty)
},

Bool | Char | U8 | U16 | U32 | U64 | U128 | FnPtr | Ptr => {
self.cast_from_int(val.to_u128()?, dest_ty, false)
},
}
},

Bool | Char | U8 | U16 | U32 | U64 | U128 => {
if val.is_ptr() {
self.cast_ptr(val, dest_ty)
} else {
self.cast_int(val.to_u128()?, dest_ty, false)
}
},

FnPtr | Ptr => self.cast_ptr(val, dest_ty),
}
}
}

fn cast_signed_int(&self, val: i128, ty: ty::Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
self.cast_int(val as u128, ty, val < 0)
fn cast_from_signed_int(&self, val: i128, ty: ty::Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
self.cast_from_int(val as u128, ty, val < 0)
}

fn cast_int(&self, v: u128, ty: ty::Ty<'tcx>, negative: bool) -> EvalResult<'tcx, PrimVal> {
fn cast_from_int(&self, v: u128, ty: ty::Ty<'tcx>, negative: bool) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*;
match ty.sty {
// Casts to bool are not permitted by rustc, no need to handle them here.
Expand All @@ -63,13 +60,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
TyInt(IntTy::Is) => {
let int_ty = self.tcx.sess.target.int_type;
let ty = self.tcx.mk_mach_int(int_ty);
self.cast_int(v, ty, negative)
self.cast_from_int(v, ty, negative)
}

TyUint(UintTy::Us) => {
let uint_ty = self.tcx.sess.target.uint_type;
let ty = self.tcx.mk_mach_uint(uint_ty);
self.cast_int(v, ty, negative)
self.cast_from_int(v, ty, negative)
}

TyFloat(FloatTy::F64) if negative => Ok(PrimVal::from_f64(v as i128 as f64)),
Expand All @@ -80,34 +77,34 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
TyChar => Err(EvalError::InvalidChar(v)),

// No alignment check needed for raw pointers
TyRawPtr(_) => Ok(PrimVal::Bytes(v % (1 << self.memory.pointer_size()))),
// No alignment check needed for raw pointers. But we have to truncate to target ptr size.
TyRawPtr(_) => Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128)),

_ => Err(EvalError::Unimplemented(format!("int to {:?} cast", ty))),
}
}

fn cast_float(&self, val: f64, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
fn cast_from_float(&self, val: f64, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*;
match ty.sty {
// Casting negative floats to unsigned integers yields zero.
TyUint(_) if val < 0.0 => self.cast_int(0, ty, false),
TyInt(_) if val < 0.0 => self.cast_int(val as i128 as u128, ty, true),
TyUint(_) if val < 0.0 => self.cast_from_int(0, ty, false),
TyInt(_) if val < 0.0 => self.cast_from_int(val as i128 as u128, ty, true),

TyInt(_) | ty::TyUint(_) => self.cast_int(val as u128, ty, false),
TyInt(_) | ty::TyUint(_) => self.cast_from_int(val as u128, ty, false),

TyFloat(FloatTy::F64) => Ok(PrimVal::from_f64(val)),
TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(val as f32)),
_ => Err(EvalError::Unimplemented(format!("float to {:?} cast", ty))),
}
}

fn cast_ptr(&self, ptr: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
fn cast_from_ptr(&self, ptr: MemoryPointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*;
match ty.sty {
// Casting to a reference or fn pointer is not permitted by rustc, no need to support it here.
TyRawPtr(_) | TyInt(IntTy::Is) | TyUint(UintTy::Us) =>
Ok(ptr),
Ok(PrimVal::Ptr(ptr)),
TyInt(_) | TyUint(_) => Err(EvalError::ReadPointerAsBytes),
_ => Err(EvalError::Unimplemented(format!("ptr to {:?} cast", ty))),
}
Expand Down
22 changes: 12 additions & 10 deletions src/librustc_mir/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
// FIXME(solson)
let dest_ptr = self.force_allocation(dest)?.to_ptr()?;

let discr_dest = dest_ptr.offset(discr_offset, self.memory.layout)?;
let discr_dest = dest_ptr.offset(discr_offset, &self)?;
self.memory.write_uint(discr_dest, discr_val, discr_size)?;

let dest = Lvalue::Ptr {
Expand Down Expand Up @@ -585,7 +585,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
// FIXME(solson)
let dest = self.force_allocation(dest)?.to_ptr()?;

let dest = dest.offset(offset.bytes(), self.memory.layout)?;
let dest = dest.offset(offset.bytes(), &self)?;
let dest_size = self.type_size(ty)?
.expect("bad StructWrappedNullablePointer discrfield");
self.memory.write_int(dest, 0, dest_size)?;
Expand Down Expand Up @@ -645,7 +645,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let dest = Pointer::from(self.force_allocation(dest)?.to_ptr()?);

for i in 0..length {
let elem_dest = dest.offset(i * elem_size, self.memory.layout)?;
let elem_dest = dest.offset(i * elem_size, &self)?;
self.write_value_to_ptr(value, elem_dest, elem_ty)?;
}
}
Expand Down Expand Up @@ -911,7 +911,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
// FIXME: assuming here that type size is < i64::max_value()
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
let offset = offset.overflowing_mul(pointee_size).0;
ptr.wrapping_signed_offset(offset, self.memory.layout)
ptr.wrapping_signed_offset(offset, self)
}

pub(super) fn pointer_offset(&self, ptr: Pointer, pointee_ty: Ty<'tcx>, offset: i64) -> EvalResult<'tcx, Pointer> {
Expand All @@ -926,7 +926,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
// FIXME: assuming here that type size is < i64::max_value()
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
return if let Some(offset) = offset.checked_mul(pointee_size) {
let ptr = ptr.signed_offset(offset, self.memory.layout)?;
let ptr = ptr.signed_offset(offset, self)?;
// Do not do bounds-checking for integers; they can never alias a normal pointer anyway.
if let PrimVal::Ptr(ptr) = ptr.into_inner_primval() {
self.memory.check_bounds(ptr, false)?;
Expand Down Expand Up @@ -1217,8 +1217,10 @@ 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 field_0_ptr = ptr.offset(field_0, &self)?.into();
let field_1_ptr = ptr.offset(field_1, &self)?.into();
self.memory.write_primval(field_0_ptr, a, field_0_size)?;
self.memory.write_primval(field_1_ptr, b, field_1_size)?;
Ok(())
}

Expand Down Expand Up @@ -1335,7 +1337,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Ok(p.to_value())
} else {
trace!("reading fat pointer extra of type {}", pointee_ty);
let extra = ptr.offset(self.memory.pointer_size(), self.memory.layout)?;
let extra = ptr.offset(self.memory.pointer_size(), self)?;
match self.tcx.struct_tail(pointee_ty).sty {
ty::TyDynamic(..) => Ok(p.to_value_with_vtable(self.memory.read_ptr(extra)?.to_ptr()?)),
ty::TySlice(..) |
Expand Down Expand Up @@ -1530,8 +1532,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
}
let src_field_offset = self.get_field_offset(src_ty, i)?.bytes();
let dst_field_offset = self.get_field_offset(dest_ty, i)?.bytes();
let src_f_ptr = src_ptr.offset(src_field_offset, self.memory.layout)?;
let dst_f_ptr = dest.offset(dst_field_offset, self.memory.layout)?;
let src_f_ptr = src_ptr.offset(src_field_offset, &self)?;
let dst_f_ptr = dest.offset(dst_field_offset, &self)?;
if src_fty == dst_fty {
self.copy(src_f_ptr, dst_f_ptr.into(), src_fty)?;
} else {
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_mir/interpret/lvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
_ => offset.bytes(),
};

let ptr = base_ptr.offset(offset, self.memory.layout)?;
let ptr = base_ptr.offset(offset, &self)?;

let field_ty = self.monomorphize(field_ty, self.substs());

Expand Down Expand Up @@ -412,7 +412,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let usize = self.tcx.types.usize;
let n = self.value_to_primval(n_ptr, usize)?.to_u64()?;
assert!(n < len, "Tried to access element {} of array/slice with length {}", n, len);
let ptr = base_ptr.offset(n * elem_size, self.memory.layout)?;
let ptr = base_ptr.offset(n * elem_size, &self)?;
(ptr, LvalueExtra::None, aligned)
}

Expand All @@ -431,7 +431,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
u64::from(offset)
};

let ptr = base_ptr.offset(index * elem_size, self.memory.layout)?;
let ptr = base_ptr.offset(index * elem_size, &self)?;
(ptr, LvalueExtra::None, aligned)
}

Expand All @@ -443,7 +443,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let (elem_ty, n) = base.elem_ty_and_len(base_ty);
let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized");
assert!(u64::from(from) <= n - u64::from(to));
let ptr = base_ptr.offset(u64::from(from) * elem_size, self.memory.layout)?;
let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?;
let extra = LvalueExtra::Length(n - u64::from(to) - u64::from(from));
(ptr, extra, aligned)
}
Expand Down
Loading

0 comments on commit 03ca15e

Please sign in to comment.